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 */
getName(const char * zSystem,int bRecover,Datatest1 * pTest)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 
testControlDb(TestDb ** ppDb)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 
testDatasourceFetch(TestDb * pDb,Datasource * pData,int iKey,int * pRc)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 */
testDbContents(TestDb * pDb,Datasource * pData,int nRow,int iFirst,int iLast,int nLookupTest,int nScanTest,int * pRc)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 */
testCaseProgress(int i,int n,int nDot,int * piDot)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 
testCaseNDot(void)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 
testReopenRecover(TestDb ** ppDb,int * pRc)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 
doDataTest1(const char * zSystem,int bRecover,Datatest1 * p,int * pRc)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   int iToggle = 0;
278 
279   /* Start the test case, open a database and allocate the datasource. */
280   pDb = testOpen(zSystem, 1, &rc);
281   pData = testDatasourceNew(&p->defn);
282 
283   i = 0;
284   iDot = 0;
285   while( rc==LSM_OK && i<p->nRow ){
286 
287     /* Insert some data */
288     testWriteDatasourceRange(pDb, pData, i, p->nVerify, &rc);
289     i += p->nVerify;
290 
291     if( iToggle ) testBegin(pDb, 1, &rc);
292     /* Check that the db content is correct. */
293     testDbContents(pDb, pData, p->nRow, 0, i-1, p->nTest, p->bTestScan, &rc);
294     if( iToggle ) testCommit(pDb, 0, &rc);
295     iToggle = (iToggle+1)%2;
296 
297     if( bRecover ){
298       testReopenRecover(&pDb, &rc);
299     }else{
300       testReopen(&pDb, &rc);
301     }
302 
303     /* Check that the db content is still correct. */
304     testDbContents(pDb, pData, p->nRow, 0, i-1, p->nTest, p->bTestScan, &rc);
305 
306     /* Update the progress dots... */
307     testCaseProgress(i, p->nRow, testCaseNDot()/2, &iDot);
308   }
309 
310   i = 0;
311   iDot = 0;
312   while( rc==LSM_OK && i<p->nRow ){
313 
314     /* Delete some entries */
315     testDeleteDatasourceRange(pDb, pData, i, p->nVerify, &rc);
316     i += p->nVerify;
317 
318     /* Check that the db content is correct. */
319     testDbContents(pDb, pData, p->nRow, i, p->nRow-1,p->nTest,p->bTestScan,&rc);
320 
321     /* Close and reopen the database. */
322     if( bRecover ){
323       testReopenRecover(&pDb, &rc);
324     }else{
325       testReopen(&pDb, &rc);
326     }
327 
328     /* Check that the db content is still correct. */
329     testDbContents(pDb, pData, p->nRow, i, p->nRow-1,p->nTest,p->bTestScan,&rc);
330 
331     /* Update the progress dots... */
332     testCaseProgress(i, p->nRow, testCaseNDot()/2, &iDot);
333   }
334 
335   /* Free the datasource, close the database and finish the test case. */
336   testDatasourceFree(pData);
337   tdb_close(pDb);
338   testCaseFinish(rc);
339   *pRc = rc;
340 }
341 
342 
test_data_1(const char * zSystem,const char * zPattern,int * pRc)343 void test_data_1(
344   const char *zSystem,            /* Database system name */
345   const char *zPattern,           /* Run test cases that match this pattern */
346   int *pRc                        /* IN/OUT: Error code */
347 ){
348   Datatest1 aTest[] = {
349     { {DATA_RANDOM,     500,600,   1000,2000},     1000,  100,  10,  0},
350     { {DATA_RANDOM,     20,25,     100,200},       1000,  250, 1000, 1},
351     { {DATA_RANDOM,     8,10,      100,200},       1000,  250, 1000, 1},
352     { {DATA_RANDOM,     8,10,      10,20},         1000,  250, 1000, 1},
353     { {DATA_RANDOM,     8,10,      1000,2000},     1000,  250, 1000, 1},
354     { {DATA_RANDOM,     8,100,     10000,20000},    100,   25,  100, 1},
355     { {DATA_RANDOM,     80,100,    10,20},         1000,  250, 1000, 1},
356     { {DATA_RANDOM,     5000,6000, 10,20},          100,   25,  100, 1},
357     { {DATA_SEQUENTIAL, 5,10,      10,20},         1000,  250, 1000, 1},
358     { {DATA_SEQUENTIAL, 5,10,      100,200},       1000,  250, 1000, 1},
359     { {DATA_SEQUENTIAL, 5,10,      1000,2000},     1000,  250, 1000, 1},
360     { {DATA_SEQUENTIAL, 5,100,     10000,20000},    100,   25,  100, 1},
361     { {DATA_RANDOM,     10,10,     100,100},     100000, 1000,  100, 0},
362     { {DATA_SEQUENTIAL, 10,10,     100,100},     100000, 1000,  100, 0},
363   };
364 
365   int i;
366   int bRecover;
367 
368   for(bRecover=0; bRecover<2; bRecover++){
369     if( bRecover==1 && memcmp(zSystem, "lsm", 3) ) break;
370     for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
371       char *zName = getName(zSystem, bRecover, &aTest[i]);
372       if( testCaseBegin(pRc, zPattern, "%s", zName) ){
373         doDataTest1(zSystem, bRecover, &aTest[i], pRc);
374       }
375       testFree(zName);
376     }
377   }
378 }
379 
testCompareDb(Datasource * pData,int nData,int iSeed,TestDb * pControl,TestDb * pDb,int * pRc)380 void testCompareDb(
381   Datasource *pData,
382   int nData,
383   int iSeed,
384   TestDb *pControl,
385   TestDb *pDb,
386   int *pRc
387 ){
388   int i;
389 
390   static int nCall = 0;
391   nCall++;
392 
393   testScanCompare(pControl, pDb, 0, 0, 0,         0, 0,         pRc);
394   testScanCompare(pControl, pDb, 1, 0, 0,         0, 0,         pRc);
395 
396   if( *pRc==0 ){
397     int iKey1;
398     int iKey2;
399     void *pKey1; int nKey1;       /* Start key */
400     void *pKey2; int nKey2;       /* Final key */
401 
402     iKey1 = testPrngValue(iSeed) % nData;
403     iKey2 = testPrngValue(iSeed+1) % nData;
404     testDatasourceEntry(pData, iKey1, &pKey2, &nKey1, 0, 0);
405     pKey1 = testMalloc(nKey1+1);
406     memcpy(pKey1, pKey2, nKey1+1);
407     testDatasourceEntry(pData, iKey2, &pKey2, &nKey2, 0, 0);
408 
409     testScanCompare(pControl, pDb, 0, 0, 0,         pKey2, nKey2, pRc);
410     testScanCompare(pControl, pDb, 0, pKey1, nKey1, 0, 0,         pRc);
411     testScanCompare(pControl, pDb, 0, pKey1, nKey1, pKey2, nKey2, pRc);
412     testScanCompare(pControl, pDb, 1, 0, 0,         pKey2, nKey2, pRc);
413     testScanCompare(pControl, pDb, 1, pKey1, nKey1, 0, 0,         pRc);
414     testScanCompare(pControl, pDb, 1, pKey1, nKey1, pKey2, nKey2, pRc);
415     testFree(pKey1);
416   }
417 
418   for(i=0; i<nData && *pRc==0; i++){
419     void *pKey; int nKey;
420     testDatasourceEntry(pData, i, &pKey, &nKey, 0, 0);
421     testFetchCompare(pControl, pDb, pKey, nKey, pRc);
422   }
423 }
424 
doDataTest2(const char * zSystem,int bRecover,Datatest2 * p,int * pRc)425 static void doDataTest2(
426   const char *zSystem,            /* Database system to test */
427   int bRecover,
428   Datatest2 *p,                   /* Structure containing test parameters */
429   int *pRc                        /* OUT: Error code */
430 ){
431   TestDb *pDb;
432   TestDb *pControl;
433   Datasource *pData;
434   int i;
435   int rc = LSM_OK;
436   int iDot = 0;
437 
438   /* Start the test case, open a database and allocate the datasource. */
439   pDb = testOpen(zSystem, 1, &rc);
440   pData = testDatasourceNew(&p->defn);
441   rc = testControlDb(&pControl);
442 
443   if( tdb_lsm(pDb) ){
444     int nBuf = 32 * 1024 * 1024;
445     lsm_config(tdb_lsm(pDb), LSM_CONFIG_AUTOFLUSH, &nBuf);
446   }
447 
448   for(i=0; rc==0 && i<p->nIter; i++){
449     void *pKey1; int nKey1;
450     void *pKey2; int nKey2;
451     int ii;
452     int nRange = MIN(p->nIter*p->nWrite, p->nRange);
453 
454     for(ii=0; rc==0 && ii<p->nWrite; ii++){
455       int iKey = (i*p->nWrite + ii) % p->nRange;
456       testWriteDatasource(pControl, pData, iKey, &rc);
457       testWriteDatasource(pDb, pData, iKey, &rc);
458     }
459 
460     testDatasourceEntry(pData, i+1000000, &pKey1, &nKey1, 0, 0);
461     pKey1 = testMallocCopy(pKey1, nKey1);
462     testDatasourceEntry(pData, i+2000000, &pKey2, &nKey2, 0, 0);
463 
464     testDeleteRange(pDb, pKey1, nKey1, pKey2, nKey2, &rc);
465     testDeleteRange(pControl, pKey1, nKey1, pKey2, nKey2, &rc);
466     testFree(pKey1);
467 
468     testCompareDb(pData, nRange, i, pControl, pDb, &rc);
469     if( bRecover ){
470       testReopenRecover(&pDb, &rc);
471     }else{
472       testReopen(&pDb, &rc);
473     }
474     testCompareDb(pData, nRange, i, pControl, pDb, &rc);
475 
476     /* Update the progress dots... */
477     testCaseProgress(i, p->nIter, testCaseNDot(), &iDot);
478   }
479 
480   testClose(&pDb);
481   testClose(&pControl);
482   testDatasourceFree(pData);
483   testCaseFinish(rc);
484   *pRc = rc;
485 }
486 
getName2(const char * zSystem,int bRecover,Datatest2 * pTest)487 static char *getName2(const char *zSystem, int bRecover, Datatest2 *pTest){
488   char *zRet;
489   char *zData;
490   zData = testDatasourceName(&pTest->defn);
491   zRet = testMallocPrintf("data2.%s.%s.rec=%d.%d.%d.%d",
492       zSystem, zData, bRecover, pTest->nRange, pTest->nWrite, pTest->nIter
493   );
494   testFree(zData);
495   return zRet;
496 }
497 
test_data_2(const char * zSystem,const char * zPattern,int * pRc)498 void test_data_2(
499   const char *zSystem,            /* Database system name */
500   const char *zPattern,           /* Run test cases that match this pattern */
501   int *pRc                        /* IN/OUT: Error code */
502 ){
503   Datatest2 aTest[] = {
504       /* defn,                                 nRange, nWrite, nIter */
505     { {DATA_RANDOM,     20,25,     100,200},   10000,  10,     50   },
506     { {DATA_RANDOM,     20,25,     100,200},   10000,  200,    50   },
507     { {DATA_RANDOM,     20,25,     100,200},   100,    10,     1000 },
508     { {DATA_RANDOM,     20,25,     100,200},   100,    200,    50   },
509   };
510 
511   int i;
512   int bRecover;
513 
514   for(bRecover=0; bRecover<2; bRecover++){
515     if( bRecover==1 && memcmp(zSystem, "lsm", 3) ) break;
516     for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
517       char *zName = getName2(zSystem, bRecover, &aTest[i]);
518       if( testCaseBegin(pRc, zPattern, "%s", zName) ){
519         doDataTest2(zSystem, bRecover, &aTest[i], pRc);
520       }
521       testFree(zName);
522     }
523   }
524 }
525 
526 /*************************************************************************
527 ** Test case data3.*
528 */
529 
530 typedef struct Datatest3 Datatest3;
531 struct Datatest3 {
532   int nRange;                     /* Keys are between 1 and this value, incl. */
533   int nIter;                      /* Number of iterations */
534   int nWrite;                     /* Number of writes per iteration */
535   int nDelete;                    /* Number of deletes per iteration */
536 
537   int nValMin;                    /* Minimum value size for writes */
538   int nValMax;                    /* Maximum value size for writes */
539 };
540 
testPutU32(u8 * aBuf,u32 iVal)541 void testPutU32(u8 *aBuf, u32 iVal){
542   aBuf[0] = (iVal >> 24) & 0xFF;
543   aBuf[1] = (iVal >> 16) & 0xFF;
544   aBuf[2] = (iVal >>  8) & 0xFF;
545   aBuf[3] = (iVal >>  0) & 0xFF;
546 }
547 
dt3PutKey(u8 * aBuf,int iKey)548 void dt3PutKey(u8 *aBuf, int iKey){
549   assert( iKey<100000 && iKey>=0 );
550   sprintf((char *)aBuf, "%.5d", iKey);
551 }
552 
doDataTest3(const char * zSystem,Datatest3 * p,int * pRc)553 static void doDataTest3(
554   const char *zSystem,            /* Database system to test */
555   Datatest3 *p,                   /* Structure containing test parameters */
556   int *pRc                        /* OUT: Error code */
557 ){
558   int iDot = 0;
559   int rc = *pRc;
560   TestDb *pDb;
561   u8 *abPresent;                  /* Array of boolean */
562   char *aVal;                     /* Buffer to hold values */
563   int i;
564   u32 iSeq = 10;                  /* prng counter */
565 
566   abPresent = (u8 *)testMalloc(p->nRange+1);
567   aVal = (char *)testMalloc(p->nValMax+1);
568   pDb = testOpen(zSystem, 1, &rc);
569 
570   for(i=0; i<p->nIter && rc==0; i++){
571     int ii;
572 
573     testCaseProgress(i, p->nIter, testCaseNDot(), &iDot);
574 
575     /* Perform nWrite inserts */
576     for(ii=0; ii<p->nWrite; ii++){
577       u8 aKey[6];
578       u32 iKey;
579       int nVal;
580 
581       iKey = (testPrngValue(iSeq++) % p->nRange) + 1;
582       nVal = (testPrngValue(iSeq++) % (p->nValMax - p->nValMin)) + p->nValMin;
583       testPrngString(testPrngValue(iSeq++), aVal, nVal);
584       dt3PutKey(aKey, iKey);
585 
586       testWrite(pDb, aKey, sizeof(aKey)-1, aVal, nVal, &rc);
587       abPresent[iKey] = 1;
588     }
589 
590     /* Perform nDelete deletes */
591     for(ii=0; ii<p->nDelete; ii++){
592       u8 aKey1[6];
593       u8 aKey2[6];
594       u32 iKey;
595 
596       iKey = (testPrngValue(iSeq++) % p->nRange) + 1;
597       dt3PutKey(aKey1, iKey-1);
598       dt3PutKey(aKey2, iKey+1);
599 
600       testDeleteRange(pDb, aKey1, sizeof(aKey1)-1, aKey2, sizeof(aKey2)-1, &rc);
601       abPresent[iKey] = 0;
602     }
603 
604     testReopen(&pDb, &rc);
605 
606     for(ii=1; rc==0 && ii<=p->nRange; ii++){
607       int nDbVal;
608       void *pDbVal;
609       u8 aKey[6];
610       int dbrc;
611 
612       dt3PutKey(aKey, ii);
613       dbrc = tdb_fetch(pDb, aKey, sizeof(aKey)-1, &pDbVal, &nDbVal);
614       testCompareInt(0, dbrc, &rc);
615 
616       if( abPresent[ii] ){
617         testCompareInt(1, (nDbVal>0), &rc);
618       }else{
619         testCompareInt(1, (nDbVal<0), &rc);
620       }
621     }
622   }
623 
624   testClose(&pDb);
625   testCaseFinish(rc);
626   *pRc = rc;
627 }
628 
getName3(const char * zSystem,Datatest3 * p)629 static char *getName3(const char *zSystem, Datatest3 *p){
630   return testMallocPrintf("data3.%s.%d.%d.%d.%d.(%d..%d)",
631       zSystem, p->nRange, p->nIter, p->nWrite, p->nDelete,
632       p->nValMin, p->nValMax
633   );
634 }
635 
test_data_3(const char * zSystem,const char * zPattern,int * pRc)636 void test_data_3(
637   const char *zSystem,            /* Database system name */
638   const char *zPattern,           /* Run test cases that match this pattern */
639   int *pRc                        /* IN/OUT: Error code */
640 ){
641   Datatest3 aTest[] = {
642     /* nRange, nIter, nWrite, nDelete, nValMin, nValMax */
643     {  100,    1000,  5,      5,       50,      100 },
644     {  100,    1000,  2,      2,        5,       10 },
645   };
646 
647   int i;
648 
649   for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
650     char *zName = getName3(zSystem, &aTest[i]);
651     if( testCaseBegin(pRc, zPattern, "%s", zName) ){
652       doDataTest3(zSystem, &aTest[i], pRc);
653     }
654     testFree(zName);
655   }
656 }
657