[asterisk-commits] tilghman: branch tilghman/realtime_failover r140668 - in /team/tilghman/realt...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Sep 2 16:50:06 CDT 2008


Author: tilghman
Date: Tue Sep  2 16:50:05 2008
New Revision: 140668

URL: http://svn.digium.com/view/asterisk?view=rev&rev=140668
Log:
Got infrastructure okay, I think

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

Modified: team/tilghman/realtime_failover/include/asterisk/res_odbc.h
URL: http://svn.digium.com/view/asterisk/team/tilghman/realtime_failover/include/asterisk/res_odbc.h?view=diff&rev=140668&r1=140667&r2=140668
==============================================================================
--- team/tilghman/realtime_failover/include/asterisk/res_odbc.h (original)
+++ team/tilghman/realtime_failover/include/asterisk/res_odbc.h Tue Sep  2 16:50:05 2008
@@ -50,9 +50,7 @@
 	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.
- */
+/*!\brief These structures are used for adaptive capabilities */
 struct odbc_cache_columns {
 	char *name;
 	SQLSMALLINT type;
@@ -96,24 +94,29 @@
 /*! 
  * \brief Retrieves a connected ODBC object
  * \param name The name of the ODBC class for which a connection is needed.
- * \param check Whether to ensure that a connection is valid before returning the handle.  Usually unnecessary.
+ * \param flags One or more of the following flags:
+ *    ODBC_SANITY_CHECK Whether to ensure that a connection is valid before returning the handle.  Usually unnecessary.
+ *    ODBC_CONNECTED Only return a connected handle.  Intended for use with peers which use idlecheck, which are checked periodically for reachability.
  * \retval ODBC object 
  * \retval  NULL if there is no connection available with the requested name.
  *
  * Connection classes may, in fact, contain multiple connection handles.  If
  * the connection is pooled, then each connection will be dedicated to the
  * thread which requests it.  Note that all connections should be released
- * when the thread is done by calling odbc_release_obj(), below.
+ * when the thread is done by calling ast_odbc_release_obj(), below.
  */
 #ifdef DEBUG_THREADS
-struct odbc_obj *_ast_odbc_request_obj(const char *name, int check, const char *file, const char *function, int lineno);
+struct odbc_obj *_ast_odbc_request_obj(const char *name, int flags, const char *file, const char *function, int lineno);
 #define ast_odbc_request_obj(a, b)	_ast_odbc_request_obj(a, b, __FILE__, __PRETTY_FUNCTION__, __LINE__)
 #else
-struct odbc_obj *ast_odbc_request_obj(const char *name, int check);
+struct odbc_obj *ast_odbc_request_obj(const char *name, int flags);
 #endif
 
+#define	ODBC_SANITY_CHECK   (1 << 0)
+#define ODBC_CONNECTED      (1 << 1)
+
 /*! 
- * \brief Releases an ODBC object previously allocated by odbc_request_obj()
+ * \brief Releases an ODBC object previously allocated by ast_odbc_request_obj()
  * \param obj The ODBC object
  */
 void ast_odbc_release_obj(struct odbc_obj *obj);
@@ -158,7 +161,9 @@
  * \param table Tablename to describe
  * \retval A structure describing the table layout, or NULL, if the table is not found or another error occurs.
  * When a structure is returned, the contained columns list will be
- * rdlock'ed, to ensure that it will be retained in memory.
+ * rdlock'ed, to ensure that it will be retained in memory.  The information
+ * will be cached until a reload event or when ast_odbc_clear_cache() is called
+ * with the relevant parameters.
  */
 struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char *tablename);
 
@@ -172,6 +177,8 @@
 
 /*!
  * \brief Remove a cache entry from memory
+ * This function may be called to clear entries created and cached by the
+ * ast_odbc_find_table() API call.
  * \param database Name of an ODBC class (used to ensure like-named tables in different databases are not confused)
  * \param table Tablename for which a cached record should be removed
  * \retval 0 if the cache entry was removed, or -1 if no matching entry was found.

Modified: team/tilghman/realtime_failover/res/res_odbc.c
URL: http://svn.digium.com/view/asterisk/team/tilghman/realtime_failover/res/res_odbc.c?view=diff&rev=140668&r1=140667&r2=140668
==============================================================================
--- team/tilghman/realtime_failover/res/res_odbc.c (original)
+++ team/tilghman/realtime_failover/res/res_odbc.c Tue Sep  2 16:50:05 2008
@@ -64,6 +64,12 @@
 	unsigned int limit;                  /* 1023 wasn't enough for some people */
 	unsigned int count;                  /* Running count of pooled connections */
 	unsigned int idlecheck;              /* Recheck the connection if it is idle for this long */
+	unsigned int conntimeout;            /* Maximum time the connection process should take */
+	/* When a connection fails, cache that failure for how long? */
+	struct timeval negative_connection_cache;
+	/* When a connection fails, when did that last occur? */
+	struct timeval last_negative_connect;
+	/* List of handles associated with this class */
 	struct ao2_container *obj_container;
 };
 
@@ -409,7 +415,8 @@
 	struct ast_variable *v;
 	char *cat;
 	const char *dsn, *username, *password, *sanitysql;
-	int enabled, pooling, limit, bse;
+	int enabled, pooling, limit, bse, conntimeout;
+	struct timeval ncache;
 	unsigned int idlecheck;
 	int preconnect = 0, res = 0;
 	struct ast_flags config_flags = { 0 };
@@ -469,6 +476,22 @@
 					sanitysql = v->value;
 				} else if (!strcasecmp(v->name, "backslash_is_escape")) {
 					bse = ast_true(v->value);
+				} else if (!strcasecmp(v->name, "connect_timeout")) {
+					if (sscanf(v->value, "%d", &conntimeout) != 1 || conntimeout < 1) {
+						ast_log(LOG_WARNING, "connect_timeout must be a positive integer\n");
+						conntimeout = 10;
+					}
+				} else if (!strcasecmp(v->name, "negative_connection_cache")) {
+					double dncache;
+					if (sscanf(v->value, "%lf", &dncache) != 1 || dncache < 0) {
+						ast_log(LOG_WARNING, "negative_connection_cache must be a non-negative integer\n");
+						/* 5 minutes sounds like a reasonable default */
+						ncache.tv_sec = 300;
+						ncache.tv_usec = 0;
+					} else {
+						ncache.tv_sec = (int)dncache;
+						ncache.tv_usec = (dncache - ncache.tv_sec) * 1000000;
+					}
 				}
 			}
 
@@ -503,6 +526,8 @@
 
 				new->backslash_is_escape = bse ? 1 : 0;
 				new->idlecheck = idlecheck;
+				new->conntimeout = conntimeout;
+				new->negative_connection_cache = ncache;
 
 				if (cat)
 					ast_copy_string(new->name, cat, sizeof(new->name));
@@ -655,9 +680,9 @@
 }
 
 #ifdef DEBUG_THREADS
-struct odbc_obj *_ast_odbc_request_obj(const char *name, int check, const char *file, const char *function, int lineno)
+struct odbc_obj *_ast_odbc_request_obj(const char *name, int flags, const char *file, const char *function, int lineno)
 #else
-struct odbc_obj *ast_odbc_request_obj(const char *name, int check)
+struct odbc_obj *ast_odbc_request_obj(const char *name, int flags)
 #endif
 {
 	struct odbc_obj *obj = NULL;
@@ -687,10 +712,12 @@
 			ao2_ref(obj, -1);
 		}
 
-		if (!obj && (class->count < class->limit)) {
+		if (!obj && (class->count < class->limit) &&
+				ast_tvdiff_ms(ast_tvnow(), ast_tvadd(class->last_negative_connect, class->negative_connection_cache)) > 0) {
 			class->count++;
 			obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
 			if (!obj) {
+				class->count--;
 				ao2_ref(class, -1);
 				return NULL;
 			}
@@ -735,10 +762,16 @@
 		}
 	}
 
-	if (obj && check) {
+	if ((flags & ODBC_CONNECTED) && !obj->up) {
+		/* Check if this connection qualifies for reconnection, with negative connection cache time */
+		if (ast_tvdiff_ms(ast_tvnow(), ast_tvadd(class->last_negative_connect, class->negative_connection_cache)) > 0) {
+			odbc_obj_connect(obj);
+		}
+	} else if (obj && (flags & ODBC_SANITY_CHECK)) {
 		ast_odbc_sanity_check(obj);
-	} else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck)
+	} else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) {
 		odbc_obj_connect(obj);
+	}
 
 #ifdef DEBUG_THREADS
 	if (obj) {
@@ -796,11 +829,12 @@
 
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
+		obj->last_negative_connect = ast_tvnow();
 		ast_mutex_unlock(&obj->lock);
 		return ODBC_FAIL;
 	}
-	SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0);
-	SQLSetConnectAttr(obj->con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *) 10, 0);
+	SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) obj->parent->conntimeout, 0);
+	SQLSetConnectAttr(obj->con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *) obj->parent->conntimeout, 0);
 #ifdef NEEDTRACE
 	SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
 	SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
@@ -820,6 +854,7 @@
 
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, state, &err, msg, 100, &mlen);
+		obj->last_negative_connect = ast_tvnow();
 		ast_mutex_unlock(&obj->lock);
 		ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
 		return ODBC_FAIL;




More information about the asterisk-commits mailing list