f558f8888fc486e82384f05665be19c6f8e5f452 markd Wed Dec 15 21:00:16 2010 -0800 assign ids in seq and extFile tables locally rather than globally (RM #26) diff --git src/hg/lib/hgRelate.c src/hg/lib/hgRelate.c index 225cb4c..fc546c2 100644 --- src/hg/lib/hgRelate.c +++ src/hg/lib/hgRelate.c @@ -28,155 +28,115 @@ static char historyCreate[] = /* This contains a row for each update made to database. * (The idea is that this is just updated in batch.) * It keeps track of which id global ids are used * as well as providing a record of updates. */ "create table history (" "ix int not null auto_increment primary key," /* Update number. */ "startId int unsigned not null," /* Start this session's ids. */ "endId int unsigned not null," /* First id for next session. */ "who varchar(255) not null," /* User who updated. */ "what varchar(255) not null," /* What they did. */ "modTime timestamp not null," /* Modification time. */ "errata varchar(255) )"; /* Deleted data */ -HGID hgIdQuery(struct sqlConnection *conn, char *query) -/* Return first field of first table as HGID. 0 return ok. */ -{ -struct sqlResult *sr; -char **row; -HGID ret = 0; - -sr = sqlGetResult(conn, query); -row = sqlNextRow(sr); -if (row == NULL) - errAbort("Couldn't find ID in response to %s\nDatabase needs updating", query); -ret = sqlUnsigned(row[0]); -sqlFreeResult(&sr); -return ret; -} - -HGID hgRealIdQuery(struct sqlConnection *conn, char *query) -/* Return first field of first table as HGID- abort if 0. */ -{ -HGID ret = hgIdQuery(conn, query); -if (ret == 0) - errAbort("Unexpected NULL response to %s", query); -return ret; -} - HGID hgGetMaxId(struct sqlConnection *conn, char *tableName) /* get the maximum value of the id column in a table or zero if empry */ { /* we get a row with NULL if the table is empty */ char query[128]; char **row = NULL; HGID maxId; struct sqlResult *sr; safef(query, sizeof(query), "SELECT MAX(id) from %s", tableName); sr = sqlGetResult(conn, query); if (sr != NULL) row = sqlNextRow(sr); if ((row == NULL) || (row[0] == NULL)) maxId = 0; /* empty table */ else maxId = sqlUnsigned(row[0]); sqlFreeResult(&sr); return maxId; } -static HGID startUpdateId; /* First ID in this update. */ -static HGID endUpdateId; /* One past last ID in this update. */ +static void ensureHistoryTableExists(struct sqlConnection *conn) +/* create history table if it doesn't exist */ +{ +static boolean first = TRUE; +if (first) + { + sqlMaybeMakeTable(conn, "history", historyCreate); + first = FALSE; + } +} -HGID hgNextId(void) -/* Get next free global ID. */ +static void hgHistoryEnterVa(struct sqlConnection *conn, int startId, int endId, char *comment, va_list args) +/* add an entry to the history table */ { -return endUpdateId++; +// create SQL encoded string for comment +struct dyString *commentBuf = dyStringNew(256); +dyStringVaPrintf(commentBuf, comment, args); +char *commentStr = sqlEscapeString(commentBuf->string); +dyStringFree(&commentBuf); +struct dyString *query = dyStringNew(256); +ensureHistoryTableExists(conn); +dyStringPrintf(query, "INSERT into history (ix, startId, endId, who, what, modTime, errata) VALUES(NULL,%d,%d,'%s',\"%s\",NOW(), NULL)", + startId, endId, getUser(), commentStr); +sqlUpdate(conn,query->string); +dyStringFree(&query); +freeMem(commentStr); } void hgHistoryComment(struct sqlConnection *conn, char *comment, ...) -/* Add comment to history table. Does not lock the process. */ +/* Add comment to history table. */ { -struct dyString *query = newDyString(256); va_list args; -static boolean initialized = FALSE; - va_start(args, comment); -/* create history table if it does not exist already */ -if (!initialized) - { - if (sqlMaybeMakeTable(conn, "history", historyCreate)) - { - char query[256]; - safef(query, sizeof(query), - "INSERT into history (ix, startId, endId, who, what, modTime, errata) VALUES(NULL,0,10,'%s','New',NOW(), NULL)", - getUser()); - sqlUpdate(conn, query); - } - initialized = TRUE; +hgHistoryEnterVa(conn, 0, 0, comment, args); +va_end(args); } -/* add comment with startId and endId as 0 */ -dyStringPrintf(query, "INSERT into history (ix, startId, endId, who, what, modTime, errata) VALUES(NULL,%d,%d,'%s',\"", - 0, 0, getUser()); -dyStringVaPrintf(query, comment, args); -dyStringAppend(query, "\",NOW(), NULL)"); -sqlUpdate(conn,query->string); -dyStringFree(&query); + +void hgHistoryCommentWithIds(struct sqlConnection *conn, int startId, int endId, char *comment, ...) +/* Add comment to history table, with id range. */ +{ +va_list args; +va_start(args, comment); +hgHistoryEnterVa(conn, startId, endId, comment, args); +va_end(args); } struct sqlConnection *hgStartUpdate(char *db) -/* Open and connection and get next global id from the history table */ +/* Open and connection and lock the history table */ { -static boolean initialized = FALSE; struct sqlConnection *conn = sqlConnect(db); - -if (!initialized) - { - if (sqlMaybeMakeTable(conn, "history", historyCreate)) - { - char query[256]; - safef(query, sizeof(query), - "INSERT into history (ix, startId, endId, who, what, modTime, errata) VALUES(NULL,0,10,'%s','New',NOW(), NULL)", - getUser()); - sqlUpdate(conn, query); - } - initialized = TRUE; - } -/* put advisory lock on process while adding Ids to tables */ +ensureHistoryTableExists(conn); sqlGetLock(conn, "history"); -startUpdateId = endUpdateId = hgIdQuery(conn, "SELECT MAX(endId) from history"); - return conn; - } -void hgEndUpdate(struct sqlConnection **pConn, char *comment, ...) -/* Finish up connection with a printf format comment. */ +void hgEndUpdate(struct sqlConnection **pConn, int startId, int endId, char *comment, ...) +/* Finish up connection with a printf format comment and optional id range */ { struct sqlConnection *conn = *pConn; -struct dyString *query = newDyString(256); va_list args; va_start(args, comment); - -dyStringPrintf(query, "INSERT into history (ix, startId, endId, who, what, modTime, errata) VALUES(NULL,%d,%d,'%s',\"", - startUpdateId, endUpdateId, getUser()); -dyStringVaPrintf(query, comment, args); -dyStringAppend(query, "\",NOW(), NULL)"); -sqlUpdate(conn,query->string); +hgHistoryEnterVa(conn, startId, endId, comment, args); +va_end(args); sqlReleaseLock(conn, "history"); sqlDisconnect(pConn); } static void getTabFile(char *tmpDir, char *tableName, char path[PATH_LEN]) /* generate path to tab file. If tmpDir is NULL, use TMPDIR environment, or * "/var/tmp". tmpDir NULL also include pid in file name */ { boolean inclPid = (tmpDir == NULL); if (tmpDir == NULL) tmpDir = getenv("TMPDIR"); if (tmpDir == NULL) tmpDir = "/var/tmp"; if (inclPid) safef(path, PATH_LEN, "%s/%s.%d.tab", tmpDir, tableName, (int) getpid()); /* int cast for Solaris */ @@ -240,54 +200,55 @@ { char path[PATH_LEN]; getTabFile(tmpDir, tableName, path); if (remove(path) == -1) errnoAbort("Couldn't remove %s", path); } int hgAddToExtFileTbl(char *path, struct sqlConnection *conn, char *extFileTbl) /* Add entry to the specified extFile table. Delete it if it already exists. * Returns extFile id. */ { char root[128], ext[64], name[256]; struct dyString *dy = newDyString(1024); long long size = fileSize(path); -HGID id = hgNextId(); /* create table if it doesn't exist */ if (!sqlTableExists(conn, extFileTbl)) { char query[1024]; safef(query, sizeof(query), extFileCreate, extFileTbl); sqlMaybeMakeTable(conn, extFileTbl, query); } +HGID id = hgGetMaxId(conn, extFileTbl) + 1; + /* Construct file name without the directory. */ splitPath(path, NULL, root, ext); safef(name, sizeof(name), "%s%s", root, ext); /* Delete it from database. */ dyStringPrintf(dy, "delete from %s where path = '%s'", extFileTbl, path); sqlUpdate(conn, dy->string); /* Add it to table. */ dyStringClear(dy); dyStringPrintf(dy, "INSERT into %s (id, name, path, size) VALUES(%u,'%s','%s',%lld)", extFileTbl, id, name, path, size); sqlUpdate(conn, dy->string); - +hgHistoryCommentWithIds(conn, id, id, "extFile table %s: added %s (%lld)", extFileTbl, path, size); dyStringFree(&dy); return id; } int hgAddToExtFile(char *path, struct sqlConnection *conn) /* Add entry to ext file table. Delete it if it already exists. * Returns extFile id. */ { return hgAddToExtFileTbl(path, conn, "extFile"); } void hgPurgeExtFileTbl(int id, struct sqlConnection *conn, char *extFileTbl) /* remove an entry from the extFile table. Called * when there is an error loading the referenced file */