src/hg/utils/refreshNamedSessionCustomTracks/refreshNamedSessionCustomTracks.c 1.11
1.11 2010/01/13 17:27:35 angie
Added option -atime=N: if a session's lastUsed is older than N days, don't refresh its custom tracks.
Index: src/hg/utils/refreshNamedSessionCustomTracks/refreshNamedSessionCustomTracks.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/hg/utils/refreshNamedSessionCustomTracks/refreshNamedSessionCustomTracks.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -b -B -U 1000000 -r1.10 -r1.11
--- src/hg/utils/refreshNamedSessionCustomTracks/refreshNamedSessionCustomTracks.c 19 May 2009 23:54:31 -0000 1.10
+++ src/hg/utils/refreshNamedSessionCustomTracks/refreshNamedSessionCustomTracks.c 13 Jan 2010 17:27:35 -0000 1.11
@@ -1,217 +1,239 @@
/* refreshNamedSessionCustomTracks -- cron robot for keeping alive custom
* tracks that are referenced by saved sessions. */
#include "common.h"
#include "options.h"
#include "hash.h"
#include "cheapcgi.h"
#include "hdb.h"
#include "customTrack.h"
#include "customFactory.h"
#include "hui.h"
static char const rcsid[] = "$Id$";
#define savedSessionTable "namedSessionDb"
void usage()
/* Explain usage and exit. */
{
errAbort(
"refreshNamedSessionCustomTracks -- scan central database's %s\n"
" contents for custom tracks and touch any that are found, to prevent\n"
" them from being removed by the custom track cleanup process.\n"
"usage:\n"
" refreshNamedSessionCustomTracks hgcentral[test,beta]\n"
+ "options:\n"
+ " -atime=N If the session has not been accessed since N days ago,\n"
+ " don't refresh its custom tracks. Default: no limit.\n"
"This is intended to be run as a nightly cron job for each central db.\n"
"The ~/.hg.conf file (or $HGDB_CONF) must specify the same central db\n"
"as the command line. [The command line arg exists only to suppress this\n"
"message].\n"
"\n",
savedSessionTable
);
}
/* Options: */
static struct optionSpec options[] = {
+ {"atime", OPTION_INT},
{"hardcore", OPTION_BOOLEAN}, /* Intentionally omitted from usage(). */
{NULL, 0},
};
char *scanSettingsForCT(char *userName, char *sessionName, char *contents,
int *pLiveCount, int *pExpiredCount)
/* Parse the CGI-encoded session contents into {var,val} pairs and search
* for custom tracks. If found, refresh the custom track. Parsing code
* taken from cartParseOverHash.
* If any nonexistent custom track files are found, return a SQL update
* command that will remove those from this session. We can't just do
* the update here because that messes up the caller's query. */
{
int contentLength = strlen(contents);
struct dyString *newContents = dyStringNew(contentLength+1);
struct dyString *oneSetting = dyStringNew(contentLength / 4);
char *updateIfAny = NULL;
char *contentsToChop = cloneString(contents);
char *namePt = contentsToChop;
verbose(3, "Scanning %s %s\n", userName, sessionName);
while (isNotEmpty(namePt))
{
char *dataPt = strchr(namePt, '=');
char *nextNamePt;
if (dataPt == NULL)
errAbort("Mangled session content string %s", namePt);
*dataPt++ = 0;
nextNamePt = strchr(dataPt, '&');
if (nextNamePt != NULL)
*nextNamePt++ = 0;
dyStringClear(oneSetting);
dyStringPrintf(oneSetting, "%s=%s%s",
namePt, dataPt, (nextNamePt ? "&" : ""));
if (startsWith(CT_FILE_VAR_PREFIX, namePt))
{
boolean thisGotLiveCT = FALSE, thisGotExpiredCT = FALSE;
cgiDecode(dataPt, dataPt, strlen(dataPt));
verbose(3, "Found variable %s = %s\n", namePt, dataPt);
/* If the file does not exist, omit this setting from newContents so
* it doesn't get copied from session to session. If it does exist,
* leave it up to customFactoryTestExistence to parse the file for
* possible customTrash table references, some of which may exist
* and some not. */
if (! fileExists(dataPt))
{
verbose(3, "Removing %s from %s %s\n", oneSetting->string,
userName, sessionName);
thisGotExpiredCT = TRUE;
}
else
{
char *db = namePt + strlen(CT_FILE_VAR_PREFIX);
dyStringAppend(newContents, oneSetting->string);
customFactoryTestExistence(db, dataPt,
&thisGotLiveCT, &thisGotExpiredCT);
}
if (thisGotLiveCT && pLiveCount != NULL)
(*pLiveCount)++;
if (thisGotExpiredCT && pExpiredCount != NULL)
(*pExpiredCount)++;
if (thisGotExpiredCT)
{
if (verboseLevel() >= 3)
verbose(3, "Found expired custom track in %s %s: %s\n",
userName, sessionName, dataPt);
else
verbose(2, "Found expired custom track: %s\n", dataPt);
}
if (thisGotLiveCT)
verbose(4, "Found live custom track: %s\n", dataPt);
}
else
dyStringAppend(newContents, oneSetting->string);
namePt = nextNamePt;
}
if (newContents->stringSize != contentLength)
{
struct dyString *update = dyStringNew(contentLength*2);
if (newContents->stringSize > contentLength)
errAbort("Uh, why is newContents (%d) longer than original (%d)??",
newContents->stringSize, contentLength);
dyStringPrintf(update, "UPDATE %s set contents='", savedSessionTable);
dyStringAppendN(update, newContents->string, newContents->stringSize);
dyStringPrintf(update, "', lastUse=now(), useCount=useCount+1 "
"where userName=\"%s\" and sessionName=\"%s\";",
userName, sessionName);
verbose(3, "Removing one or more dead CT file settings from %s %s "
"(original length %d, now %d)\n",
userName, sessionName,
contentLength, newContents->stringSize);
updateIfAny = dyStringCannibalize(&update);
}
dyStringFree(&oneSetting);
dyStringFree(&newContents);
freeMem(contentsToChop);
return updateIfAny;
}
struct sessionInfo
{
struct sessionInfo *next;
char userName[256];
char sessionName[256];
char *contents;
};
void refreshNamedSessionCustomTracks(char *centralDbName)
/* refreshNamedSessionCustomTracks -- cron robot for keeping alive custom
* tracks that are referenced by saved sessions. */
{
struct sqlConnection *conn = hConnectCentral();
struct slPair *updateList = NULL, *update;
char *actualDbName = sqlGetDatabase(conn);
int liveCount=0, expiredCount=0;
setUdcCacheDir(); /* programs that use udc must call this to initialize cache dir location */
if (!sameString(centralDbName, actualDbName))
errAbort("Central database specified in hg.conf file is %s but %s "
"was specified on the command line.",
actualDbName, centralDbName);
else
verbose(2, "Got connection to %s\n", centralDbName);
+long long threshold = 0;
+int atime = optionInt("atime", 0);
+if (atime > 0)
+ {
+ time_t now = time(NULL);
+ threshold = now - ((long long)atime * 24 * 60 * 60);
+ }
+
if (sqlTableExists(conn, savedSessionTable))
{
struct sessionInfo *sessionList = NULL, *si;
struct sqlResult *sr = NULL;
char **row = NULL;
char query[512];
safef(query, sizeof(query),
- "select userName,sessionName,contents from %s "
+ "select userName,sessionName,UNIX_TIMESTAMP(lastUse),contents from %s "
"order by userName,sessionName", savedSessionTable);
sr = sqlGetResult(conn, query);
// Slurp results into memory instead of processing row by row,
// reducing the chance of lost connection.
while ((row = sqlNextRow(sr)) != NULL)
{
+ if (atime > 0)
+ {
+ long long lastUse = atoll(row[2]);
+ if (lastUse < threshold)
+ {
+ verbose(2, "User %s session %s is older than %d days, skipping.\n",
+ row[0], row[1], atime);
+ continue;
+ }
+ }
AllocVar(si);
safecpy(si->userName, sizeof(si->userName), row[0]);
safecpy(si->sessionName, sizeof(si->sessionName), row[1]);
- si->contents = cloneString(row[2]);
+ si->contents = cloneString(row[3]);
slAddHead(&sessionList, si);
}
sqlFreeResult(&sr);
for (si = sessionList; si != NULL; si = si->next)
{
char *updateIfAny = scanSettingsForCT(si->userName, si->sessionName, si->contents,
&liveCount, &expiredCount);
if (updateIfAny)
{
AllocVar(update);
update->name = updateIfAny;
slAddHead(&updateList, update);
}
}
}
/* Now that we're done reading from savedSessionTable, we can modify it: */
if (optionExists("hardcore"))
{
for (update = updateList; update != NULL; update = update->next)
sqlUpdate(conn, update->name);
}
hDisconnectCentral(&conn);
verbose(1, "Found %d live and %d expired custom tracks in %s.\n",
liveCount, expiredCount, centralDbName);
}
int main(int argc, char *argv[])
/* Process command line. */
{
optionInit(&argc, argv, options);
if (argc != 2)
usage();
setCurrentDir(CGI_BIN);
refreshNamedSessionCustomTracks(argv[1]);
return 0;
}