4 typedef struct OomTest OomTest
;
7 int iNext
; /* Next value to pass to testMallocOom() */
8 int nFail
; /* Number of OOM events injected */
10 int rc
; /* Test case error code */
13 static void testOomStart(OomTest
*p
){
14 memset(p
, 0, sizeof(OomTest
));
18 p
->pEnv
= tdb_lsm_env();
21 static void xOomHook(OomTest
*p
){
25 static int testOomContinue(OomTest
*p
){
26 if( p
->rc
!=0 || (p
->iNext
>1 && p
->nFail
==0) ){
30 testMallocOom(p
->pEnv
, p
->iNext
, 0, (void (*)(void*))xOomHook
, (void *)p
);
34 static void testOomEnable(OomTest
*p
, int bEnable
){
36 testMallocOomEnable(p
->pEnv
, bEnable
);
39 static void testOomNext(OomTest
*p
){
43 static int testOomHit(OomTest
*p
){
47 static int testOomFinish(OomTest
*p
){
51 static void testOomAssert(OomTest
*p
, int bVal
){
59 ** Test that the error code matches the state of the OomTest object passed
60 ** as the first argument. Specifically, check that rc is LSM_NOMEM if an
61 ** OOM error has already been injected, or LSM_OK if not.
63 static void testOomAssertRc(OomTest
*p
, int rc
){
64 testOomAssert(p
, rc
==LSM_OK
|| rc
==LSM_NOMEM
);
65 testOomAssert(p
, testOomHit(p
)==(rc
==LSM_NOMEM
) || p
->bEnable
==0 );
68 static void testOomOpen(
76 rc
= lsm_new(tdb_lsm_env(), ppDb
);
77 if( rc
==LSM_OK
) rc
= lsm_open(*ppDb
, zName
);
78 testOomAssertRc(pOom
, rc
);
83 static void testOomFetch(
90 testOomAssertRc(pOom
, *pRc
);
95 rc
= lsm_csr_open(pDb
, &pCsr
);
96 if( rc
==LSM_OK
) rc
= lsm_csr_seek(pCsr
, pKey
, nKey
, 0);
97 testOomAssertRc(pOom
, rc
);
100 const void *p
; int n
;
101 testOomAssert(pOom
, lsm_csr_valid(pCsr
));
103 rc
= lsm_csr_key(pCsr
, &p
, &n
);
104 testOomAssertRc(pOom
, rc
);
105 testOomAssert(pOom
, rc
!=LSM_OK
|| (n
==nKey
&& memcmp(pKey
, p
, nKey
)==0) );
109 const void *p
; int n
;
110 testOomAssert(pOom
, lsm_csr_valid(pCsr
));
112 rc
= lsm_csr_value(pCsr
, &p
, &n
);
113 testOomAssertRc(pOom
, rc
);
114 testOomAssert(pOom
, rc
!=LSM_OK
|| (n
==nVal
&& memcmp(pVal
, p
, nVal
)==0) );
122 static void testOomWrite(
125 void *pKey
, int nKey
,
126 void *pVal
, int nVal
,
129 testOomAssertRc(pOom
, *pRc
);
133 rc
= lsm_insert(pDb
, pKey
, nKey
, pVal
, nVal
);
134 testOomAssertRc(pOom
, rc
);
141 static void testOomFetchStr(
148 int nKey
= strlen(zKey
);
149 int nVal
= strlen(zVal
);
150 testOomFetch(pOom
, pDb
, (void *)zKey
, nKey
, (void *)zVal
, nVal
, pRc
);
153 static void testOomFetchData(
160 void *pKey
; int nKey
;
161 void *pVal
; int nVal
;
162 testDatasourceEntry(pData
, iKey
, &pKey
, &nKey
, &pVal
, &nVal
);
163 testOomFetch(pOom
, pDb
, pKey
, nKey
, pVal
, nVal
, pRc
);
166 static void testOomWriteStr(
173 int nKey
= strlen(zKey
);
174 int nVal
= strlen(zVal
);
175 testOomWrite(pOom
, pDb
, (void *)zKey
, nKey
, (void *)zVal
, nVal
, pRc
);
178 static void testOomWriteData(
185 void *pKey
; int nKey
;
186 void *pVal
; int nVal
;
187 testDatasourceEntry(pData
, iKey
, &pKey
, &nKey
, &pVal
, &nVal
);
188 testOomWrite(pOom
, pDb
, pKey
, nKey
, pVal
, nVal
, pRc
);
191 static void testOomScan(
195 const void *pKey
, int nKey
,
203 int (*xAdvance
)(lsm_cursor
*) = 0;
206 rc
= lsm_csr_open(pDb
, &pCsr
);
207 testOomAssertRc(pOom
, rc
);
211 rc
= lsm_csr_seek(pCsr
, pKey
, nKey
, LSM_SEEK_LE
);
212 xAdvance
= lsm_csr_prev
;
214 rc
= lsm_csr_seek(pCsr
, pKey
, nKey
, LSM_SEEK_GE
);
215 xAdvance
= lsm_csr_next
;
218 testOomAssertRc(pOom
, rc
);
220 while( rc
==LSM_OK
&& lsm_csr_valid(pCsr
) && iScan
<nScan
){
221 const void *p
; int n
;
223 rc
= lsm_csr_key(pCsr
, &p
, &n
);
224 testOomAssertRc(pOom
, rc
);
226 rc
= lsm_csr_value(pCsr
, &p
, &n
);
227 testOomAssertRc(pOom
, rc
);
231 testOomAssertRc(pOom
, rc
);
241 #define LSMTEST6_TESTDB "testdb.lsm"
243 void testDeleteLsmdb(const char *zFile
){
244 char *zLog
= testMallocPrintf("%s-log", zFile
);
245 char *zShm
= testMallocPrintf("%s-shm", zFile
);
253 static void copy_file(const char *zFrom
, const char *zTo
, int isDatabase
){
255 if( access(zFrom
, F_OK
) ){
265 fd1
= open(zFrom
, O_RDONLY
| _O_BINARY
, 0644);
266 fd2
= open(zTo
, O_RDWR
| O_CREAT
| _O_BINARY
, 0644);
272 aBuf
= testMalloc(4096);
273 for(i
=0; i
<sz
; i
+=4096){
274 int bLockPage
= isDatabase
&& i
== 0;
275 int nByte
= MIN((bLockPage
? 4066 : 4096), sz
- i
);
276 memset(aBuf
, 0, 4096);
277 read(fd1
, aBuf
, nByte
);
278 write(fd2
, aBuf
, nByte
);
280 lseek(fd1
, 4096, SEEK_SET
);
281 lseek(fd2
, 4096, SEEK_SET
);
291 void testCopyLsmdb(const char *zFrom
, const char *zTo
){
292 char *zLog1
= testMallocPrintf("%s-log", zFrom
);
293 char *zLog2
= testMallocPrintf("%s-log", zTo
);
294 char *zShm1
= testMallocPrintf("%s-shm", zFrom
);
295 char *zShm2
= testMallocPrintf("%s-shm", zTo
);
300 copy_file(zFrom
, zTo
, 1);
301 copy_file(zLog1
, zLog2
, 0);
302 copy_file(zShm1
, zShm2
, 0);
304 testFree(zLog1
); testFree(zLog2
); testFree(zShm1
); testFree(zShm2
);
308 ** File zFile is the path to a database. This function makes backups
309 ** of the database file and its log as follows:
311 ** cp $(zFile) $(zFile)-save
312 ** cp $(zFile)-$(zAux) $(zFile)-save-$(zAux)
314 ** Function testRestoreDb() can be used to copy the files back in the
317 void testSaveDb(const char *zFile
, const char *zAux
){
318 char *zLog
= testMallocPrintf("%s-%s", zFile
, zAux
);
319 char *zFileSave
= testMallocPrintf("%s-save", zFile
);
320 char *zLogSave
= testMallocPrintf("%s-%s-save", zFile
, zAux
);
324 copy_file(zFile
, zFileSave
, 1);
325 copy_file(zLog
, zLogSave
, 0);
327 testFree(zLog
); testFree(zFileSave
); testFree(zLogSave
);
331 ** File zFile is the path to a database. This function restores
332 ** a backup of the database made by a previous call to testSaveDb().
333 ** Specifically, it does the equivalent of:
335 ** cp $(zFile)-save $(zFile)
336 ** cp $(zFile)-save-$(zAux) $(zFile)-$(zAux)
338 void testRestoreDb(const char *zFile
, const char *zAux
){
339 char *zLog
= testMallocPrintf("%s-%s", zFile
, zAux
);
340 char *zFileSave
= testMallocPrintf("%s-save", zFile
);
341 char *zLogSave
= testMallocPrintf("%s-%s-save", zFile
, zAux
);
343 copy_file(zFileSave
, zFile
, 1);
344 copy_file(zLogSave
, zLog
, 0);
346 testFree(zLog
); testFree(zFileSave
); testFree(zLogSave
);
350 static int lsmWriteStr(lsm_db
*pDb
, const char *zKey
, const char *zVal
){
351 int nKey
= strlen(zKey
);
352 int nVal
= strlen(zVal
);
353 return lsm_insert(pDb
, (void *)zKey
, nKey
, (void *)zVal
, nVal
);
356 static void setup_delete_db(void){
357 testDeleteLsmdb(LSMTEST6_TESTDB
);
361 ** Create a small database. With the following content:
366 ** "four" -> "sixteen"
367 ** "five" -> "twentyfive"
368 ** "six" -> "thirtysix"
369 ** "seven" -> "fourtynine"
370 ** "eight" -> "sixtyfour"
372 static void setup_populate_db(void){
373 const char *azStr
[] = {
378 "five", "twentyfive",
380 "seven", "fourtynine",
381 "eight", "sixtyfour",
387 testDeleteLsmdb(LSMTEST6_TESTDB
);
389 rc
= lsm_new(tdb_lsm_env(), &pDb
);
390 if( rc
==LSM_OK
) rc
= lsm_open(pDb
, LSMTEST6_TESTDB
);
392 for(ii
=0; rc
==LSM_OK
&& ii
<ArraySize(azStr
); ii
+=2){
393 rc
= lsmWriteStr(pDb
, azStr
[ii
], azStr
[ii
+1]);
397 testSaveDb(LSMTEST6_TESTDB
, "log");
398 assert( rc
==LSM_OK
);
401 static Datasource
*getDatasource(void){
402 const DatasourceDefn defn
= { TEST_DATASOURCE_RANDOM
, 10, 15, 200, 250 };
403 return testDatasourceNew(&defn
);
407 ** Set up a database file with the following properties:
409 ** * Page size is 1024 bytes.
410 ** * Block size is 64 KB.
411 ** * Contains 5000 key-value pairs starting at 0 from the
412 ** datasource returned getDatasource().
414 static void setup_populate_db2(void){
418 int nBlocksize
= 64*1024;
419 int nPagesize
= 1024;
420 int nWritebuffer
= 4*1024;
423 testDeleteLsmdb(LSMTEST6_TESTDB
);
424 rc
= lsm_new(tdb_lsm_env(), &pDb
);
425 if( rc
==LSM_OK
) rc
= lsm_open(pDb
, LSMTEST6_TESTDB
);
427 lsm_config(pDb
, LSM_CONFIG_BLOCK_SIZE
, &nBlocksize
);
428 lsm_config(pDb
, LSM_CONFIG_PAGE_SIZE
, &nPagesize
);
429 lsm_config(pDb
, LSM_CONFIG_AUTOFLUSH
, &nWritebuffer
);
431 pData
= getDatasource();
432 for(ii
=0; rc
==LSM_OK
&& ii
<5000; ii
++){
433 void *pKey
; int nKey
;
434 void *pVal
; int nVal
;
435 testDatasourceEntry(pData
, ii
, &pKey
, &nKey
, &pVal
, &nVal
);
436 lsm_insert(pDb
, pKey
, nKey
, pVal
, nVal
);
438 testDatasourceFree(pData
);
441 testSaveDb(LSMTEST6_TESTDB
, "log");
442 assert( rc
==LSM_OK
);
446 ** Test the results of OOM conditions in lsm_new().
448 static void simple_oom_1(OomTest
*pOom
){
452 rc
= lsm_new(tdb_lsm_env(), &pDb
);
453 testOomAssertRc(pOom
, rc
);
459 ** Test the results of OOM conditions in lsm_open().
461 static void simple_oom_2(OomTest
*pOom
){
465 rc
= lsm_new(tdb_lsm_env(), &pDb
);
467 rc
= lsm_open(pDb
, "testdb.lsm");
469 testOomAssertRc(pOom
, rc
);
475 ** Test the results of OOM conditions in simple fetch operations.
477 static void simple_oom_3(OomTest
*pOom
){
481 testOomOpen(pOom
, LSMTEST6_TESTDB
, &pDb
, &rc
);
483 testOomFetchStr(pOom
, pDb
, "four", "sixteen", &rc
);
484 testOomFetchStr(pOom
, pDb
, "seven", "fourtynine", &rc
);
485 testOomFetchStr(pOom
, pDb
, "one", "one", &rc
);
486 testOomFetchStr(pOom
, pDb
, "eight", "sixtyfour", &rc
);
492 ** Test the results of OOM conditions in simple write operations.
494 static void simple_oom_4(OomTest
*pOom
){
498 testDeleteLsmdb(LSMTEST6_TESTDB
);
499 testOomOpen(pOom
, LSMTEST6_TESTDB
, &pDb
, &rc
);
501 testOomWriteStr(pOom
, pDb
, "123", "onetwothree", &rc
);
502 testOomWriteStr(pOom
, pDb
, "456", "fourfivesix", &rc
);
503 testOomWriteStr(pOom
, pDb
, "789", "seveneightnine", &rc
);
504 testOomWriteStr(pOom
, pDb
, "123", "teneleventwelve", &rc
);
505 testOomWriteStr(pOom
, pDb
, "456", "fourteenfifteensixteen", &rc
);
510 static void simple_oom_5(OomTest
*pOom
){
511 Datasource
*pData
= getDatasource();
515 testRestoreDb(LSMTEST6_TESTDB
, "log");
516 testOomOpen(pOom
, LSMTEST6_TESTDB
, &pDb
, &rc
);
518 testOomFetchData(pOom
, pDb
, pData
, 3333, &rc
);
519 testOomFetchData(pOom
, pDb
, pData
, 0, &rc
);
520 testOomFetchData(pOom
, pDb
, pData
, 4999, &rc
);
523 testDatasourceFree(pData
);
526 static void simple_oom_6(OomTest
*pOom
){
527 Datasource
*pData
= getDatasource();
531 testRestoreDb(LSMTEST6_TESTDB
, "log");
532 testOomOpen(pOom
, LSMTEST6_TESTDB
, &pDb
, &rc
);
534 testOomWriteData(pOom
, pDb
, pData
, 5000, &rc
);
535 testOomWriteData(pOom
, pDb
, pData
, 5001, &rc
);
536 testOomWriteData(pOom
, pDb
, pData
, 5002, &rc
);
537 testOomFetchData(pOom
, pDb
, pData
, 5001, &rc
);
538 testOomFetchData(pOom
, pDb
, pData
, 1234, &rc
);
541 testDatasourceFree(pData
);
544 static void simple_oom_7(OomTest
*pOom
){
545 Datasource
*pData
= getDatasource();
549 testRestoreDb(LSMTEST6_TESTDB
, "log");
550 testOomOpen(pOom
, LSMTEST6_TESTDB
, &pDb
, &rc
);
551 testOomScan(pOom
, pDb
, 0, "abc", 3, 20, &rc
);
553 testDatasourceFree(pData
);
556 static void simple_oom_8(OomTest
*pOom
){
557 Datasource
*pData
= getDatasource();
560 testRestoreDb(LSMTEST6_TESTDB
, "log");
561 testOomOpen(pOom
, LSMTEST6_TESTDB
, &pDb
, &rc
);
562 testOomScan(pOom
, pDb
, 1, "xyz", 3, 20, &rc
);
564 testDatasourceFree(pData
);
568 ** This test case has two clients connected to a database. The first client
569 ** hits an OOM while writing to the database. Check that the second
570 ** connection is still able to query the db following the OOM.
572 static void simple_oom2_1(OomTest
*pOom
){
573 const int nRecord
= 100; /* Number of records initially in db */
574 const int nIns
= 10; /* Number of records inserted with OOM */
576 Datasource
*pData
= getDatasource();
582 testDeleteLsmdb(LSMTEST6_TESTDB
);
584 /* Open the two connections. Initialize the in-memory tree so that it
585 ** contains 100 records. Do all this with OOM injection disabled. */
586 testOomEnable(pOom
, 0);
587 testOomOpen(pOom
, LSMTEST6_TESTDB
, &pDb1
, &rc
);
588 testOomOpen(pOom
, LSMTEST6_TESTDB
, &pDb2
, &rc
);
589 for(i
=0; i
<nRecord
; i
++){
590 testOomWriteData(pOom
, pDb1
, pData
, i
, &rc
);
592 testOomEnable(pOom
, 1);
595 /* Insert 10 more records using pDb1. Stop when an OOM is encountered. */
596 for(i
=nRecord
; i
<nRecord
+nIns
; i
++){
597 testOomWriteData(pOom
, pDb1
, pData
, i
, &rc
);
600 testOomAssertRc(pOom
, rc
);
602 /* Switch off OOM injection. Write a few rows using pDb2. Then check
603 ** that the database may be successfully queried. */
604 testOomEnable(pOom
, 0);
606 for(; i
<nRecord
+nIns
&& rc
==0; i
++){
607 testOomWriteData(pOom
, pDb2
, pData
, i
, &rc
);
609 for(i
=0; i
<nRecord
+nIns
; i
++) testOomFetchData(pOom
, pDb2
, pData
, i
, &rc
);
610 testOomEnable(pOom
, 1);
614 testDatasourceFree(pData
);
618 static void do_test_oom1(const char *zPattern
, int *pRc
){
621 void (*xSetup
)(void);
622 void (*xFunc
)(OomTest
*);
624 { "oom1.lsm.1", setup_delete_db
, simple_oom_1
},
625 { "oom1.lsm.2", setup_delete_db
, simple_oom_2
},
626 { "oom1.lsm.3", setup_populate_db
, simple_oom_3
},
627 { "oom1.lsm.4", setup_delete_db
, simple_oom_4
},
628 { "oom1.lsm.5", setup_populate_db2
, simple_oom_5
},
629 { "oom1.lsm.6", setup_populate_db2
, simple_oom_6
},
630 { "oom1.lsm.7", setup_populate_db2
, simple_oom_7
},
631 { "oom1.lsm.8", setup_populate_db2
, simple_oom_8
},
633 { "oom2.lsm.1", setup_delete_db
, simple_oom2_1
},
637 for(i
=0; i
<ArraySize(aSimple
); i
++){
638 if( *pRc
==0 && testCaseBegin(pRc
, zPattern
, "%s", aSimple
[i
].zName
) ){
641 if( aSimple
[i
].xSetup
){
645 for(testOomStart(&t
); testOomContinue(&t
); testOomNext(&t
)){
646 aSimple
[i
].xFunc(&t
);
649 printf("(%d injections).", t
.iNext
-2);
650 testCaseFinish( (*pRc
= testOomFinish(&t
)) );
651 testMallocOom(tdb_lsm_env(), 0, 0, 0, 0);
657 const char *zPattern
, /* Run test cases that match this pattern */
658 int *pRc
/* IN/OUT: Error code */
660 do_test_oom1(zPattern
, pRc
);