4898794edd81be5285ea6e544acbedeaeb31bf78
max
  Tue Nov 23 08:10:57 2021 -0800
Fixing pointers to README file for license in all source code files. refs #27614

diff --git src/hg/oneShot/cartSim/cartSim.c src/hg/oneShot/cartSim/cartSim.c
index 3c3d0a0..949c469 100644
--- src/hg/oneShot/cartSim/cartSim.c
+++ src/hg/oneShot/cartSim/cartSim.c
@@ -1,512 +1,512 @@
 /* cartSim - Simulate cart usage by genome browser users.. */
 
 /* Copyright (C) 2013 The Regents of the University of California 
- * See README in this or parent directory for licensing information. */
+ * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
 
 #include "common.h"
 #include "linefile.h"
 #include "hash.h"
 #include "options.h"
 #include "jksql.h"
 #include "portable.h"
 #include "hgRelate.h"
 
 
 int userCount = 10;
 int randSeed = 0;
 int cgiDelay = 100;
 int hitDelay = 100;
 int iterations = 100;
 double newRatio = 0.1;
 boolean innodb = FALSE;
 char *engine = "MyISAM";
 
 void usage()
 /* Explain usage and exit. */
 {
 errAbort(
   "cartSim - Simulate cart usage by genome browser users.\n"
   "usage:\n"
   "   cartSim host user password database\n"
   "options:\n"
   "   -randSeed=N random number generator seed.  Defaults to pid\n"
   "   -cgiDelay=N number of milliseconds to pretend cgi is crunching. Default is %d\n"
   "   -hitDelay=N number of milliseconds to delay between hits. Default is %d\n"
   "   -iterations=N number of iterations to hit cart.  Default is %d\n"
   "   -newRatio=0.N proportion of hits that are from new users. Default is %g\n"
   "   -create=N create database if it doesn't exist with given number of dummy records\n"
   "   -clone=source clone existing database\n"
   "   -engine=MyISAM|InnoDB - default %s.\n"
   "   -cleanup=N clean up database by getting rid of all but most recent N elements\n"
   "   -verbose=N level of diagnostic output verbosity.  Default is 1.\n"
   , cgiDelay, hitDelay, iterations, newRatio, engine
   );
 }
 
 static struct optionSpec options[] = {
    {"userCount", OPTION_INT},
    {"randSeed", OPTION_INT},
    {"cgiDelay", OPTION_INT},
    {"hitDelay", OPTION_INT},
    {"iterations", OPTION_INT},
    {"newRatio", OPTION_DOUBLE},
    {"create", OPTION_INT},
    {"clone", OPTION_STRING},
    {"engine", OPTION_STRING},
    {"cleanup", OPTION_INT},
    {NULL, 0},
 };
 
 /* Some data to help make up fake cart contents.  You get prefixVar=val random combinations */
 char *prefixes[] = {"pre", "post", "ex", ""};
 char *vars[] = {"avocado", "bean", "almond", "peach", "pea", "oat", "artichoke", "lettuce",
    "apple", "beet", "pumpkin", "potato", "strawberry", "raspberry", "sage", "wheat"};
 char *vals[] = { "owl", "hawk", "dove", "robin", "bluebird", "raven", "crow", "sparrow",
     "swallow", "falcon", "pigeon", "finch", "thrush", "woodpecker", "starling", };
 
 
 #define fakePrefix "FAKE "
 #define cartNumFields 6
 
 struct dyString *fakeCart(int size)
 /* Return a this=that string with so many elements */
 {
 struct dyString *dy = dyStringNew(0);
 int i;
 dyStringAppend(dy, fakePrefix);
 for (i=0; i<size; ++i)
     {
     if (i != 0)
        dyStringAppendC(dy, '&');
     dyStringPrintf(dy, "%s%s=%s%d",
     	prefixes[rand()%ArraySize(prefixes)],
 	vars[rand()%ArraySize(vars)],
 	vals[rand()%ArraySize(vals)],
 	rand()%10);
     }
 return dy;
 }
 
 #define userTable "userDb"
 
 void checkNotRealCartTable(struct sqlConnection *conn, char *database, char *table)
 /* Abort unless either table doesn't exist, or table exists and is in fake prefix format. */
 {
 if (!sqlTableExists(conn, table))
     return;
 int contentsFieldIx = sqlFieldIndex(conn, table, "contents");
 if (contentsFieldIx < 0)
     errAbort("%s.%s doesn't have a contents field", database, table);
 char query[256];
 sqlSafef(query, sizeof(query), "select contents from %s limit 1", table);
 char *firstContents = sqlQuickString(conn, query);
 if (firstContents != NULL && !startsWith(fakePrefix, firstContents))
     errAbort("%s.%s.contents doesn't start with '%s'", database, table, firstContents);
 freez(&firstContents);
 }
 
 void checkFakeCartTable(struct sqlConnection *conn, char *database, char *table)
 /* Abort unless either table doesn't exist, or table exists and is in fake prefix format. */
 {
 if (!sqlTableExists(conn, table))
     return;
 int contentsFieldIx = sqlFieldIndex(conn, table, "contents");
 if (contentsFieldIx < 0)
     errAbort("%s.%s doesn't have a contents field", database, table);
 char query[256];
 sqlSafef(query, sizeof(query), "select contents from %s limit 1", table);
 char *firstContents = sqlQuickString(conn, query);
 if (firstContents != NULL && !startsWith(fakePrefix, firstContents))
     errAbort("no goot test database %s: %s.contents doesn't start with '%s'", 
     	database, table, firstContents);
 freez(&firstContents);
 }
 
 void checkNotRealDatabase(char *host, char *user, char *password, char *database)
 /* Make sure that database does not contain real looking user table. */
 {
 struct sqlConnection *conn = sqlMayConnectRemote(host, user, password, database);
 if (conn != NULL)
     {
     checkNotRealCartTable(conn, database, userTable);
     sqlDisconnect(&conn);
     }
 }
 
 void checkEmptyOrFakeDatabase(char *host, char *user, char *password, char *database)
 /* Make sure that either database doesn't exist, or that it does exist and
  * has fake tables. */
 {
 struct sqlConnection *conn = sqlMayConnectRemote(host, user, password, database);
 if (conn != NULL)
     {
     checkFakeCartTable(conn, database, userTable);
     sqlDisconnect(&conn);
     }
 }
 
 boolean databaseExists(char *host, char *user, char *password, char *database)
 /* Return TRUE if database exists. */
 {
 struct sqlConnection *conn = sqlMayConnectRemote(host, user, password, database);
 if (conn == NULL)
     return FALSE;
 sqlDisconnect(&conn);
 return TRUE;
 }
 
 void createEmptyDatabase(char *host, char *user, char *password, char *database)
 /* Create a new database with no tables. */
 {
 struct sqlConnection *conn = sqlConnectRemote(host, user, password, NULL);
 char query[512];
 sqlSafef(query, sizeof(query), "create database %s", database);
 sqlUpdate(conn, query);
 sqlDisconnect(&conn);
 }
 
 void dropUserTable(char *host, char *user, char *password, char *database)
 /* Drop database if it exists. */
 {
 if (databaseExists(host, user, password, database))
     {
     struct sqlConnection *conn = sqlConnectRemote(host, user, password, database);
     if (sqlTableExists(conn, userTable))
 	{
 	char query[512];
 	sqlSafef(query, sizeof(query), "drop table %s", userTable);
 	sqlUpdate(conn, query);
 	}
     sqlDisconnect(&conn);
     }
 }
 
 void createNewFakeDatabase(char *host, char *user, char *password, char *database)
 /* Create a fake database with empty fake useDb table. */
 {
 dropUserTable(host, user, password, database);
 if (!databaseExists(host, user, password, database))
     createEmptyDatabase(host, user, password, database);
 struct sqlConnection *conn = sqlConnectRemote(host, user, password, database);
 char query[1024];
 sqlSafef(query, sizeof(query), 
 "CREATE TABLE %s  (\n"
 "    id integer unsigned not null auto_increment,	# Cart ID\n"
 "    contents longblob not null,	# Contents - encoded variables\n"
 "    reserved tinyint not null,	# always 0\n"
 "    firstUse DATETIME not null,	# First time this was used\n"
 "    lastUse DATETIME not null,	# Last time this was used\n"
 "    useCount int not null,	# Number of times used\n"
 "              #Indices\n"
 "    PRIMARY KEY(id)\n"
 ") ENGINE = %s\n", userTable, engine);
 sqlUpdate(conn, query);
 sqlDisconnect(&conn);
 }
 
 
 void createFakeEntry(struct sqlConnection *conn, int size)
 /* Create a fake entry of the given size. */
 {
 struct dyString *contents = fakeCart(size);
 struct dyString *query = dyStringNew(0);
 sqlDyStringPrintf(query, "INSERT %s VALUES(0,'%s',0,now(),now(),0)", userTable, contents->string);
 sqlUpdate(conn, query->string);
 dyStringClear(query);
 dyStringFree(&contents);
 }
 
 int randomFakeSize()
 /* Return a fake size of cart entry */
 {
 if (rand()%3 == 0)
     {
     double a = 0.0001 * (rand()%10000 + 1);
     return (int)(a*a*a*a*a*a*a*10000) + 10;
     }
 else
     return rand()%20 + 1;
 }
 
 void createFakeEntries(char *host, char *user, char *password, char *database, int count)
 /* create count new fake entries in database. */
 {
 struct sqlConnection *conn = sqlConnectRemote(host, user, password, database);
 int i;
 for (i=0; i<count; ++i)
     createFakeEntry(conn, randomFakeSize());
 sqlDisconnect(&conn);
 }
 
 void fakeCloneOldTable(struct sqlConnection *oldConn, struct sqlConnection *newConn, char *table)
 /* Clone cart table in newConn from oldConn. Add fake prefix to
  * contents field to help mark it as fake. */
 {
 char query[256];
 sqlSafef(query, sizeof(query), "select * from %s", table);
 struct sqlResult *sr = sqlGetResult(oldConn, query);
 char **row;
 FILE *f = hgCreateTabFile(NULL, table);
 while ((row = sqlNextRow(sr)) != NULL)
     {
     int i;
     for (i=0; i<cartNumFields; ++i)
         {
 	if (i != 0)
 	    fprintf(f, "\t");
 	if (i == 1)
 	    fprintf(f, "%s", fakePrefix);
 	fprintf(f, "%s", row[i]);
 	}
     fprintf(f, "\n");
     }
 hgLoadTabFile(newConn, NULL, table, &f);
 hgUnlinkTabFile(NULL, table);
 }
 
 void cloneOldDatabase(char *host, char *user, char *password, char *newDatabase, char *oldDatabase)
 /* Write out old database and read in new one. */
 {
 struct sqlConnection *oldConn = sqlConnectRemote(host, user, password, oldDatabase);
 struct sqlConnection *newConn = sqlConnectRemote(host, user, password, newDatabase);
 fakeCloneOldTable(oldConn, newConn, userTable);
 }
 
 int *getSomeInts(struct sqlConnection *conn, char *table, char *field, int limit)
 /* Return an array of ints from field in table. */
 {
 int *result, i;
 char query[512];
 sqlSafef(query, sizeof(query), "select %s from %s limit %d", field, table, limit);
 struct sqlResult *sr = sqlGetResult(conn, query);
 AllocArray(result, limit);
 for (i=0; i<limit; ++i)
     {
     char **row = sqlNextRow(sr);
     if (row == NULL)
         errAbort("Less than %d rows in %s", limit, table);
     result[i] = sqlSigned(row[0]);
     }
 sqlFreeResult(&sr);
 return result;
 }
 
 void updateOne(struct sqlConnection *conn, char *table, char *contents, int id, int useCount)
 /* Update one of cart tables with new contents. */
 {
 struct dyString *dy = dyStringNew(0);
 sqlDyStringPrintf(dy, "UPDATE %s SET contents='", table);
 dyStringAppend(dy, contents);
 dyStringPrintf(dy, "',lastUse=now(),useCount=%d ", useCount+1);
 dyStringPrintf(dy, " where id=%u", id);
 sqlUpdate(conn, dy->string);
 dyStringFree(&dy);
 }
 
 int dummyQuery(struct sqlConnection *conn, char *table, int id, char **retContents)
 /* Ask database for useCount and contents. Just return useCount, fill in *retContents  */
 {
 char *contents = "";
 char query[256];
 sqlSafef(query, sizeof(query), "select useCount,contents from %s where id=%d", table, id);
 struct sqlResult *sr = sqlGetResult(conn, query);
 char **row = sqlNextRow(sr);
 int useCount = 0;
 if (row != NULL)
     {
     contents = row[1];
     useCount = sqlUnsigned(row[0]);
     }
 *retContents = cloneString(contents);
 sqlFreeResult(&sr);
 return useCount;
 }
 
 int dummyInsert(struct sqlConnection *conn, char *table)
 /* Insert new row into cart table and return ID */
 {
 char query[256];
 sqlSafef(query, sizeof(query), "INSERT %s VALUES(0,\"\",0,now(),now(),0)",
       table);
 sqlUpdate(conn, query);
 return sqlLastAutoId(conn);
 }
 
 boolean randomBitFromProb(double prob)
 /* Where prob is between 0 and 1,  return TRUE with at given probability,
  * FALSE otherwise. */
 {
 return (rand() % 1000000 <= prob*1000000);
 }
 
 void cartSimulate(char *host, char *user, char *password, char *database)
 /* Simulate action of various UCSC Genome Browser CGIs on cart. */
 {
 /* Figure out size of tables. */
 struct sqlConnection *conn = sqlConnectRemote(host, user, password, database);
 int userDbSize = sqlQuickNum(conn, NOSQLINJ "select count(*) from userDb");
 if (userDbSize == 0)
     errAbort("%s.%s table is empty", database, userTable);
 int maxSampleSize = 1024*1024;
 int sampleSize = min(userDbSize, maxSampleSize);
 verbose(2, "# userDb has %d rows, sampling %d\n"
 	, userDbSize, sampleSize);
 
 /* Get sample of user id's. */
 int *userIds = getSomeInts(conn, "userDb", "id", sampleSize);
 
 /* Get userCount random indexes. */
 int *randomIxArray, ix;
 AllocArray(randomIxArray, userCount);
 verbose(2, "random user ix:\n");
 for (ix=0; ix<userCount; ++ix)
     {
     randomIxArray[ix] = rand() % sampleSize;
     verbose(2, "%d ", randomIxArray[ix]);
     }
 verbose(2, "\n");
 
 sqlDisconnect(&conn);
 
 int iteration = 0;
 for (;;)
     {
     for (ix = 0; ix < userCount; ++ix)
 	{
 	int randomIx = rand()%sampleSize;
 	boolean doNew = randomBitFromProb(newRatio);
 	long startTime = clock1000();
 	struct sqlConnection *conn = sqlConnectRemote(host, user, password, database);
 	long connectTime = clock1000();
 	struct dyString *contents = fakeCart(randomFakeSize());
 
 	char *userContents = NULL;
 	int userId = userIds[randomIx];
 	if (doNew)
 	    userId = userIds[randomIx] = dummyInsert(conn, userTable);
 	int userUseCount = dummyQuery(conn, userTable, userId, &userContents);
 	long userReadTime = clock1000();
 
 	sleep1000(cgiDelay);
 	long cgiSleepTime = clock1000();
 
 	updateOne(conn, userTable, contents->string, userId, userUseCount);
 	long userWriteTime = clock1000();
 
 	sqlDisconnect(&conn);
 	long disconnectTime = clock1000();
 
 	printf("%ld total, %ld oldSize, %ld newSize, %ld connect, %ld userRead, %ld userWrite, %ld disconnect\n",
 		disconnectTime - startTime - (cgiSleepTime - userReadTime),
 		(long) strlen(userContents),
 		(long)contents->stringSize,
 		connectTime - startTime,
 		userReadTime - connectTime,
 		userWriteTime - cgiSleepTime,
 		disconnectTime - userWriteTime );
 
 	dyStringFree(&contents);
 	freez(&userContents);
 
 	sleep1000(hitDelay);
 	if (++iteration >= iterations)
 	    return;
 	}
     }
 
 errAbort("cartSimulate(%s %s %s %s) not implemented", host, user, password, database);
 }
 
 
 void cleanupTable(char *host, char *user, char *password, char *database, char *table, int target)
 /* Trim table to target most recent items.  */
 {
 uglyTime(NULL);
 struct sqlConnection *conn = sqlConnectRemote(host, user, password, database);
 struct dyString *query = dyStringNew(0);
 sqlDyStringPrintf(query, "select count(*) from %s", table);
 int initialCount = sqlQuickNum(conn, query->string);
 uglyTime("%d initial vs %d target", initialCount, target);
 if (target < initialCount)
     {
     /* Query database for id's ordered by age */
 
     dyStringClear(query);
     sqlDyStringPrintf(query, "select id,now()-lastUse age from %s order by age", table);
     struct sqlResult *sr = sqlGetResult(conn, query->string);
 
     /* Build up new query that'll delete old things. */
     dyStringClear(query);
     sqlDyStringPrintf(query, "delete from %s where id in (", table);
     int i=0;
     boolean addComma = FALSE;
     char **row;
     while ((row = sqlNextRow(sr)) != NULL)
         {
 	if (++i > target)
 	   {
 	   if (addComma)
 	       dyStringAppendC(query, ',');
 	   else
 	       addComma = TRUE;
 	   dyStringPrintf(query, "'%s'", row[0]);
 	   }
 	}
     dyStringPrintf(query, ")");
     sqlFreeResult(&sr);
     uglyTime("made delete query %d chars", query->stringSize);
 
     /* Excute deletion */
     sqlUpdate(conn, query->string);
     uglyTime("deleted");
     }
 sqlDisconnect(&conn);
 }
 
 void cartSim(char *host, char *user, char *password, char *database)
 /* cartSim - Simulate cart usage by genome browser users. */
 {
 char *create = optionVal("create", NULL);
 char *clone = optionVal("clone", NULL);
 char *cleanup = optionVal("cleanup", NULL);
 if (create != NULL)
     {
     checkNotRealDatabase(host, user, password, database);
     checkEmptyOrFakeDatabase(host, user, password, database);
     createNewFakeDatabase(host, user, password, database);
     createFakeEntries(host, user, password, database, sqlUnsigned(create));
     }
 else if (clone != NULL)
     {
     checkNotRealDatabase(host, user, password, database);
     checkEmptyOrFakeDatabase(host, user, password, database);
     createNewFakeDatabase(host, user, password, database);
     cloneOldDatabase(host, user, password, database, clone);
     }
 else if (cleanup != NULL)
     {
     cleanupTable(host, user, password, database, userTable, sqlUnsigned(cleanup));
     }
 else
     {
     cartSimulate(host, user, password, database);
     }
 }
 
 int main(int argc, char *argv[])
 /* Process command line. */
 {
 optionInit(&argc, argv, options);
 if (argc != 5)
     usage();
 userCount = optionInt("userCount", userCount);
 randSeed = optionInt("randSeed", getpid());
 srand(randSeed);
 cgiDelay = optionInt("cgiDelay", cgiDelay);
 hitDelay = optionInt("hitDelay", hitDelay);
 iterations = optionInt("iterations", iterations);
 newRatio = optionDouble("newRatio", newRatio);
 engine = optionVal("engine", engine);
 cartSim(argv[1], argv[2], argv[3], argv[4]);
 return 0;
 }