/ Check-in [07b0401a]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Many improvements to the mptest program. Added a simple test script.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | mptest
Files: files | file ages | folders
SHA1:07b0401a9b61b1664fc6dcddac3b5969fc0f481a
User & Date: drh 2013-04-06 13:09:11
Context
2013-04-06
14:04
Get the mptest program running on windows. check-in: 3966b332 user: drh tags: mptest
13:09
Many improvements to the mptest program. Added a simple test script. check-in: 07b0401a user: drh tags: mptest
00:19
Add a prototype TH3-script-style test harness that starts multiple processes operating on the same database file at the same time. check-in: c318fafe user: drh tags: mptest
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Added mptest/config01.test.

            1  +/*
            2  +** Configure five tasks in different ways, then run tests.
            3  +*/
            4  +PRAGMA page_size=8192;
            5  +--task 1
            6  +  PRAGMA journal_mode=PERSIST;
            7  +  PRAGMA mmap_limit=0;
            8  +--end
            9  +--task 2
           10  +  PRAGMA journal_mode=TRUNCATE;
           11  +  PRAGMA mmap_limit=28672;
           12  +--end
           13  +--task 3
           14  +  PRAGMA journal_mode=MEMORY;
           15  +--end
           16  +--task 4
           17  +  PRAGMA journal_mode=OFF;
           18  +--end
           19  +--source multiwrite01.test

Changes to mptest/mptest.c.

    53     53     char *zLog;            /* Name of output log file */
    54     54     FILE *pLog;            /* Where to write log messages */
    55     55     char zName[12];        /* Symbolic name of this process */
    56     56     int taskId;            /* Task ID.  0 means supervisor. */
    57     57     int iTrace;            /* Tracing level */
    58     58     int bSqlTrace;         /* True to trace SQL commands */
    59     59     int nError;            /* Number of errors */
           60  +  int nTest;             /* Number of --match operators */
           61  +  int iTimeout;          /* Milliseconds until a busy timeout */
    60     62   } g;
    61     63   
           64  +/* Default timeout */
           65  +#define DEFAULT_TIMEOUT 10000
           66  +
    62     67   /*
    63     68   ** Print a message adding zPrefix[] to the beginning of every line.
    64     69   */
    65     70   static void printWithPrefix(FILE *pOut, const char *zPrefix, const char *zMsg){
    66     71     while( zMsg && zMsg[0] ){
    67     72       int i;
    68     73       for(i=0; zMsg[i] && zMsg[i]!='\n' && zMsg[i]!='\r'; i++){}
................................................................................
   222    227       printWithPrefix(g.pErrLog, zPrefix, zMsg);
   223    228       fflush(g.pErrLog);
   224    229       maybeClose(g.pErrLog);
   225    230     }
   226    231     sqlite3_free(zMsg);
   227    232     if( g.db ){
   228    233       int nTry = 0;
   229         -    while( trySql("CREATE TABLE halt(x);")==SQLITE_BUSY && (nTry++)<100 ){
          234  +    g.iTimeout = 0;
          235  +    while( trySql("UPDATE client SET wantHalt=1;")==SQLITE_BUSY
          236  +           && (nTry++)<100 ){
   230    237         sqlite3_sleep(10);
   231    238       }
   232    239     }
   233    240     sqlite3_close(g.db);
   234    241     exit(1);  
   235    242   }
   236    243   
................................................................................
   257    264   ** Return the length of a string omitting trailing whitespace
   258    265   */
   259    266   static int clipLength(const char *z){
   260    267     int n = (int)strlen(z);
   261    268     while( n>0 && isspace(z[n-1]) ){ n--; }
   262    269     return n;
   263    270   }
          271  +
          272  +/*
          273  +** Busy handler with a g.iTimeout-millisecond timeout
          274  +*/
          275  +static int busyHandler(void *pCD, int count){
          276  +  if( count*10>g.iTimeout ){
          277  +    if( g.iTimeout>0 ) errorMessage("timeout after %dms", g.iTimeout);
          278  +    return 0;
          279  +  }
          280  +  sqlite3_sleep(10);
          281  +  return 1;
          282  +}
   264    283   
   265    284   /*
   266    285   ** SQL Trace callback
   267    286   */
   268    287   static void sqlTraceCallback(void *NotUsed1, const char *zSql){
   269    288     logMessage("[%.*s]", clipLength(zSql), zSql);
   270    289   }
................................................................................
   404    423     va_list ap;
   405    424     char *zSql;
   406    425     int rc;
   407    426     char *zErrMsg = 0;
   408    427     va_start(ap, zFormat);
   409    428     zSql = sqlite3_vmprintf(zFormat, ap);
   410    429     va_end(ap);
          430  +  assert( g.iTimeout>0 );
   411    431     rc = sqlite3_exec(g.db, zSql, evalCallback, p, &zErrMsg);
   412    432     sqlite3_free(zSql);
   413    433     if( rc ){
   414    434       char zErr[30];
   415    435       sqlite3_snprintf(sizeof(zErr), zErr, "error(%d)", rc);
   416    436       stringAppendTerm(p, zErr);
   417    437       if( zErrMsg ){
................................................................................
   431    451     int iClient,              /* The client number */
   432    452     char **pzScript,          /* Write task script here */
   433    453     int *pTaskId              /* Write task number here */
   434    454   ){
   435    455     sqlite3_stmt *pStmt = 0;
   436    456     int taskId;
   437    457     int rc;
          458  +  int totalTime = 0;
   438    459   
   439    460     *pzScript = 0;
          461  +  g.iTimeout = 0;
   440    462     while(1){
   441         -    if( trySql("SELECT * FROM halt")==SQLITE_OK ) return SQLITE_DONE;
   442    463       rc = trySql("BEGIN IMMEDIATE");
   443    464       if( rc==SQLITE_BUSY ){
   444    465         sqlite3_sleep(10);
          466  +      totalTime += 10;
   445    467         continue;
   446    468       }
   447    469       if( rc!=SQLITE_OK ){
   448    470         fatalError("%s\nBEGIN IMMEDIATE", sqlite3_errmsg(g.db));
   449    471       }
   450         -    if( g.nError ){
   451         -      runSql("UPDATE clienterror SET cnt=cnt+%d", g.nError);
          472  +    if( g.nError || g.nTest ){
          473  +      runSql("UPDATE counters SET nError=nError+%d, nTest=nTest+%d",
          474  +             g.nError, g.nTest);
   452    475         g.nError = 0;
          476  +      g.nTest = 0;
          477  +    }
          478  +    pStmt = prepareSql("SELECT 1 FROM client WHERE id=%d AND wantHalt",iClient);
          479  +    rc = sqlite3_step(pStmt);
          480  +    sqlite3_finalize(pStmt);
          481  +    if( rc==SQLITE_ROW ){
          482  +      runSql("DELETE FROM client WHERE id=%d", iClient);
          483  +      runSql("COMMIT");
          484  +      g.iTimeout = DEFAULT_TIMEOUT;
          485  +      return SQLITE_DONE;
   453    486       }
   454    487       pStmt = prepareSql(
   455    488                 "SELECT script, id FROM task"
   456    489                 " WHERE client=%d AND starttime IS NULL"
   457    490                 " ORDER BY id LIMIT 1", iClient);
   458    491       rc = sqlite3_step(pStmt);
   459    492       if( rc==SQLITE_ROW ){
................................................................................
   462    495         strcpy(*pzScript, (const char*)sqlite3_column_text(pStmt, 0));
   463    496         *pTaskId = taskId = sqlite3_column_int(pStmt, 1);
   464    497         sqlite3_finalize(pStmt);
   465    498         runSql("UPDATE task"
   466    499                "   SET starttime=strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')"
   467    500                " WHERE id=%d;", taskId);
   468    501         runSql("COMMIT;");
          502  +      g.iTimeout = DEFAULT_TIMEOUT;
   469    503         return SQLITE_OK;
   470    504       }
   471    505       sqlite3_finalize(pStmt);
   472    506       if( rc==SQLITE_DONE ){
          507  +      if( totalTime>30000 ){
          508  +        errorMessage("Waited over 30 seconds with no work.  Giving up.");
          509  +        runSql("DELETE FROM client WHERE id=%d; COMMIT;", iClient);
          510  +        sqlite3_close(g.db);
          511  +        exit(1);
          512  +      }
   473    513         runSql("COMMIT;");
   474    514         sqlite3_sleep(100);
          515  +      totalTime += 100;
   475    516         continue;
   476    517       }
   477    518       fatalError("%s", sqlite3_errmsg(g.db));
   478    519     }
          520  +  g.iTimeout = DEFAULT_TIMEOUT;
          521  +}
          522  +
          523  +/*
          524  +** Mark a script as having finished.   Remove the CLIENT table entry
          525  +** if bShutdown is true.
          526  +*/
          527  +static int finishScript(int iClient, int taskId, int bShutdown){
          528  +  runSql("UPDATE task"
          529  +         "   SET endtime=strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')"
          530  +         " WHERE id=%d;", taskId);
          531  +  if( bShutdown ){
          532  +    runSql("DELETE FROM client WHERE id=%d", iClient);
          533  +  }
          534  +  return SQLITE_OK;
   479    535   }
   480    536   
   481    537   /*
   482         -** Mark a script as having finished.
          538  +** Start up a client process for iClient, if it is not already
          539  +** running.  If the client is already running, then this routine
          540  +** is a no-op.
   483    541   */
   484         -static int finishScript(int taskId){
   485         -  sqlite3_stmt *pStmt;
   486         -  int rc;
   487         -  pStmt = prepareSql(
   488         -             "UPDATE task"
   489         -             "   SET endtime=strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')"
   490         -             " WHERE id=%d;", taskId);
   491         -  do{
   492         -    rc = sqlite3_step(pStmt);
   493         -    sqlite3_reset(pStmt);
   494         -  }while( rc==SQLITE_BUSY );
   495         -  sqlite3_finalize(pStmt);
   496         -  if( rc!=SQLITE_DONE ){
   497         -    fatalError("%s\n", sqlite3_errmsg(g.db));
          542  +static void startClient(int iClient){
          543  +  runSql("INSERT OR IGNORE INTO client VALUES(%d,0)", iClient);
          544  +  if( sqlite3_changes(g.db) ){
          545  +    char *zSys;
          546  +    zSys = sqlite3_mprintf(
          547  +                 "%s \"%s\" --client %d --trace %d %s&",
          548  +                 g.argv0, g.zDbFile, iClient, g.iTrace,
          549  +                 g.bSqlTrace ? "--sqltrace " : "");
          550  +
          551  +    system(zSys);
          552  +    sqlite3_free(zSys);
   498    553     }
   499         -  return rc; 
   500    554   }
   501    555   
   502    556   /*
   503    557   ** Read the entire content of a file into memory
   504    558   */
   505    559   static char *readFile(const char *zFilename){
   506    560     FILE *in = fopen(zFilename, "rb");
................................................................................
   593    647   ** Wait for a client process to complete all its tasks
   594    648   */
   595    649   static void waitForClient(int iClient, int iTimeout, char *zErrPrefix){
   596    650     sqlite3_stmt *pStmt;
   597    651     int rc;
   598    652     if( iClient>0 ){
   599    653       pStmt = prepareSql(
   600         -               "SELECT 1 FROM task WHERE client=%d AND endtime IS NULL",
          654  +               "SELECT 1 FROM task"
          655  +               " WHERE client=%d"
          656  +               "   AND client IN (SELECT id FROM client)"
          657  +               "  AND endtime IS NULL",
   601    658                  iClient);
   602    659     }else{
   603    660       pStmt = prepareSql(
   604         -               "SELECT 1 FROM task WHERE client=%d AND endtime IS NULL",
   605         -               iClient);
          661  +               "SELECT 1 FROM task"
          662  +               " WHERE client IN (SELECT id FROM client)"
          663  +               "   AND endtime IS NULL");
   606    664     }
          665  +  g.iTimeout = 0;
   607    666     while( ((rc = sqlite3_step(pStmt))==SQLITE_BUSY || rc==SQLITE_ROW)
   608    667       && iTimeout>0
   609    668     ){
   610    669       sqlite3_reset(pStmt);
   611    670       sqlite3_sleep(50);
   612    671       iTimeout -= 50;
   613    672     }
   614    673     sqlite3_finalize(pStmt);
          674  +  g.iTimeout = DEFAULT_TIMEOUT;
   615    675     if( rc!=SQLITE_DONE ){
   616    676       if( zErrPrefix==0 ) zErrPrefix = "";
   617    677       if( iClient>0 ){
   618    678         errorMessage("%stimeout waiting for client %d", zErrPrefix, iClient);
   619    679       }else{
   620    680         errorMessage("%stimeout waiting for all clients", zErrPrefix);
   621    681       }
................................................................................
   635    695     char *zFilename    /* File from which script was read. */
   636    696   ){
   637    697     int lineno = 1;
   638    698     int prevLine = 1;
   639    699     int ii = 0;
   640    700     int iBegin = 0;
   641    701     int n, c, j;
   642         -  int rc;
   643    702     int len;
   644    703     int nArg;
   645    704     String sResult;
   646    705     char zCmd[30];
   647    706     char zError[1000];
   648    707     char azArg[MX_ARG][100];
   649         -  unsigned char isRunning[100];
   650    708   
   651         -  memset(isRunning, 0, sizeof(isRunning));
   652    709     memset(&sResult, 0, sizeof(sResult));
   653    710     stringReset(&sResult);
   654    711     while( (c = zScript[ii])!=0 ){
   655    712       prevLine = lineno;
   656    713       len = tokenLength(zScript+ii, &lineno);
   657    714       if( isspace(c) || (c=='/' && zScript[ii+1]=='*') ){
   658    715         ii += len;
................................................................................
   695    752       **   --exit N
   696    753       **
   697    754       ** Exit this process.  If N>0 then exit without shutting down
   698    755       ** SQLite.  (In other words, simulate a crash.)
   699    756       */
   700    757       if( strcmp(zCmd, "exit")==0 ){
   701    758         int rc = atoi(azArg[0]);
   702         -      finishScript(taskId);
          759  +      finishScript(iClient, taskId, 1);
   703    760         if( rc==0 ) sqlite3_close(g.db);
   704    761         exit(rc);
   705    762       }else
   706    763   
   707    764       /*
   708    765       **  --result
   709    766       **
................................................................................
   723    780         char *zAns = zScript+ii;
   724    781         for(jj=7; jj<len-1 && isspace(zAns[jj]); jj++){}
   725    782         zAns += jj;
   726    783         if( strncmp(sResult.z, zAns, len-jj-1) ){
   727    784           errorMessage("line %d of %s:\nExpected [%.*s]\n     Got [%s]",
   728    785             prevLine, zFilename, len-jj-1, zAns, sResult.z);
   729    786         }
          787  +      g.nTest++;
   730    788         stringReset(&sResult);
   731    789       }else
   732    790   
   733    791       /*
   734    792       **  --source FILENAME
   735    793       **
   736    794       ** Run a subscript from a separate file.
   737    795       */
   738    796       if( strcmp(zCmd, "source")==0 ){
   739         -      char *zNewFile = azArg[1];
          797  +      char *zNewFile = azArg[0];
   740    798         char *zNewScript = readFile(zNewFile);
   741    799         if( g.iTrace ) logMessage("begin script [%s]\n", zNewFile);
   742    800         runScript(0, 0, zNewScript, zNewFile);
   743    801         sqlite3_free(zNewScript);
   744    802         if( g.iTrace ) logMessage("end script [%s]\n", zNewFile);
   745    803       }else
   746    804   
................................................................................
   758    816       /*
   759    817       **  --start CLIENT
   760    818       **
   761    819       ** Start up the given client.
   762    820       */
   763    821       if( strcmp(zCmd, "start")==0 ){
   764    822         int iNewClient = atoi(azArg[0]);
   765         -      char *zSys;
   766         -      if( iNewClient<1 || iNewClient>=sizeof(isRunning) ){
   767         -        errorMessage("line %d of %s: bad client number: %d",
   768         -                   prevLine, zFilename, iNewClient);
   769         -        goto start_error;
          823  +      if( iNewClient>0 ){
          824  +        startClient(iNewClient);
   770    825         }
   771         -      if( isRunning[iNewClient] ){
   772         -        errorMessage("line %d of %s: client already running: %d",
   773         -                     prevLine, zFilename, iNewClient);
   774         -        goto start_error;
   775         -      }
   776         -      zSys = sqlite3_mprintf(
   777         -                 "%s \"%s\" --client %d --trace %d %s&",
   778         -                 g.argv0, g.zDbFile, iNewClient, g.iTrace,
   779         -                 g.bSqlTrace ? "--sqltrace " : "");
   780         -
   781         -      system(zSys);
   782         -      sqlite3_free(zSys);
   783         -      isRunning[iNewClient] = 1;
   784         -      start_error:  {/* no-op */}
   785    826       }else
   786    827   
   787    828       /*
   788    829       **  --wait CLIENT TIMEOUT
   789    830       **
   790    831       ** Wait until all tasks complete for the given client.  If CLIENT is
   791    832       ** "all" then wait for all clients to complete.  Wait no longer than
................................................................................
   799    840       }else
   800    841   
   801    842       /*
   802    843       **  --task CLIENT
   803    844       **     <task-content-here>
   804    845       **  --end
   805    846       **
   806         -    ** Assign work to a client.
          847  +    ** Assign work to a client.  Start the client if it is not running
          848  +    ** already.
   807    849       */
   808    850       if( strcmp(zCmd, "task")==0 ){
   809    851         int iTarget = atoi(azArg[0]);
   810    852         int iEnd;
   811    853         char *zTask;
   812         -      sqlite3_stmt *pStmt;
   813    854         iEnd = findEnd(zScript+ii+len, &lineno);
   814         -      if( iTarget<0 || iTarget>=sizeof(isRunning)
   815         -            || !isRunning[iTarget] ){
   816         -        errorMessage("line %d of %s: client %d is not running",
          855  +      if( iTarget<0 ){
          856  +        errorMessage("line %d of %s: bad client number: %d",
   817    857                        prevLine, zFilename, iTarget);
   818         -        goto task_error;
          858  +      }else{
          859  +        zTask = sqlite3_mprintf("%.*s", iEnd, zScript+ii+len);
          860  +        startClient(iTarget);
          861  +        runSql("INSERT INTO task(client,script)"
          862  +               " VALUES(%d,'%q')", iTarget, zTask);
          863  +        sqlite3_free(zTask);
   819    864         }
   820         -      zTask = sqlite3_mprintf("%.*s", iEnd, zScript+ii+len);
   821         -      pStmt = prepareSql("INSERT INTO task(client,script)"
   822         -                         " VALUES(%d,'%q')", iTarget, zTask);
   823         -      sqlite3_free(zTask);
   824         -      while( (rc = sqlite3_step(pStmt))==SQLITE_BUSY ){
   825         -        sqlite3_reset(pStmt);
   826         -        sqlite3_sleep(10);
   827         -      }
   828         -      sqlite3_finalize(pStmt);
   829         -      task_error:
   830    865         iEnd += tokenLength(zScript+ii+len+iEnd, &lineno);
   831    866         len += iEnd;
   832    867         iBegin = ii+len;
   833    868       }else
   834    869   
   835    870       /* error */{
   836    871         errorMessage("line %d of %s: unknown command --%s",
................................................................................
   960    995     }else{
   961    996       iClient =  0;
   962    997       unlink(g.zDbFile);
   963    998       openFlags |= SQLITE_OPEN_CREATE;
   964    999     }
   965   1000     rc = sqlite3_open_v2(g.zDbFile, &g.db, openFlags, g.zVfs);
   966   1001     if( rc ) fatalError("cannot open [%s]", g.zDbFile);
         1002  +  sqlite3_busy_handler(g.db, busyHandler, 0);
         1003  +  g.iTimeout = DEFAULT_TIMEOUT;
   967   1004     if( g.bSqlTrace ) sqlite3_trace(g.db, sqlTraceCallback, 0);
   968   1005     if( iClient>0 ){
   969   1006       if( n>0 ) unrecognizedArguments(argv[0], n, argv+2);
   970   1007       if( g.iTrace ) logMessage("start-client");
   971   1008       while(1){
   972   1009         char zTaskName[50];
   973   1010         rc = startScript(iClient, &zScript, &taskId);
   974   1011         if( rc==SQLITE_DONE ) break;
   975   1012         if( g.iTrace ) logMessage("begin task %d", taskId);
   976   1013         sqlite3_snprintf(sizeof(zTaskName), zTaskName, "client%02d-task-%d",
   977   1014                          iClient, taskId);
   978   1015         runScript(iClient, taskId, zScript, zTaskName);
   979   1016         if( g.iTrace ) logMessage("end task %d", taskId);
   980         -      finishScript(taskId);
         1017  +      finishScript(iClient, taskId, 0);
   981   1018         sqlite3_sleep(10);
   982   1019       }
   983   1020       if( g.iTrace ) logMessage("end-client");
   984   1021     }else{
   985   1022       sqlite3_stmt *pStmt;
         1023  +    int iTimeout;
   986   1024       if( n==0 ){
   987   1025         fatalError("missing script filename");
   988   1026       }
   989   1027       if( n>1 ) unrecognizedArguments(argv[0], n, argv+2);
   990   1028       runSql(
   991   1029         "CREATE TABLE task(\n"
   992   1030         "  id INTEGER PRIMARY KEY,\n"
   993   1031         "  client INTEGER,\n"
   994   1032         "  starttime DATE,\n"
   995   1033         "  endtime DATE,\n"
   996   1034         "  script TEXT\n"
   997   1035         ");"
   998         -      "CREATE TABLE clienterror(cnt);\n"
   999         -      "INSERT INTO clienterror VALUES(0);\n"
         1036  +      "CREATE INDEX task_i1 ON task(client, starttime);\n"
         1037  +      "CREATE INDEX task_i2 ON task(client, endtime);\n"
         1038  +      "CREATE TABLE counters(nError,nTest);\n"
         1039  +      "INSERT INTO counters VALUES(0,0);\n"
         1040  +      "CREATE TABLE client(id INTEGER PRIMARY KEY, wantHalt);\n"
  1000   1041       );
  1001   1042       zScript = readFile(argv[2]);
  1002   1043       if( g.iTrace ) logMessage("begin script [%s]\n", argv[2]);
  1003   1044       runScript(0, 0, zScript, argv[2]);
  1004   1045       sqlite3_free(zScript);
  1005   1046       if( g.iTrace ) logMessage("end script [%s]\n", argv[2]);
  1006   1047       waitForClient(0, 2000, "during shutdown...\n");
  1007         -    while( trySql("CREATE TABLE halt(x);")==SQLITE_BUSY ){
         1048  +    trySql("UPDATE client SET wantHalt=1");
         1049  +    sqlite3_sleep(10);
         1050  +    g.iTimeout = 0;
         1051  +    iTimeout = 1000;
         1052  +    while( ((rc = trySql("SELECT 1 FROM client"))==SQLITE_BUSY
         1053  +        || rc==SQLITE_ROW) && iTimeout>0 ){
  1008   1054         sqlite3_sleep(10);
         1055  +      iTimeout -= 10;
  1009   1056       }
  1010   1057       sqlite3_sleep(100);
  1011         -    pStmt = prepareSql("SELECT cnt FROM clienterror");
  1012         -    while( (rc = sqlite3_step(pStmt))==SQLITE_BUSY ){
         1058  +    pStmt = prepareSql("SELECT nError, nTest FROM counters");
         1059  +    iTimeout = 1000;
         1060  +    while( (rc = sqlite3_step(pStmt))==SQLITE_BUSY && iTimeout>0 ){
  1013   1061         sqlite3_sleep(10);
         1062  +      iTimeout -= 10;
  1014   1063       }
  1015   1064       if( rc==SQLITE_ROW ){
  1016   1065         g.nError += sqlite3_column_int(pStmt, 0);
         1066  +      g.nTest += sqlite3_column_int(pStmt, 1);
  1017   1067       }
  1018   1068       sqlite3_finalize(pStmt);
  1019   1069     }
  1020   1070     sqlite3_close(g.db);  
  1021   1071     maybeClose(g.pLog);
  1022   1072     maybeClose(g.pErrLog);
  1023   1073     if( iClient==0 ){
  1024         -    if( g.nError ){
  1025         -      printf("ERRORS: %d\n", g.nError);
  1026         -    }else if( g.iTrace ){
  1027         -      printf("All OK\n");
  1028         -    }
         1074  +    printf("Summary: %d errors in %d tests\n", g.nError, g.nTest);
  1029   1075     }
  1030   1076     return g.nError>0;
  1031   1077   }

Added mptest/multiwrite01.test.

            1  +/*
            2  +** This script sets up five different tasks all writing and updating
            3  +** the database at the same time, but each in its own table.
            4  +*/
            5  +--task 1
            6  +  DROP TABLE IF EXISTS t1;
            7  +  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
            8  +  --sleep 1
            9  +  INSERT INTO t1 VALUES(1, randomblob(2000));
           10  +  INSERT INTO t1 VALUES(2, randomblob(1000));
           11  +  --sleep 1
           12  +  INSERT INTO t1 SELECT a+2, randomblob(1500) FROM t1;
           13  +  INSERT INTO t1 SELECT a+4, randomblob(1500) FROM t1;
           14  +  INSERT INTO t1 SELECT a+8, randomblob(1500) FROM t1;
           15  +  --sleep 1
           16  +  INSERT INTO t1 SELECT a+16, randomblob(1500) FROM t1;
           17  +  --sleep 1
           18  +  INSERT INTO t1 SELECT a+32, randomblob(1500) FROM t1;
           19  +  SELECT count(*) FROM t1;
           20  +  --match 64
           21  +  SELECT avg(length(b)) FROM t1;
           22  +  --match 1500.0
           23  +  --sleep 2
           24  +  UPDATE t1 SET b='x'||a||'y';
           25  +  SELECT total(length(b)) FROM t1;
           26  +  --match 247
           27  +--end
           28  +
           29  +
           30  +--task 2
           31  +  DROP TABLE IF EXISTS t2;
           32  +  CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
           33  +  --sleep 1
           34  +  INSERT INTO t2 VALUES(1, randomblob(2000));
           35  +  INSERT INTO t2 VALUES(2, randomblob(1000));
           36  +  --sleep 1
           37  +  INSERT INTO t2 SELECT a+2, randomblob(1500) FROM t2;
           38  +  INSERT INTO t2 SELECT a+4, randomblob(1500) FROM t2;
           39  +  INSERT INTO t2 SELECT a+8, randomblob(1500) FROM t2;
           40  +  --sleep 1
           41  +  INSERT INTO t2 SELECT a+16, randomblob(1500) FROM t2;
           42  +  --sleep 1
           43  +  INSERT INTO t2 SELECT a+32, randomblob(1500) FROM t2;
           44  +  SELECT count(*) FROM t2;
           45  +  --match 64
           46  +  SELECT avg(length(b)) FROM t2;
           47  +  --match 1500.0
           48  +  --sleep 2
           49  +  UPDATE t2 SET b='x'||a||'y';
           50  +  SELECT total(length(b)) FROM t2;
           51  +  --match 247
           52  +--end
           53  +
           54  +--task 3
           55  +  DROP TABLE IF EXISTS t3;
           56  +  CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
           57  +  --sleep 1
           58  +  INSERT INTO t3 VALUES(1, randomblob(2000));
           59  +  INSERT INTO t3 VALUES(2, randomblob(1000));
           60  +  --sleep 1
           61  +  INSERT INTO t3 SELECT a+2, randomblob(1500) FROM t3;
           62  +  INSERT INTO t3 SELECT a+4, randomblob(1500) FROM t3;
           63  +  INSERT INTO t3 SELECT a+8, randomblob(1500) FROM t3;
           64  +  --sleep 1
           65  +  INSERT INTO t3 SELECT a+16, randomblob(1500) FROM t3;
           66  +  --sleep 1
           67  +  INSERT INTO t3 SELECT a+32, randomblob(1500) FROM t3;
           68  +  SELECT count(*) FROM t3;
           69  +  --match 64
           70  +  SELECT avg(length(b)) FROM t3;
           71  +  --match 1500.0
           72  +  --sleep 2
           73  +  UPDATE t3 SET b='x'||a||'y';
           74  +  SELECT total(length(b)) FROM t3;
           75  +  --match 247
           76  +--end
           77  +
           78  +--task 4
           79  +  DROP TABLE IF EXISTS t4;
           80  +  CREATE TABLE t4(a INTEGER PRIMARY KEY, b);
           81  +  --sleep 1
           82  +  INSERT INTO t4 VALUES(1, randomblob(2000));
           83  +  INSERT INTO t4 VALUES(2, randomblob(1000));
           84  +  --sleep 1
           85  +  INSERT INTO t4 SELECT a+2, randomblob(1500) FROM t4;
           86  +  INSERT INTO t4 SELECT a+4, randomblob(1500) FROM t4;
           87  +  INSERT INTO t4 SELECT a+8, randomblob(1500) FROM t4;
           88  +  --sleep 1
           89  +  INSERT INTO t4 SELECT a+16, randomblob(1500) FROM t4;
           90  +  --sleep 1
           91  +  INSERT INTO t4 SELECT a+32, randomblob(1500) FROM t4;
           92  +  SELECT count(*) FROM t4;
           93  +  --match 64
           94  +  SELECT avg(length(b)) FROM t4;
           95  +  --match 1500.0
           96  +  --sleep 2
           97  +  UPDATE t4 SET b='x'||a||'y';
           98  +  SELECT total(length(b)) FROM t4;
           99  +  --match 247
          100  +--end
          101  +
          102  +--task 5
          103  +  DROP TABLE IF EXISTS t5;
          104  +  CREATE TABLE t5(a INTEGER PRIMARY KEY, b);
          105  +  --sleep 1
          106  +  INSERT INTO t5 VALUES(1, randomblob(2000));
          107  +  INSERT INTO t5 VALUES(2, randomblob(1000));
          108  +  --sleep 1
          109  +  INSERT INTO t5 SELECT a+2, randomblob(1500) FROM t5;
          110  +  INSERT INTO t5 SELECT a+4, randomblob(1500) FROM t5;
          111  +  INSERT INTO t5 SELECT a+8, randomblob(1500) FROM t5;
          112  +  --sleep 1
          113  +  INSERT INTO t5 SELECT a+16, randomblob(1500) FROM t5;
          114  +  --sleep 1
          115  +  INSERT INTO t5 SELECT a+32, randomblob(1500) FROM t5;
          116  +  SELECT count(*) FROM t5;
          117  +  --match 64
          118  +  SELECT avg(length(b)) FROM t5;
          119  +  --match 1500.0
          120  +  --sleep 2
          121  +  UPDATE t5 SET b='x'||a||'y';
          122  +  SELECT total(length(b)) FROM t5;
          123  +  --match 247
          124  +--end
          125  +
          126  +--wait all
          127  +SELECT count(*), total(length(b)) FROM t1;
          128  +--match 64 247
          129  +SELECT count(*), total(length(b)) FROM t2;
          130  +--match 64 247
          131  +SELECT count(*), total(length(b)) FROM t3;
          132  +--match 64 247
          133  +SELECT count(*), total(length(b)) FROM t4;
          134  +--match 64 247
          135  +SELECT count(*), total(length(b)) FROM t5;
          136  +--match 64 247
          137  +DROP TABLE t1;
          138  +DROP TABLE t2;
          139  +DROP TABLE t3;
          140  +DROP TABLE t4;
          141  +DROP TABLE t5;