modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/lsm1/lsm-test/lsmtest1.c (about)

     1  
     2  #include "lsmtest.h"
     3  
     4  #define DATA_SEQUENTIAL TEST_DATASOURCE_SEQUENCE
     5  #define DATA_RANDOM     TEST_DATASOURCE_RANDOM
     6  
     7  typedef struct Datatest1 Datatest1;
     8  typedef struct Datatest2 Datatest2;
     9  
    10  /*
    11  ** An instance of the following structure contains parameters used to
    12  ** customize the test function in this file. Test procedure:
    13  **
    14  **   1. Create a data-source based on the "datasource definition" vars.
    15  **
    16  **   2. Insert nRow key value pairs into the database.
    17  **
    18  **   3. Delete all keys from the database. Deletes are done in the same 
    19  **      order as the inserts.
    20  **
    21  ** During steps 2 and 3 above, after each Datatest1.nVerify inserts or
    22  ** deletes, the following:
    23  **
    24  **   a. Run Datasource.nTest key lookups and check the results are as expected.
    25  **
    26  **   b. If Datasource.bTestScan is true, run a handful (8) of range
    27  **      queries (scanning forwards and backwards). Check that the results
    28  **      are as expected.
    29  **
    30  **   c. Close and reopen the database. Then run (a) and (b) again.
    31  */
    32  struct Datatest1 {
    33    /* Datasource definition */
    34    DatasourceDefn defn;
    35  
    36    /* Test procedure parameters */
    37    int nRow;                       /* Number of rows to insert then delete */
    38    int nVerify;                    /* How often to verify the db contents */
    39    int nTest;                      /* Number of keys to test (0==all) */
    40    int bTestScan;                  /* True to do scan tests */
    41  };
    42  
    43  /*
    44  ** An instance of the following data structure is used to describe the
    45  ** second type of test case in this file. The chief difference between 
    46  ** these tests and those described by Datatest1 is that these tests also
    47  ** experiment with range-delete operations. Tests proceed as follows:
    48  **
    49  **     1. Open the datasource described by Datatest2.defn. 
    50  **
    51  **     2. Open a connection on an empty database.
    52  **
    53  **     3. Do this Datatest2.nIter times:
    54  **
    55  **        a) Insert Datatest2.nWrite key-value pairs from the datasource.
    56  **
    57  **        b) Select two pseudo-random keys and use them as the start
    58  **           and end points of a range-delete operation.
    59  **
    60  **        c) Verify that the contents of the database are as expected (see
    61  **           below for details).
    62  **
    63  **        d) Close and then reopen the database handle.
    64  **
    65  **        e) Verify that the contents of the database are still as expected.
    66  **
    67  ** The inserts and range deletes are run twice - once on the database being
    68  ** tested and once using a control system (sqlite3, kc etc. - something that 
    69  ** works). In order to verify that the contents of the db being tested are
    70  ** correct, the test runs a bunch of scans and lookups on both the test and
    71  ** control databases. If the results are the same, the test passes.
    72  */
    73  struct Datatest2 {
    74    DatasourceDefn defn;
    75    int nRange;
    76    int nWrite;                     /* Number of writes per iteration */
    77    int nIter;                      /* Total number of iterations to run */
    78  };
    79  
    80  /*
    81  ** Generate a unique name for the test case pTest with database system
    82  ** zSystem.
    83  */
    84  static char *getName(const char *zSystem, int bRecover, Datatest1 *pTest){
    85    char *zRet;
    86    char *zData;
    87    zData = testDatasourceName(&pTest->defn);
    88    zRet = testMallocPrintf("data.%s.%s.rec=%d.%d.%d", 
    89        zSystem, zData, bRecover, pTest->nRow, pTest->nVerify
    90    );
    91    testFree(zData);
    92    return zRet;
    93  }
    94  
    95  int testControlDb(TestDb **ppDb){
    96  #ifdef HAVE_KYOTOCABINET
    97    return tdb_open("kyotocabinet", "tmp.db", 1, ppDb);
    98  #else
    99    return tdb_open("sqlite3", "", 1, ppDb);
   100  #endif
   101  }
   102  
   103  void testDatasourceFetch(
   104    TestDb *pDb,                    /* Database handle */
   105    Datasource *pData,
   106    int iKey,
   107    int *pRc                        /* IN/OUT: Error code */
   108  ){
   109    void *pKey; int nKey;           /* Database key to query for */
   110    void *pVal; int nVal;           /* Expected result of query */
   111  
   112    testDatasourceEntry(pData, iKey, &pKey, &nKey, &pVal, &nVal);
   113    testFetch(pDb, pKey, nKey, pVal, nVal, pRc);
   114  }
   115  
   116  /*
   117  ** This function is called to test that the contents of database pDb
   118  ** are as expected. In this case, expected is defined as containing
   119  ** key-value pairs iFirst through iLast, inclusive, from data source 
   120  ** pData. In other words, a loop like the following could be used to
   121  ** construct a database with identical contents from scratch.
   122  **
   123  **   for(i=iFirst; i<=iLast; i++){
   124  **     testDatasourceEntry(pData, i, &pKey, &nKey, &pVal, &nVal);
   125  **     // insert (pKey, nKey) -> (pVal, nVal) into database
   126  **   }
   127  **
   128  ** The key domain consists of keys 0 to (nRow-1), inclusive, from
   129  ** data source pData. For both scan and lookup tests, keys are selected
   130  ** pseudo-randomly from within this set.
   131  **
   132  ** This function runs nLookupTest lookup tests and nScanTest scan tests.
   133  **
   134  ** A lookup test consists of selecting a key from the domain and querying
   135  ** pDb for it. The test fails if the presence of the key and, if present,
   136  ** the associated value do not match the expectations defined above.
   137  **
   138  ** A scan test involves selecting a key from the domain and running
   139  ** the following queries:
   140  **
   141  **   1. Scan all keys equal to or greater than the key, in ascending order.
   142  **   2. Scan all keys equal to or smaller than the key, in descending order.
   143  **
   144  ** Additionally, if nLookupTest is greater than zero, the following are
   145  ** run once:
   146  **
   147  **   1. Scan all keys in the db, in ascending order.
   148  **   2. Scan all keys in the db, in descending order.
   149  **
   150  ** As you would assume, the test fails if the returned values do not match
   151  ** expectations.
   152  */
   153  void testDbContents(
   154    TestDb *pDb,                    /* Database handle being tested */
   155    Datasource *pData,              /* pDb contains data from here */
   156    int nRow,                       /* Size of key domain */
   157    int iFirst,                     /* Index of first key from pData in pDb */
   158    int iLast,                      /* Index of last key from pData in pDb */
   159    int nLookupTest,                /* Number of lookup tests to run */
   160    int nScanTest,                  /* Number of scan tests to run */
   161    int *pRc                        /* IN/OUT: Error code */
   162  ){
   163    int j;
   164    int rc = *pRc;
   165  
   166    if( rc==0 && nScanTest ){
   167      TestDb *pDb2 = 0;
   168  
   169      /* Open a control db (i.e. one that we assume works) */
   170      rc = testControlDb(&pDb2);
   171  
   172      for(j=iFirst; rc==0 && j<=iLast; j++){
   173        void *pKey; int nKey;         /* Database key to insert */
   174        void *pVal; int nVal;         /* Database value to insert */
   175        testDatasourceEntry(pData, j, &pKey, &nKey, &pVal, &nVal);
   176        rc = tdb_write(pDb2, pKey, nKey, pVal, nVal);
   177      }
   178  
   179      if( rc==0 ){
   180        int iKey1;
   181        int iKey2;
   182        void *pKey1; int nKey1;       /* Start key */
   183        void *pKey2; int nKey2;       /* Final key */
   184  
   185        iKey1 = testPrngValue((iFirst<<8) + (iLast<<16)) % nRow;
   186        iKey2 = testPrngValue((iLast<<8) + (iFirst<<16)) % nRow;
   187        testDatasourceEntry(pData, iKey1, &pKey2, &nKey1, 0, 0);
   188        pKey1 = testMalloc(nKey1+1);
   189        memcpy(pKey1, pKey2, nKey1+1);
   190        testDatasourceEntry(pData, iKey2, &pKey2, &nKey2, 0, 0);
   191  
   192        testScanCompare(pDb2, pDb, 0, 0, 0,         0, 0,         &rc);
   193        testScanCompare(pDb2, pDb, 0, 0, 0,         pKey2, nKey2, &rc);
   194        testScanCompare(pDb2, pDb, 0, pKey1, nKey1, 0, 0,         &rc);
   195        testScanCompare(pDb2, pDb, 0, pKey1, nKey1, pKey2, nKey2, &rc);
   196        testScanCompare(pDb2, pDb, 1, 0, 0,         0, 0,         &rc);
   197        testScanCompare(pDb2, pDb, 1, 0, 0,         pKey2, nKey2, &rc);
   198        testScanCompare(pDb2, pDb, 1, pKey1, nKey1, 0, 0,         &rc);
   199        testScanCompare(pDb2, pDb, 1, pKey1, nKey1, pKey2, nKey2, &rc);
   200        testFree(pKey1);
   201      }
   202      tdb_close(pDb2);
   203    }
   204  
   205    /* Test some lookups. */
   206    for(j=0; rc==0 && j<nLookupTest; j++){
   207      int iKey;                     /* Datasource key to test */
   208      void *pKey; int nKey;         /* Database key to query for */
   209      void *pVal; int nVal;         /* Expected result of query */
   210  
   211      if( nLookupTest>=nRow ){
   212        iKey = j;
   213      }else{
   214        iKey = testPrngValue(j + (iFirst<<8) + (iLast<<16)) % nRow;
   215      }
   216  
   217      testDatasourceEntry(pData, iKey, &pKey, &nKey, &pVal, &nVal);
   218      if( iFirst>iKey || iKey>iLast ){
   219        pVal = 0;
   220        nVal = -1;
   221      }
   222  
   223      testFetch(pDb, pKey, nKey, pVal, nVal, &rc);
   224    }
   225  
   226    *pRc = rc;
   227  }
   228  
   229  /*
   230  ** This function should be called during long running test cases to output
   231  ** the progress dots (...) to stdout.
   232  */
   233  void testCaseProgress(int i, int n, int nDot, int *piDot){
   234    int iDot = *piDot;
   235    while( iDot < ( ((nDot*2+1) * i) / (n*2) ) ){
   236      printf(".");
   237      fflush(stdout);
   238      iDot++;
   239    }
   240    *piDot = iDot;
   241  }
   242  
   243  int testCaseNDot(void){ return 20; }
   244  
   245  #if 0
   246  static void printScanCb(
   247      void *pCtx, void *pKey, int nKey, void *pVal, int nVal
   248  ){
   249    printf("%s\n", (char *)pKey);
   250    fflush(stdout);
   251  }
   252  #endif
   253  
   254  void testReopenRecover(TestDb **ppDb, int *pRc){
   255    if( *pRc==0 ){
   256      const char *zLib = tdb_library_name(*ppDb);
   257      const char *zDflt = tdb_default_db(zLib);
   258      testCopyLsmdb(zDflt, "bak.db");
   259      testClose(ppDb);
   260      testCopyLsmdb("bak.db", zDflt);
   261      *pRc = tdb_open(zLib, 0, 0, ppDb);
   262    }
   263  }
   264  
   265  
   266  static void doDataTest1(
   267    const char *zSystem,            /* Database system to test */
   268    int bRecover,
   269    Datatest1 *p,                   /* Structure containing test parameters */
   270    int *pRc                        /* OUT: Error code */
   271  ){
   272    int i;
   273    int iDot;
   274    int rc = LSM_OK;
   275    Datasource *pData;
   276    TestDb *pDb;
   277  
   278    /* Start the test case, open a database and allocate the datasource. */
   279    pDb = testOpen(zSystem, 1, &rc);
   280    pData = testDatasourceNew(&p->defn);
   281  
   282    i = 0;
   283    iDot = 0;
   284    while( rc==LSM_OK && i<p->nRow ){
   285  
   286      /* Insert some data */
   287      testWriteDatasourceRange(pDb, pData, i, p->nVerify, &rc);
   288      i += p->nVerify;
   289  
   290      /* Check that the db content is correct. */
   291      testDbContents(pDb, pData, p->nRow, 0, i-1, p->nTest, p->bTestScan, &rc);
   292  
   293      if( bRecover ){
   294        testReopenRecover(&pDb, &rc);
   295      }else{
   296        testReopen(&pDb, &rc);
   297      }
   298  
   299      /* Check that the db content is still correct. */
   300      testDbContents(pDb, pData, p->nRow, 0, i-1, p->nTest, p->bTestScan, &rc);
   301  
   302      /* Update the progress dots... */
   303      testCaseProgress(i, p->nRow, testCaseNDot()/2, &iDot);
   304    }
   305  
   306    i = 0;
   307    iDot = 0;
   308    while( rc==LSM_OK && i<p->nRow ){
   309  
   310      /* Delete some entries */
   311      testDeleteDatasourceRange(pDb, pData, i, p->nVerify, &rc);
   312      i += p->nVerify;
   313  
   314      /* Check that the db content is correct. */
   315      testDbContents(pDb, pData, p->nRow, i, p->nRow-1,p->nTest,p->bTestScan,&rc);
   316  
   317      /* Close and reopen the database. */
   318      if( bRecover ){
   319        testReopenRecover(&pDb, &rc);
   320      }else{
   321        testReopen(&pDb, &rc);
   322      }
   323  
   324      /* Check that the db content is still correct. */
   325      testDbContents(pDb, pData, p->nRow, i, p->nRow-1,p->nTest,p->bTestScan,&rc);
   326  
   327      /* Update the progress dots... */
   328      testCaseProgress(i, p->nRow, testCaseNDot()/2, &iDot);
   329    }
   330  
   331    /* Free the datasource, close the database and finish the test case. */
   332    testDatasourceFree(pData);
   333    tdb_close(pDb);
   334    testCaseFinish(rc);
   335    *pRc = rc;
   336  }
   337  
   338  
   339  void test_data_1(
   340    const char *zSystem,            /* Database system name */
   341    const char *zPattern,           /* Run test cases that match this pattern */
   342    int *pRc                        /* IN/OUT: Error code */
   343  ){
   344    Datatest1 aTest[] = {
   345      { {DATA_RANDOM,     500,600,   1000,2000},     1000,  100,  10,  0},
   346      { {DATA_RANDOM,     20,25,     100,200},       1000,  250, 1000, 1},
   347      { {DATA_RANDOM,     8,10,      100,200},       1000,  250, 1000, 1},
   348      { {DATA_RANDOM,     8,10,      10,20},         1000,  250, 1000, 1},
   349      { {DATA_RANDOM,     8,10,      1000,2000},     1000,  250, 1000, 1},
   350      { {DATA_RANDOM,     8,100,     10000,20000},    100,   25,  100, 1},
   351      { {DATA_RANDOM,     80,100,    10,20},         1000,  250, 1000, 1},
   352      { {DATA_RANDOM,     5000,6000, 10,20},          100,   25,  100, 1},
   353      { {DATA_SEQUENTIAL, 5,10,      10,20},         1000,  250, 1000, 1},
   354      { {DATA_SEQUENTIAL, 5,10,      100,200},       1000,  250, 1000, 1},
   355      { {DATA_SEQUENTIAL, 5,10,      1000,2000},     1000,  250, 1000, 1},
   356      { {DATA_SEQUENTIAL, 5,100,     10000,20000},    100,   25,  100, 1},
   357      { {DATA_RANDOM,     10,10,     100,100},     100000, 1000,  100, 0},
   358      { {DATA_SEQUENTIAL, 10,10,     100,100},     100000, 1000,  100, 0},
   359    };
   360  
   361    int i;
   362    int bRecover;
   363  
   364    for(bRecover=0; bRecover<2; bRecover++){
   365      if( bRecover==1 && memcmp(zSystem, "lsm", 3) ) break;
   366      for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
   367        char *zName = getName(zSystem, bRecover, &aTest[i]);
   368        if( testCaseBegin(pRc, zPattern, "%s", zName) ){
   369          doDataTest1(zSystem, bRecover, &aTest[i], pRc);
   370        }
   371        testFree(zName);
   372      }
   373    }
   374  }
   375  
   376  void testCompareDb(
   377    Datasource *pData,
   378    int nData,
   379    int iSeed,
   380    TestDb *pControl,
   381    TestDb *pDb,
   382    int *pRc
   383  ){
   384    int i;
   385  
   386    static int nCall = 0;
   387    nCall++;
   388  
   389    testScanCompare(pControl, pDb, 0, 0, 0,         0, 0,         pRc);
   390    testScanCompare(pControl, pDb, 1, 0, 0,         0, 0,         pRc);
   391  
   392    if( *pRc==0 ){
   393      int iKey1;
   394      int iKey2;
   395      void *pKey1; int nKey1;       /* Start key */
   396      void *pKey2; int nKey2;       /* Final key */
   397  
   398      iKey1 = testPrngValue(iSeed) % nData;
   399      iKey2 = testPrngValue(iSeed+1) % nData;
   400      testDatasourceEntry(pData, iKey1, &pKey2, &nKey1, 0, 0);
   401      pKey1 = testMalloc(nKey1+1);
   402      memcpy(pKey1, pKey2, nKey1+1);
   403      testDatasourceEntry(pData, iKey2, &pKey2, &nKey2, 0, 0);
   404  
   405      testScanCompare(pControl, pDb, 0, 0, 0,         pKey2, nKey2, pRc);
   406      testScanCompare(pControl, pDb, 0, pKey1, nKey1, 0, 0,         pRc);
   407      testScanCompare(pControl, pDb, 0, pKey1, nKey1, pKey2, nKey2, pRc);
   408      testScanCompare(pControl, pDb, 1, 0, 0,         pKey2, nKey2, pRc);
   409      testScanCompare(pControl, pDb, 1, pKey1, nKey1, 0, 0,         pRc);
   410      testScanCompare(pControl, pDb, 1, pKey1, nKey1, pKey2, nKey2, pRc);
   411      testFree(pKey1);
   412    }
   413  
   414    for(i=0; i<nData && *pRc==0; i++){
   415      void *pKey; int nKey;
   416      testDatasourceEntry(pData, i, &pKey, &nKey, 0, 0);
   417      testFetchCompare(pControl, pDb, pKey, nKey, pRc);
   418    }
   419  }
   420  
   421  static void doDataTest2(
   422    const char *zSystem,            /* Database system to test */
   423    int bRecover,
   424    Datatest2 *p,                   /* Structure containing test parameters */
   425    int *pRc                        /* OUT: Error code */
   426  ){
   427    TestDb *pDb;
   428    TestDb *pControl;
   429    Datasource *pData;
   430    int i;
   431    int rc = LSM_OK;
   432    int iDot = 0;
   433  
   434    /* Start the test case, open a database and allocate the datasource. */
   435    pDb = testOpen(zSystem, 1, &rc);
   436    pData = testDatasourceNew(&p->defn);
   437    rc = testControlDb(&pControl);
   438  
   439    if( tdb_lsm(pDb) ){
   440      int nBuf = 32 * 1024 * 1024;
   441      lsm_config(tdb_lsm(pDb), LSM_CONFIG_AUTOFLUSH, &nBuf);
   442    }
   443  
   444    for(i=0; rc==0 && i<p->nIter; i++){
   445      void *pKey1; int nKey1;
   446      void *pKey2; int nKey2;
   447      int ii;
   448      int nRange = MIN(p->nIter*p->nWrite, p->nRange);
   449  
   450      for(ii=0; rc==0 && ii<p->nWrite; ii++){
   451        int iKey = (i*p->nWrite + ii) % p->nRange;
   452        testWriteDatasource(pControl, pData, iKey, &rc);
   453        testWriteDatasource(pDb, pData, iKey, &rc);
   454      }
   455  
   456      testDatasourceEntry(pData, i+1000000, &pKey1, &nKey1, 0, 0);
   457      pKey1 = testMallocCopy(pKey1, nKey1);
   458      testDatasourceEntry(pData, i+2000000, &pKey2, &nKey2, 0, 0);
   459  
   460      testDeleteRange(pDb, pKey1, nKey1, pKey2, nKey2, &rc);
   461      testDeleteRange(pControl, pKey1, nKey1, pKey2, nKey2, &rc);
   462      testFree(pKey1);
   463  
   464      testCompareDb(pData, nRange, i, pControl, pDb, &rc);
   465      if( bRecover ){
   466        testReopenRecover(&pDb, &rc);
   467      }else{
   468        testReopen(&pDb, &rc);
   469      }
   470      testCompareDb(pData, nRange, i, pControl, pDb, &rc);
   471  
   472      /* Update the progress dots... */
   473      testCaseProgress(i, p->nIter, testCaseNDot(), &iDot);
   474    }
   475  
   476    testClose(&pDb);
   477    testClose(&pControl);
   478    testDatasourceFree(pData);
   479    testCaseFinish(rc);
   480    *pRc = rc;
   481  }
   482  
   483  static char *getName2(const char *zSystem, int bRecover, Datatest2 *pTest){
   484    char *zRet;
   485    char *zData;
   486    zData = testDatasourceName(&pTest->defn);
   487    zRet = testMallocPrintf("data2.%s.%s.rec=%d.%d.%d.%d", 
   488        zSystem, zData, bRecover, pTest->nRange, pTest->nWrite, pTest->nIter
   489    );
   490    testFree(zData);
   491    return zRet;
   492  }
   493  
   494  void test_data_2(
   495    const char *zSystem,            /* Database system name */
   496    const char *zPattern,           /* Run test cases that match this pattern */
   497    int *pRc                        /* IN/OUT: Error code */
   498  ){
   499    Datatest2 aTest[] = {
   500        /* defn,                                 nRange, nWrite, nIter */
   501      { {DATA_RANDOM,     20,25,     100,200},   10000,  10,     50   },
   502      { {DATA_RANDOM,     20,25,     100,200},   10000,  200,    50   },
   503      { {DATA_RANDOM,     20,25,     100,200},   100,    10,     1000 },
   504      { {DATA_RANDOM,     20,25,     100,200},   100,    200,    50   },
   505    };
   506  
   507    int i;
   508    int bRecover;
   509  
   510    for(bRecover=0; bRecover<2; bRecover++){
   511      if( bRecover==1 && memcmp(zSystem, "lsm", 3) ) break;
   512      for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
   513        char *zName = getName2(zSystem, bRecover, &aTest[i]);
   514        if( testCaseBegin(pRc, zPattern, "%s", zName) ){
   515          doDataTest2(zSystem, bRecover, &aTest[i], pRc);
   516        }
   517        testFree(zName);
   518      }
   519    }
   520  }
   521  
   522  /*************************************************************************
   523  ** Test case data3.*
   524  */
   525  
   526  typedef struct Datatest3 Datatest3;
   527  struct Datatest3 {
   528    int nRange;                     /* Keys are between 1 and this value, incl. */
   529    int nIter;                      /* Number of iterations */
   530    int nWrite;                     /* Number of writes per iteration */
   531    int nDelete;                    /* Number of deletes per iteration */
   532  
   533    int nValMin;                    /* Minimum value size for writes */
   534    int nValMax;                    /* Maximum value size for writes */
   535  };
   536  
   537  void testPutU32(u8 *aBuf, u32 iVal){
   538    aBuf[0] = (iVal >> 24) & 0xFF;
   539    aBuf[1] = (iVal >> 16) & 0xFF;
   540    aBuf[2] = (iVal >>  8) & 0xFF;
   541    aBuf[3] = (iVal >>  0) & 0xFF;
   542  }
   543  
   544  void dt3PutKey(u8 *aBuf, int iKey){
   545    assert( iKey<100000 && iKey>=0 );
   546    sprintf((char *)aBuf, "%.5d", iKey);
   547  }
   548  
   549  static void doDataTest3(
   550    const char *zSystem,            /* Database system to test */
   551    Datatest3 *p,                   /* Structure containing test parameters */
   552    int *pRc                        /* OUT: Error code */
   553  ){
   554    int iDot = 0;
   555    int rc = *pRc;
   556    TestDb *pDb;
   557    u8 *abPresent;                  /* Array of boolean */
   558    char *aVal;                     /* Buffer to hold values */
   559    int i;
   560    u32 iSeq = 10;                  /* prng counter */
   561  
   562    abPresent = (u8 *)testMalloc(p->nRange+1);
   563    aVal = (char *)testMalloc(p->nValMax+1);
   564    pDb = testOpen(zSystem, 1, &rc);
   565  
   566    for(i=0; i<p->nIter && rc==0; i++){
   567      int ii;
   568  
   569      testCaseProgress(i, p->nIter, testCaseNDot(), &iDot);
   570  
   571      /* Perform nWrite inserts */
   572      for(ii=0; ii<p->nWrite; ii++){
   573        u8 aKey[6];
   574        u32 iKey;
   575        int nVal;
   576  
   577        iKey = (testPrngValue(iSeq++) % p->nRange) + 1;
   578        nVal = (testPrngValue(iSeq++) % (p->nValMax - p->nValMin)) + p->nValMin;
   579        testPrngString(testPrngValue(iSeq++), aVal, nVal);
   580        dt3PutKey(aKey, iKey);
   581  
   582        testWrite(pDb, aKey, sizeof(aKey)-1, aVal, nVal, &rc);
   583        abPresent[iKey] = 1;
   584      }
   585  
   586      /* Perform nDelete deletes */
   587      for(ii=0; ii<p->nDelete; ii++){
   588        u8 aKey1[6];
   589        u8 aKey2[6];
   590        u32 iKey;
   591  
   592        iKey = (testPrngValue(iSeq++) % p->nRange) + 1;
   593        dt3PutKey(aKey1, iKey-1);
   594        dt3PutKey(aKey2, iKey+1);
   595  
   596        testDeleteRange(pDb, aKey1, sizeof(aKey1)-1, aKey2, sizeof(aKey2)-1, &rc);
   597        abPresent[iKey] = 0;
   598      }
   599  
   600      testReopen(&pDb, &rc);
   601  
   602      for(ii=1; rc==0 && ii<=p->nRange; ii++){
   603        int nDbVal;
   604        void *pDbVal;
   605        u8 aKey[6];
   606        int dbrc;
   607  
   608        dt3PutKey(aKey, ii);
   609        dbrc = tdb_fetch(pDb, aKey, sizeof(aKey)-1, &pDbVal, &nDbVal);
   610        testCompareInt(0, dbrc, &rc);
   611  
   612        if( abPresent[ii] ){
   613          testCompareInt(1, (nDbVal>0), &rc);
   614        }else{
   615          testCompareInt(1, (nDbVal<0), &rc);
   616        }
   617      }
   618    }
   619  
   620    testClose(&pDb);
   621    testCaseFinish(rc);
   622    *pRc = rc;
   623  }
   624  
   625  static char *getName3(const char *zSystem, Datatest3 *p){
   626    return testMallocPrintf("data3.%s.%d.%d.%d.%d.(%d..%d)",
   627        zSystem, p->nRange, p->nIter, p->nWrite, p->nDelete, 
   628        p->nValMin, p->nValMax
   629    );
   630  }
   631  
   632  void test_data_3(
   633    const char *zSystem,            /* Database system name */
   634    const char *zPattern,           /* Run test cases that match this pattern */
   635    int *pRc                        /* IN/OUT: Error code */
   636  ){
   637    Datatest3 aTest[] = {
   638      /* nRange, nIter, nWrite, nDelete, nValMin, nValMax */
   639      {  100,    1000,  5,      5,       50,      100 },
   640      {  100,    1000,  2,      2,        5,       10 },
   641    };
   642  
   643    int i;
   644  
   645    for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
   646      char *zName = getName3(zSystem, &aTest[i]);
   647      if( testCaseBegin(pRc, zPattern, "%s", zName) ){
   648        doDataTest3(zSystem, &aTest[i], pRc);
   649      }
   650      testFree(zName);
   651    }
   652  }
   653  
   654