modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/lsm1/lsm-test/lsmtest6.c (about) 1 2 #include "lsmtest.h" 3 4 typedef struct OomTest OomTest; 5 struct OomTest { 6 lsm_env *pEnv; 7 int iNext; /* Next value to pass to testMallocOom() */ 8 int nFail; /* Number of OOM events injected */ 9 int bEnable; 10 int rc; /* Test case error code */ 11 }; 12 13 static void testOomStart(OomTest *p){ 14 memset(p, 0, sizeof(OomTest)); 15 p->iNext = 1; 16 p->bEnable = 1; 17 p->nFail = 1; 18 p->pEnv = tdb_lsm_env(); 19 } 20 21 static void xOomHook(OomTest *p){ 22 p->nFail++; 23 } 24 25 static int testOomContinue(OomTest *p){ 26 if( p->rc!=0 || (p->iNext>1 && p->nFail==0) ){ 27 return 0; 28 } 29 p->nFail = 0; 30 testMallocOom(p->pEnv, p->iNext, 0, (void (*)(void*))xOomHook, (void *)p); 31 return 1; 32 } 33 34 static void testOomEnable(OomTest *p, int bEnable){ 35 p->bEnable = bEnable; 36 testMallocOomEnable(p->pEnv, bEnable); 37 } 38 39 static void testOomNext(OomTest *p){ 40 p->iNext++; 41 } 42 43 static int testOomHit(OomTest *p){ 44 return (p->nFail>0); 45 } 46 47 static int testOomFinish(OomTest *p){ 48 return p->rc; 49 } 50 51 static void testOomAssert(OomTest *p, int bVal){ 52 if( bVal==0 ){ 53 test_failed(); 54 p->rc = 1; 55 } 56 } 57 58 /* 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. 62 */ 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 ); 66 } 67 68 static void testOomOpen( 69 OomTest *pOom, 70 const char *zName, 71 lsm_db **ppDb, 72 int *pRc 73 ){ 74 if( *pRc==LSM_OK ){ 75 int rc; 76 rc = lsm_new(tdb_lsm_env(), ppDb); 77 if( rc==LSM_OK ) rc = lsm_open(*ppDb, zName); 78 testOomAssertRc(pOom, rc); 79 *pRc = rc; 80 } 81 } 82 83 static void testOomFetch( 84 OomTest *pOom, 85 lsm_db *pDb, 86 void *pKey, int nKey, 87 void *pVal, int nVal, 88 int *pRc 89 ){ 90 testOomAssertRc(pOom, *pRc); 91 if( *pRc==LSM_OK ){ 92 lsm_cursor *pCsr; 93 int rc; 94 95 rc = lsm_csr_open(pDb, &pCsr); 96 if( rc==LSM_OK ) rc = lsm_csr_seek(pCsr, pKey, nKey, 0); 97 testOomAssertRc(pOom, rc); 98 99 if( rc==LSM_OK ){ 100 const void *p; int n; 101 testOomAssert(pOom, lsm_csr_valid(pCsr)); 102 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) ); 106 } 107 108 if( rc==LSM_OK ){ 109 const void *p; int n; 110 testOomAssert(pOom, lsm_csr_valid(pCsr)); 111 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) ); 115 } 116 117 lsm_csr_close(pCsr); 118 *pRc = rc; 119 } 120 } 121 122 static void testOomWrite( 123 OomTest *pOom, 124 lsm_db *pDb, 125 void *pKey, int nKey, 126 void *pVal, int nVal, 127 int *pRc 128 ){ 129 testOomAssertRc(pOom, *pRc); 130 if( *pRc==LSM_OK ){ 131 int rc; 132 133 rc = lsm_insert(pDb, pKey, nKey, pVal, nVal); 134 testOomAssertRc(pOom, rc); 135 136 *pRc = rc; 137 } 138 } 139 140 141 static void testOomFetchStr( 142 OomTest *pOom, 143 lsm_db *pDb, 144 const char *zKey, 145 const char *zVal, 146 int *pRc 147 ){ 148 int nKey = strlen(zKey); 149 int nVal = strlen(zVal); 150 testOomFetch(pOom, pDb, (void *)zKey, nKey, (void *)zVal, nVal, pRc); 151 } 152 153 static void testOomFetchData( 154 OomTest *pOom, 155 lsm_db *pDb, 156 Datasource *pData, 157 int iKey, 158 int *pRc 159 ){ 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); 164 } 165 166 static void testOomWriteStr( 167 OomTest *pOom, 168 lsm_db *pDb, 169 const char *zKey, 170 const char *zVal, 171 int *pRc 172 ){ 173 int nKey = strlen(zKey); 174 int nVal = strlen(zVal); 175 testOomWrite(pOom, pDb, (void *)zKey, nKey, (void *)zVal, nVal, pRc); 176 } 177 178 static void testOomWriteData( 179 OomTest *pOom, 180 lsm_db *pDb, 181 Datasource *pData, 182 int iKey, 183 int *pRc 184 ){ 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); 189 } 190 191 static void testOomScan( 192 OomTest *pOom, 193 lsm_db *pDb, 194 int bReverse, 195 const void *pKey, int nKey, 196 int nScan, 197 int *pRc 198 ){ 199 if( *pRc==0 ){ 200 int rc; 201 int iScan = 0; 202 lsm_cursor *pCsr; 203 int (*xAdvance)(lsm_cursor *) = 0; 204 205 206 rc = lsm_csr_open(pDb, &pCsr); 207 testOomAssertRc(pOom, rc); 208 209 if( rc==LSM_OK ){ 210 if( bReverse ){ 211 rc = lsm_csr_seek(pCsr, pKey, nKey, LSM_SEEK_LE); 212 xAdvance = lsm_csr_prev; 213 }else{ 214 rc = lsm_csr_seek(pCsr, pKey, nKey, LSM_SEEK_GE); 215 xAdvance = lsm_csr_next; 216 } 217 } 218 testOomAssertRc(pOom, rc); 219 220 while( rc==LSM_OK && lsm_csr_valid(pCsr) && iScan<nScan ){ 221 const void *p; int n; 222 223 rc = lsm_csr_key(pCsr, &p, &n); 224 testOomAssertRc(pOom, rc); 225 if( rc==LSM_OK ){ 226 rc = lsm_csr_value(pCsr, &p, &n); 227 testOomAssertRc(pOom, rc); 228 } 229 if( rc==LSM_OK ){ 230 rc = xAdvance(pCsr); 231 testOomAssertRc(pOom, rc); 232 } 233 iScan++; 234 } 235 236 lsm_csr_close(pCsr); 237 *pRc = rc; 238 } 239 } 240 241 #define LSMTEST6_TESTDB "testdb.lsm" 242 243 void testDeleteLsmdb(const char *zFile){ 244 char *zLog = testMallocPrintf("%s-log", zFile); 245 char *zShm = testMallocPrintf("%s-shm", zFile); 246 unlink(zFile); 247 unlink(zLog); 248 unlink(zShm); 249 testFree(zLog); 250 testFree(zShm); 251 } 252 253 static void copy_file(const char *zFrom, const char *zTo, int isDatabase){ 254 255 if( access(zFrom, F_OK) ){ 256 unlink(zTo); 257 }else{ 258 int fd1; 259 int fd2; 260 off_t sz; 261 off_t i; 262 struct stat buf; 263 u8 *aBuf; 264 265 fd1 = open(zFrom, O_RDONLY | _O_BINARY, 0644); 266 fd2 = open(zTo, O_RDWR | O_CREAT | _O_BINARY, 0644); 267 268 fstat(fd1, &buf); 269 sz = buf.st_size; 270 ftruncate(fd2, sz); 271 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); 279 if( bLockPage ){ 280 lseek(fd1, 4096, SEEK_SET); 281 lseek(fd2, 4096, SEEK_SET); 282 } 283 } 284 testFree(aBuf); 285 286 close(fd1); 287 close(fd2); 288 } 289 } 290 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); 296 297 unlink(zShm2); 298 unlink(zLog2); 299 unlink(zTo); 300 copy_file(zFrom, zTo, 1); 301 copy_file(zLog1, zLog2, 0); 302 copy_file(zShm1, zShm2, 0); 303 304 testFree(zLog1); testFree(zLog2); testFree(zShm1); testFree(zShm2); 305 } 306 307 /* 308 ** File zFile is the path to a database. This function makes backups 309 ** of the database file and its log as follows: 310 ** 311 ** cp $(zFile) $(zFile)-save 312 ** cp $(zFile)-$(zAux) $(zFile)-save-$(zAux) 313 ** 314 ** Function testRestoreDb() can be used to copy the files back in the 315 ** other direction. 316 */ 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); 321 322 unlink(zFileSave); 323 unlink(zLogSave); 324 copy_file(zFile, zFileSave, 1); 325 copy_file(zLog, zLogSave, 0); 326 327 testFree(zLog); testFree(zFileSave); testFree(zLogSave); 328 } 329 330 /* 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: 334 ** 335 ** cp $(zFile)-save $(zFile) 336 ** cp $(zFile)-save-$(zAux) $(zFile)-$(zAux) 337 */ 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); 342 343 copy_file(zFileSave, zFile, 1); 344 copy_file(zLogSave, zLog, 0); 345 346 testFree(zLog); testFree(zFileSave); testFree(zLogSave); 347 } 348 349 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); 354 } 355 356 static void setup_delete_db(void){ 357 testDeleteLsmdb(LSMTEST6_TESTDB); 358 } 359 360 /* 361 ** Create a small database. With the following content: 362 ** 363 ** "one" -> "one" 364 ** "two" -> "four" 365 ** "three" -> "nine" 366 ** "four" -> "sixteen" 367 ** "five" -> "twentyfive" 368 ** "six" -> "thirtysix" 369 ** "seven" -> "fourtynine" 370 ** "eight" -> "sixtyfour" 371 */ 372 static void setup_populate_db(void){ 373 const char *azStr[] = { 374 "one", "one", 375 "two", "four", 376 "three", "nine", 377 "four", "sixteen", 378 "five", "twentyfive", 379 "six", "thirtysix", 380 "seven", "fourtynine", 381 "eight", "sixtyfour", 382 }; 383 int rc; 384 int ii; 385 lsm_db *pDb; 386 387 testDeleteLsmdb(LSMTEST6_TESTDB); 388 389 rc = lsm_new(tdb_lsm_env(), &pDb); 390 if( rc==LSM_OK ) rc = lsm_open(pDb, LSMTEST6_TESTDB); 391 392 for(ii=0; rc==LSM_OK && ii<ArraySize(azStr); ii+=2){ 393 rc = lsmWriteStr(pDb, azStr[ii], azStr[ii+1]); 394 } 395 lsm_close(pDb); 396 397 testSaveDb(LSMTEST6_TESTDB, "log"); 398 assert( rc==LSM_OK ); 399 } 400 401 static Datasource *getDatasource(void){ 402 const DatasourceDefn defn = { TEST_DATASOURCE_RANDOM, 10, 15, 200, 250 }; 403 return testDatasourceNew(&defn); 404 } 405 406 /* 407 ** Set up a database file with the following properties: 408 ** 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(). 413 */ 414 static void setup_populate_db2(void){ 415 Datasource *pData; 416 int ii; 417 int rc; 418 int nBlocksize = 64*1024; 419 int nPagesize = 1024; 420 int nWritebuffer = 4*1024; 421 lsm_db *pDb; 422 423 testDeleteLsmdb(LSMTEST6_TESTDB); 424 rc = lsm_new(tdb_lsm_env(), &pDb); 425 if( rc==LSM_OK ) rc = lsm_open(pDb, LSMTEST6_TESTDB); 426 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); 430 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); 437 } 438 testDatasourceFree(pData); 439 lsm_close(pDb); 440 441 testSaveDb(LSMTEST6_TESTDB, "log"); 442 assert( rc==LSM_OK ); 443 } 444 445 /* 446 ** Test the results of OOM conditions in lsm_new(). 447 */ 448 static void simple_oom_1(OomTest *pOom){ 449 int rc; 450 lsm_db *pDb; 451 452 rc = lsm_new(tdb_lsm_env(), &pDb); 453 testOomAssertRc(pOom, rc); 454 455 lsm_close(pDb); 456 } 457 458 /* 459 ** Test the results of OOM conditions in lsm_open(). 460 */ 461 static void simple_oom_2(OomTest *pOom){ 462 int rc; 463 lsm_db *pDb; 464 465 rc = lsm_new(tdb_lsm_env(), &pDb); 466 if( rc==LSM_OK ){ 467 rc = lsm_open(pDb, "testdb.lsm"); 468 } 469 testOomAssertRc(pOom, rc); 470 471 lsm_close(pDb); 472 } 473 474 /* 475 ** Test the results of OOM conditions in simple fetch operations. 476 */ 477 static void simple_oom_3(OomTest *pOom){ 478 int rc = LSM_OK; 479 lsm_db *pDb; 480 481 testOomOpen(pOom, LSMTEST6_TESTDB, &pDb, &rc); 482 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); 487 488 lsm_close(pDb); 489 } 490 491 /* 492 ** Test the results of OOM conditions in simple write operations. 493 */ 494 static void simple_oom_4(OomTest *pOom){ 495 int rc = LSM_OK; 496 lsm_db *pDb; 497 498 testDeleteLsmdb(LSMTEST6_TESTDB); 499 testOomOpen(pOom, LSMTEST6_TESTDB, &pDb, &rc); 500 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); 506 507 lsm_close(pDb); 508 } 509 510 static void simple_oom_5(OomTest *pOom){ 511 Datasource *pData = getDatasource(); 512 int rc = LSM_OK; 513 lsm_db *pDb; 514 515 testRestoreDb(LSMTEST6_TESTDB, "log"); 516 testOomOpen(pOom, LSMTEST6_TESTDB, &pDb, &rc); 517 518 testOomFetchData(pOom, pDb, pData, 3333, &rc); 519 testOomFetchData(pOom, pDb, pData, 0, &rc); 520 testOomFetchData(pOom, pDb, pData, 4999, &rc); 521 522 lsm_close(pDb); 523 testDatasourceFree(pData); 524 } 525 526 static void simple_oom_6(OomTest *pOom){ 527 Datasource *pData = getDatasource(); 528 int rc = LSM_OK; 529 lsm_db *pDb; 530 531 testRestoreDb(LSMTEST6_TESTDB, "log"); 532 testOomOpen(pOom, LSMTEST6_TESTDB, &pDb, &rc); 533 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); 539 540 lsm_close(pDb); 541 testDatasourceFree(pData); 542 } 543 544 static void simple_oom_7(OomTest *pOom){ 545 Datasource *pData = getDatasource(); 546 int rc = LSM_OK; 547 lsm_db *pDb; 548 549 testRestoreDb(LSMTEST6_TESTDB, "log"); 550 testOomOpen(pOom, LSMTEST6_TESTDB, &pDb, &rc); 551 testOomScan(pOom, pDb, 0, "abc", 3, 20, &rc); 552 lsm_close(pDb); 553 testDatasourceFree(pData); 554 } 555 556 static void simple_oom_8(OomTest *pOom){ 557 Datasource *pData = getDatasource(); 558 int rc = LSM_OK; 559 lsm_db *pDb; 560 testRestoreDb(LSMTEST6_TESTDB, "log"); 561 testOomOpen(pOom, LSMTEST6_TESTDB, &pDb, &rc); 562 testOomScan(pOom, pDb, 1, "xyz", 3, 20, &rc); 563 lsm_close(pDb); 564 testDatasourceFree(pData); 565 } 566 567 /* 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. 571 */ 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 */ 575 576 Datasource *pData = getDatasource(); 577 int rc = LSM_OK; 578 lsm_db *pDb1; 579 lsm_db *pDb2; 580 int i; 581 582 testDeleteLsmdb(LSMTEST6_TESTDB); 583 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); 591 } 592 testOomEnable(pOom, 1); 593 assert( rc==0 ); 594 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); 598 if( rc ) break; 599 } 600 testOomAssertRc(pOom, rc); 601 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); 605 rc = 0; 606 for(; i<nRecord+nIns && rc==0; i++){ 607 testOomWriteData(pOom, pDb2, pData, i, &rc); 608 } 609 for(i=0; i<nRecord+nIns; i++) testOomFetchData(pOom, pDb2, pData, i, &rc); 610 testOomEnable(pOom, 1); 611 612 lsm_close(pDb1); 613 lsm_close(pDb2); 614 testDatasourceFree(pData); 615 } 616 617 618 static void do_test_oom1(const char *zPattern, int *pRc){ 619 struct SimpleOom { 620 const char *zName; 621 void (*xSetup)(void); 622 void (*xFunc)(OomTest *); 623 } aSimple[] = { 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 }, 632 633 { "oom2.lsm.1", setup_delete_db, simple_oom2_1 }, 634 }; 635 int i; 636 637 for(i=0; i<ArraySize(aSimple); i++){ 638 if( *pRc==0 && testCaseBegin(pRc, zPattern, "%s", aSimple[i].zName) ){ 639 OomTest t; 640 641 if( aSimple[i].xSetup ){ 642 aSimple[i].xSetup(); 643 } 644 645 for(testOomStart(&t); testOomContinue(&t); testOomNext(&t)){ 646 aSimple[i].xFunc(&t); 647 } 648 649 printf("(%d injections).", t.iNext-2); 650 testCaseFinish( (*pRc = testOomFinish(&t)) ); 651 testMallocOom(tdb_lsm_env(), 0, 0, 0, 0); 652 } 653 } 654 } 655 656 void test_oom( 657 const char *zPattern, /* Run test cases that match this pattern */ 658 int *pRc /* IN/OUT: Error code */ 659 ){ 660 do_test_oom1(zPattern, pRc); 661 }