[svn-commits] tilghman: branch tilghman/odbc_tx_support r166900 - in /team/tilghman/odbc_tx...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Dec 29 18:33:44 CST 2008


Author: tilghman
Date: Mon Dec 29 18:33:44 2008
New Revision: 166900

URL: http://svn.digium.com/view/asterisk?view=rev&rev=166900
Log:
Testing yields improvements

Modified:
    team/tilghman/odbc_tx_support/include/asterisk/res_odbc.h
    team/tilghman/odbc_tx_support/res/res_odbc.c

Modified: team/tilghman/odbc_tx_support/include/asterisk/res_odbc.h
URL: http://svn.digium.com/view/asterisk/team/tilghman/odbc_tx_support/include/asterisk/res_odbc.h?view=diff&rev=166900&r1=166899&r2=166900
==============================================================================
--- team/tilghman/odbc_tx_support/include/asterisk/res_odbc.h (original)
+++ team/tilghman/odbc_tx_support/include/asterisk/res_odbc.h Mon Dec 29 18:33:44 2008
@@ -58,9 +58,6 @@
 	AST_LIST_ENTRY(odbc_obj) list;
 };
 
-/*!\brief These aren't used in any API calls, but they are kept in a common
- * location, simply for convenience and to avoid duplication.
- */
 struct odbc_cache_columns {
 	char *name;
 	SQLSMALLINT type;

Modified: team/tilghman/odbc_tx_support/res/res_odbc.c
URL: http://svn.digium.com/view/asterisk/team/tilghman/odbc_tx_support/res/res_odbc.c?view=diff&rev=166900&r1=166899&r2=166900
==============================================================================
--- team/tilghman/odbc_tx_support/res/res_odbc.c (original)
+++ team/tilghman/odbc_tx_support/res/res_odbc.c Mon Dec 29 18:33:44 2008
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2005, Digium, Inc.
+ * Copyright (C) 1999 - 2008, Digium, Inc.
  *
  * Mark Spencer <markster at digium.com>
  *
@@ -25,6 +25,7 @@
  * 
  * \author Mark Spencer <markster at digium.com>
  * \author Anthony Minessale II <anthmct at yahoo.com>
+ * \author Tilghman Lesher <tilghman at digium.com>
  *
  * \arg See also: \ref cdr_odbc
  */
@@ -82,6 +83,7 @@
 static odbc_status odbc_obj_disconnect(struct odbc_obj *obj);
 static int odbc_register_class(struct odbc_class *class, int connect);
 static void odbc_txn_free(void *data);
+static void odbc_release_obj2(struct odbc_obj *obj, struct odbc_txn_frame *tx);
 
 AST_THREADSTORAGE(errors_buf);
 
@@ -92,12 +94,6 @@
 
 struct odbc_txn_frame {
 	AST_LIST_ENTRY(odbc_txn_frame) list;
-	/*!\brief Status of this transaction
-	 * This is important only when considering what happens when an uncommitted
-	 * transaction is released without an explicit Commit or Rollback.  That
-	 * action is decided by the forcecommit flag, below.
-	 */
-	enum { ODBC_STATUS_TXCLOSED = 0, ODBC_STATUS_TXOPEN = 1 } status;
 	struct ast_channel *owner;
 	struct odbc_obj *obj;        /*!< Database handle within which transacted statements are run */
 	/*!\brief Is this record the current active transaction within the channel?
@@ -213,6 +209,7 @@
 		txn->obj = obj;
 		txn->isolation = obj->parent->isolation;
 		txn->forcecommit = obj->parent->forcecommit;
+		txn->owner = chan;
 		txn->active = 1;
 
 		/* On creation, the txn becomes active, and all others inactive */
@@ -220,51 +217,58 @@
 			otxn->active = 0;
 		}
 		AST_LIST_INSERT_TAIL(oldlist, txn, list);
+
+		obj->txf = txn;
+		obj->tx = 1;
 	}
 	AST_LIST_UNLOCK(oldlist);
 
 	return txn;
 }
 
-static void release_transaction(struct odbc_txn_frame *tx)
-{
-	struct ast_channel *chan;
-	struct ast_datastore *txn_store;
-	AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
-
-	if (tx && tx->owner) {
-		chan = tx->owner;
-		ast_channel_lock(chan);
-	} else {
-		/* No channel == no transaction */
-		return;
-	}
-
-	if (!(txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
-		ast_channel_unlock(chan);
-		return;
-	}
-
-	oldlist = txn_store->data;
-	AST_LIST_LOCK(oldlist);
-	AST_LIST_REMOVE(oldlist, tx, list);
-	AST_LIST_UNLOCK(oldlist);
+static struct odbc_txn_frame *release_transaction(struct odbc_txn_frame *tx)
+{
+	if (!tx) {
+		return NULL;
+	}
+
+	ast_debug(2, "release_transaction(%p) called (tx->obj = %p, tx->obj->txf = %p)\n", tx, tx->obj, tx->obj ? tx->obj->txf : NULL);
+
+	/* If we have an owner, disassociate */
+	if (tx->owner) {
+		struct ast_datastore *txn_store;
+		AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
+
+		ast_channel_lock(tx->owner);
+		if ((txn_store = ast_channel_datastore_find(tx->owner, &txn_info, NULL))) {
+			oldlist = txn_store->data;
+			AST_LIST_LOCK(oldlist);
+			AST_LIST_REMOVE(oldlist, tx, list);
+			AST_LIST_UNLOCK(oldlist);
+		}
+		ast_channel_unlock(tx->owner);
+		tx->owner = NULL;
+	}
+
 	if (tx->obj) {
-		/* Have to remove this link, first, or the destructors will recursively call each other */
+		/* If we have any uncommitted transactions, they are handled when we release the object */
+		struct odbc_obj *obj = tx->obj;
+		/* Prevent recursion during destruction */
 		tx->obj->txf = NULL;
-		/* If we have any uncommitted transactions, they are handled when we release the object */
-		ast_odbc_release_obj(tx->obj);
 		tx->obj = NULL;
-	}
-	tx->owner = NULL;
+		odbc_release_obj2(obj, tx);
+	}
 	ast_free(tx);
-	ast_channel_unlock(chan);
+	return NULL;
 }
 
 static void odbc_txn_free(void *vdata)
 {
 	struct odbc_txn_frame *tx;
 	AST_LIST_HEAD(, odbc_txn_frame) *oldlist = vdata;
+
+	ast_debug(2, "odbc_txn_free(%p) called\n", vdata);
+
 	AST_LIST_LOCK(oldlist);
 	while ((tx = AST_LIST_REMOVE_HEAD(oldlist, list))) {
 		release_transaction(tx);
@@ -679,7 +683,8 @@
 			pooling = 0;
 			limit = 0;
 			bse = 1;
-			forcecommit = isolation = 0;
+			forcecommit = 0;
+			isolation = SQL_TXN_READ_COMMITTED;
 			for (v = ast_variable_browse(config, cat); v; v = v->next) {
 				if (!strcasecmp(v->name, "pooling")) {
 					if (ast_true(v->value))
@@ -892,15 +897,16 @@
 	}
 }
 
-void ast_odbc_release_obj(struct odbc_obj *obj)
-{
-	struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0);
+static void odbc_release_obj2(struct odbc_obj *obj, struct odbc_txn_frame *tx)
+{
 	SQLINTEGER nativeerror=0, numfields=0;
 	SQLSMALLINT diagbytes=0, i;
 	unsigned char state[10], diagnostic[256];
 
+	ast_debug(2, "odbc_release_obj2(%p) called (obj->txf = %p)\n", obj, obj->txf);
 	if (tx) {
-		if (SQLEndTran(SQL_HANDLE_DBC, obj->con, obj->parent->forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) {
+		ast_debug(1, "called on a transactional handle with %s\n", tx->forcecommit ? "COMMIT" : "ROLLBACK");
+		if (SQLEndTran(SQL_HANDLE_DBC, obj->con, tx->forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) {
 			/* Handle possible transaction commit failure */
 			SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
 			for (i = 0; i < numfields; i++) {
@@ -920,7 +926,7 @@
 		}
 
 		/* Transaction is done, reset autocommit */
-		if (obj->parent->haspool && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
+		if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
 			SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
 			for (i = 0; i < numfields; i++) {
 				SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
@@ -943,11 +949,17 @@
 	 * reused.  For non-pooled connections, it does nothing. */
 	obj->used = 0;
 	if (obj->txf) {
-		/* We'll get called a second time, with txf set to NULL */
-		release_transaction(obj->txf);
-	} else {
-		ao2_ref(obj, -1);
-	}
+		/* Prevent recursion -- transaction is already closed out. */
+		obj->txf->obj = NULL;
+		obj->txf = release_transaction(obj->txf);
+	}
+	ao2_ref(obj, -1);
+}
+
+void ast_odbc_release_obj(struct odbc_obj *obj)
+{
+	struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0);
+	odbc_release_obj2(obj, tx);
 }
 
 int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
@@ -988,7 +1000,6 @@
 			}
 			pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", ast_str_buffer(errors));
 		}
-		tx->status = ODBC_STATUS_TXCLOSED;
 	}
 	return 0;
 }
@@ -1026,7 +1037,6 @@
 			}
 			pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", ast_str_buffer(errors));
 		}
-		tx->status = ODBC_STATUS_TXCLOSED;
 	}
 	return 0;
 }
@@ -1087,16 +1097,16 @@
 			ast_mutex_init(&obj->lock);
 			/* obj inherits the outstanding reference to class */
 			obj->parent = class;
+			class = NULL;
 			if (odbc_obj_connect(obj) == ODBC_FAIL) {
 				ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
 				ao2_ref(obj, -1);
 				obj = NULL;
 			} else {
 				obj->used = 1;
-				ao2_link(class->obj_container, obj);
-				ast_atomic_fetchadd_int(&class->count, +1);
-			}
-			class = NULL;
+				ao2_link(obj->parent->obj_container, obj);
+				ast_atomic_fetchadd_int(&obj->parent->count, +1);
+			}
 		} else {
 			/* Object is not constructed, so delete outstanding reference to class. */
 			ao2_ref(class, -1);
@@ -1128,14 +1138,15 @@
 			ast_mutex_init(&obj->lock);
 			/* obj inherits the outstanding reference to class */
 			obj->parent = class;
+			class = NULL;
 			if (odbc_obj_connect(obj) == ODBC_FAIL) {
 				ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
 				ao2_ref(obj, -1);
 				obj = NULL;
 			} else {
 				obj->used = 1;
-				ao2_link(class->obj_container, obj);
-				ast_atomic_fetchadd_int(&class->count, +1);
+				ao2_link(obj->parent->obj_container, obj);
+				ast_atomic_fetchadd_int(&obj->parent->count, +1);
 			}
 		}
 
@@ -1158,22 +1169,21 @@
 			class = NULL;
 		} else {
 			/* No entry: build one */
-			obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
-			if (!obj) {
+			if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) {
 				ao2_ref(class, -1);
 				return NULL;
 			}
 			ast_mutex_init(&obj->lock);
 			/* obj inherits the outstanding reference to class */
 			obj->parent = class;
+			class = NULL;
 			if (odbc_obj_connect(obj) == ODBC_FAIL) {
 				ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
 				ao2_ref(obj, -1);
 				obj = NULL;
 			} else {
-				ao2_link(class->obj_container, obj);
-			}
-			class = NULL;
+				ao2_link(obj->parent->obj_container, obj);
+			}
 		}
 
 		if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
@@ -1190,7 +1200,7 @@
 	}
 
 	/* Set the isolation property */
-	if (SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) {
+	if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) {
 		SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
 		for (i = 0; i < numfields; i++) {
 			SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
@@ -1418,6 +1428,7 @@
 			if (!(tx = find_transaction(chan, obj, value, 0))) {
 				return -1;
 			}
+			obj->tx = 1;
 		}
 		return 0;
 	} else if (strcasecmp(args.property, "forcecommit") == 0) {




More information about the svn-commits mailing list