Database connection behaviour and database connection pool designed for handling transaction, prepare/execute, cursors and client process describe/encode/decode.
Examples of using the DBConnection
behaviour are available in
./examples/db_agent/
and ./examples/tcp_connection/
.
There is also a series of articles on building database adapters. It includes articles covering both DBConnection and Ecto integrations.
Run unit tests with:
$ mix test
To run the integration tests (for each available pool):
$ mix test.pools
To run all tests:
$ mix test.all
This library is made of four main modules:
DBConnection
- this is the code running on the client
and the specification of the DBConnection API
DBConnection.Connection
- this is the process that
establishes the database connection
DBConnection.ConnectionPool
- this is the connection
pool. A client asks the connection pool for a connection.
There is also an ownership pool, used mostly during tests,
which we won't discuss here.
DBConnection.Holder
- the holder is responsible for
keeping the connection and checkout state. It is modelled
by using an ETS table.
Once a connection is created, it creates a holder and assigns the connection pool as the heir. Then the holder is promptly given away to the pool. The connection itself is mostly a dummy. It is there to handle connections and pings. The state itself (such as the socket) is all in the holder.
Once there is a checkout, the pool gives the holder to the client process and stores all relevant information in the holder table itself. If the client terminates without checking in, then the holder is given back to the pool via the heir mechanism. The pool will then discard the connection.
One important design detail in DBConnection is that it avoids copying data. Other database libraries would send a request to the connection process, perform the query in the connection process, and then send it back to the client. This means a lot of data copying in Elixir. DBConnection keeps the socket in the holder and works on it directly.
DBConnection also takes all of the care necessary to handle failures, and it shuts down the connection and the socket whenever the client does not check in the connection to avoid recycling sockets/connections in a corrupted state (such as a socket that is stuck inside a transaction).
When a checkout happens, a deadline is started by the client
to send a message to the pool after a time interval. If the
deadline is reached and the connection is still checked out,
the holder is deleted and the connection is terminated. If the
client tries to use a terminated connection, an error will
be raised (see Holder.handle/4
).
The queuing algorithm used by the pool is CoDel which allows us to plan for overloads and reject requests without clogging the pool once checkouts do not read a certain target.
Copyright 2015 James Fish
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.