Files
asterisk/include/asterisk/res_odbc_transaction.h
Mark Michelson 9714da7aa4 res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.

Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.

This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.

Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.

Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.

In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.

Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
2016-01-22 11:59:06 -06:00

55 lines
2.5 KiB
C

/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2016, Digium, Inc.
*
* Mark Michelson <mmichelson@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
#ifndef RES_ODBC_TRANSACTION_H
#define RES_ODBC_TRANSACTION_H
/*!
* \brief
*
* Retrieve an ODBC transaction connection with the given ODBC class name.
*
* \note The name passed here is *not* the name of the transaction but the name of the
* ODBC class defined in res_odbc.conf.
*
* \note Do not call ast_odbc_release_obj() on the retrieved connection. Calling this function
* does not make you the owner of the connection.
*
* XXX This function is majorly flawed because it ignores properties of transactions and simply
* finds one that corresponds to the given DSN. The problem here is that transactions have names
* and they maintain which transaction is "active" for operations like transaction creation,
* commit, and rollback. However, when it comes to intermediary operations to be made on the
* transactions, all that is ignored. It means that if a channel has created multiple transactions
* for the same DSN, it's a crapshoot which of those transactions the operation will be performed
* on. This can potentially lead to baffling errors under the right circumstances.
*
* XXX The semantics of this function make for writing some awkward code. If you use func_odbc as
* an example, it has to first try to retrieve a transactional connection, then failing that, create
* a non-transactional connection. The result is that it has to remember which type of connection it's
* using and know whether to release the connection when completed or not. It would be much better
* if callers did not have to jump through such hoops.
*
* \param chan Channel on which the ODBC transaction was created
* \param objname The name of the ODBC class configured in res_odbc.conf
* \retval NULL Transaction connection could not be found.
* \retval non-NULL A transactional connection
*/
struct odbc_obj *ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname);
#endif /* RES_ODBC_TRANSACTION_H */