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