11c1c560b88d430fd2c6967a86d2e87109806357 max Fri Jan 24 09:15:03 2014 -0800 corrections after code review refs #12524. These changes probably don'tneed to reviewed anymore, as Angie has already seen them, I copied them into the ticket #12524. diff --git src/hg/lib/jksql.c src/hg/lib/jksql.c index ee17d37..e64a48d 100644 --- src/hg/lib/jksql.c +++ src/hg/lib/jksql.c @@ -59,31 +59,31 @@ char *password; // database server password struct slName *dbs; // database associated with profile, can be NULL. }; struct sqlConnection /* This is an item on a list of sql open connections. */ { MYSQL *conn; /* Connection. */ struct sqlProfile *profile; /* profile, or NULL if not opened via a profile */ struct dlNode *node; /* Pointer to list node. */ struct dlList *resultList; /* Any open results. */ boolean hasHardLock; /* TRUE if table has a non-advisory lock. */ boolean inCache; /* debugging flag to indicate it's in a cache */ boolean isFree; /* is this connection free for reuse; alway FALSE * unless managed by a cache */ - boolean hasTableCache; /* to avoid repeated checks for cache table name existence, -1 if not initialized yet */ + int hasTableCache; /* to avoid repeated checks for cache table name existence, -1 if not initialized yet */ struct sqlConnection *slowConn; /* optional. tried if a query fails on the conn connection */ char *db; /* to be able to lazily connect later, we need to store the database */ }; struct sqlResult /* This is an item on a list of sql open results. */ { MYSQL_RES *result; /* Result. */ struct dlNode *node; /* Pointer to list node we're on. */ struct sqlConnection *conn; /* Pointer to connection. */ long fetchTime; /* cummulative time taken by row fetches for this result */ }; static struct dlList *sqlOpenConnections = NULL; static unsigned sqlNumOpenConnections = 0; @@ -393,69 +393,59 @@ /* called at the end of a routine that is monitored, updates time count. * returns time since enter. */ { long deltaTime = 0; if (monitorFlags) { deltaTime = clock1000() - monitorEnterTime; assert(monitorEnterTime > 0); if (monitorFlags & JKSQL_PROF) sqlTotalTime += deltaTime; monitorEnterTime = 0; } return deltaTime; } -static char *scConnHost(struct sqlConnection *sc) -/* Return the host of a sqlConnection */ -{ -if (sc->conn) - return sc->conn->host; -if (sc->profile->host) - return sc->profile->host; -return NULL; -} - static char *scConnDb(struct sqlConnection *sc) /* Return sc->db, unless it is NULL -- if NULL, return a string for * fprint'd messages. */ { return (sc->db ? sc->db : "db=?"); } static void monitorPrintInfo(struct sqlConnection *sc, char *name) /* print a monitor message, with connection id and databases. */ { long int threadId = 0; if (sc->conn) threadId = sc->conn->thread_id; fprintf(stderr, "%.*s%s %ld %s\n", traceIndent, indentStr, name, threadId, scConnDb(sc)); fflush(stderr); } static void monitorPrint(struct sqlConnection *sc, char *name, char *format, ...) /* print a monitor message, with connection id, databases, and * printf style message.*/ { va_list args; long int threadId = 0; if (sc->conn) threadId = sc->conn->thread_id; fprintf(stderr, "%.*s%s %ld %s %s ", traceIndent, indentStr, name, - threadId, scConnHost(sc), scConnDb(sc)); + threadId, sqlGetHost(sc), scConnDb(sc)); va_start(args, format); vfprintf(stderr, format, args); va_end(args); fputc('\n', stderr); fflush(stderr); } static void monitorPrintTime(void) /* print total time */ { /* only print if not explictly disabled */ if (monitorFlags & JKSQL_PROF) { fprintf(stderr, "%.*sSQL_TOTAL_TIME %0.3fs\n", traceIndent, indentStr, ((double)sqlTotalTime)/1000.0); @@ -588,42 +578,44 @@ // also close local cache connection if (sc->slowConn != NULL) sqlDisconnect(&sc->slowConn); freez(pSc); sqlNumOpenConnections--; } } char* sqlGetDatabase(struct sqlConnection *sc) /* Get the database associated with an connection. Warning: return may be NULL! */ { -assert(!sc->isFree); if (sc->conn) return sc->conn->db; else return sc->db; } char* sqlGetHost(struct sqlConnection *sc) -/* Get the host associated with an connection. */ +/* Get the host associated with a connection or NULL. */ { -assert(!sc->isFree); +if (sc->conn) return sc->conn->host; +if (sc->profile->host) + return sc->profile->host; +return NULL; } struct slName *sqlGetAllDatabase(struct sqlConnection *sc) /* Get a list of all database on the server */ { char query[32]; sqlSafef(query, sizeof query, "show databases"); struct sqlResult *sr = sqlGetResult(sc, query); char **row; struct slName *databases = NULL; while ((row = sqlNextRow(sr)) != NULL) { if (!startsWith("mysql", row[0])) /* Avoid internal databases. */ slSafeAddHead(&databases, slNameNew(row[0])); } @@ -953,46 +945,53 @@ struct sqlConnection *sc; // get the slow-db profile for the profile, if it exists struct sqlProfile *slow = sqlProfileGetFailover(sp, database); // if we have a failover profile, don't abort right away if (slow!=NULL) mainAbort = FALSE; // connect with the default profile sc = sqlConnRemote(sp->host, sp->port, sp->socket, sp->user, sp->password, database, mainAbort); if (slow==NULL) // the default case: just return sc, can be NULL return sc; // we still have a failover profile to setup + if (sc==NULL) { // We have a failover connection configured, but no main connection. // This can happen if the requested database exists only on the failover connection // We only create a failover connection in this case and return it as the main one sc = sqlConnRemote(slow->host, slow->port, slow->socket, slow->user, slow->password, database, abort); + + if (sc!=NULL)// sc can be NULL if abort was FALSE + sc->profile = sp; // remember the profile + if (monitorFlags & JKSQL_TRACE) fprintf(stderr, "SQL_FAILOVER_AT_CONNECT"); return sc; } +// at this point we know that sc cannot be NULL sc->profile = sp; // remember the profile // don't connect the slow connection yet: lazily connect later when needed; saves 0.5 // seconds per connection on transatlantic links -// instead create a "placeholder" sqlConnection with all connection data, but no connection +// instead create a "placeholder" sqlConnection with all connection data, but no mysql connection +// object struct sqlConnection *slowSc; AllocVar(slowSc); slowSc->profile = slow; // remember the profile slowSc->db = database; slowSc->hasTableCache = -1; sc->slowConn = slowSc; return sc; } struct sqlConnection *sqlMayConnect(char *database) /* Connect to database on default host as default user. * Return NULL (don't abort) on failure. */ { return sqlConnProfile(sqlProfileMustGet(NULL, database), database, FALSE); } @@ -1103,31 +1102,31 @@ // additional check finds errors of multiple NOSQLINJ tags if (strstr(query, "NOSQLINJ ")) { sqlCheckError("Oops, multiple occurrences of NOSQLINJ tag in query: %s", query); query = replaceChars(query, "NOSQLINJ ", ""); fixedMultipleNOSQLINJ = TRUE; } assert(!sc->isFree); monitorEnter(); int mysqlError = mysql_real_query(sc->conn, query, strlen(query)); // if the query fails on the main connection, connect the slower/failover connection and try there -if (mysqlError != 0 && sc->slowConn) +if (mysqlError != 0 && sc->slowConn && sameWord(sqlGetDatabase(sc), sqlGetDatabase(sc->slowConn))) { if (monitorFlags & JKSQL_TRACE) monitorPrint(sc, "SQL_FAILOVER", "%s -> %s", sc->profile->name, sc->slowConn->profile->name); sc = sc->slowConn; sc = sqlConnectIfUnconnected(sc); mysqlError = mysql_real_query(sc->conn, query, strlen(query)); } if (mysqlError != 0) { if (abort) { monitorLeave(); if (sameOk(cfgOption("noSqlInj.dumpStack"), "on")) @@ -2159,57 +2158,58 @@ char *database) /* does a database match the one in the connection cache? */ { return ((database == NULL) && (scce->conn->db == NULL)) || sameString(database, scce->conn->db); } static boolean sqlConnChangeDb(struct sqlConnection *sc, char *database, boolean abort) /* change the database of an sql connection (and its failover connection) * */ { // if we have a failover connection, keep its db in sync int slowConnErr = 0; if (sc->slowConn) { - sc->slowConn->db = database; if (monitorFlags & JKSQL_TRACE) monitorPrint(sc->slowConn, "SQL_SET_DB", "%s %s", sc->slowConn->profile->name, database); if (sc->slowConn->conn) slowConnErr = mysql_select_db(sc->slowConn->conn, database); - // we ignore the errors here: this allows to have some DBs only locally + if (slowConnErr==0) + sc->slowConn->db = database; + // if an error occured, the slowConn will be out of sync with the main connection } sc->db=database; if (monitorFlags & JKSQL_TRACE) monitorPrint(sc, "SQL_SET_DB", "%s %s", sc->profile->name, database); // we only fail if there is no failover connection, this allows to have a DB // that does not exist locally but only remote int localConnErr = 0; localConnErr = mysql_select_db(sc->conn, database); if (sc->slowConn==NULL && sc->conn!=NULL && localConnErr != 0) { if (abort) - errAbort("Couldn't set connection database to %s\n%s", - database, mysql_error(sc->conn)); + sqlAbort(sc, "Couldn't set connection database to %s", database); else return FALSE; } if (localConnErr!=0 && slowConnErr!=0 && abort) - errAbort("Couldn't set connection database to %s in both default and failover connection\n%s", + // can't use sqlAbort, not sure which one is connected at this point + errAbort("Couldn't set connection database to %s in either default or failover connection\n%s", database, mysql_error(sc->conn)); return TRUE; } static boolean sqlConnCacheEntrySetDb(struct sqlConnCacheEntry *scce, char *database, boolean abort) /* set the connect cache and connect to the specified database */ { return sqlConnChangeDb(scce->conn, database, abort); } static struct sqlConnCacheEntry *sqlConnCacheFindFree(struct sqlConnCache *cache, struct sqlProfile *profile,