lots.c (13415B)
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* use sequental numbers printed to strings 7 * to store lots and lots of entries in the 8 * database. 9 * 10 * Start with 100 entries, put them and then 11 * read them out. Then delete the first 12 * half and verify that all of the first half 13 * is gone and then verify that the second 14 * half is still there. 15 * Then add the first half back and verify 16 * again. Then delete the middle third 17 * and verify again. 18 * Then increase the size by 1000 and do 19 * the whole add delete thing again. 20 * 21 * The data for each object is the number string translated 22 * to hex and replicated a random number of times. The 23 * number of times that the data is replicated is the first 24 * int32 in the data. 25 */ 26 27 #include <stdio.h> 28 29 #include <stdlib.h> 30 #ifdef STDC_HEADERS 31 #include <stdarg.h> 32 #else 33 #include <varargs.h> 34 #endif 35 36 #ifdef HAVE_MEMORY_H 37 #include <memory.h> 38 #endif 39 #include <string.h> 40 #include <assert.h> 41 #include "mcom_db.h" 42 43 DB *database = 0; 44 int MsgPriority = 5; 45 46 #if defined(_WINDOWS) && !defined(WIN32) 47 #define int32 long 48 #define uint32 unsigned long 49 #else 50 #define int32 int 51 #define uint32 unsigned int 52 #endif 53 54 typedef enum { 55 USE_LARGE_KEY, 56 USE_SMALL_KEY 57 } key_type_enum; 58 59 #define TraceMe(priority, msg) \ 60 do { \ 61 if (priority <= MsgPriority) { \ 62 ReportStatus msg; \ 63 } \ 64 } while (0) 65 66 int 67 ReportStatus(char *string, ...) 68 { 69 va_list args; 70 71 #ifdef STDC_HEADERS 72 va_start(args, string); 73 #else 74 va_start(args); 75 #endif 76 vfprintf(stderr, string, args); 77 va_end(args); 78 79 fprintf(stderr, "\n"); 80 81 return (0); 82 } 83 84 int 85 ReportError(char *string, ...) 86 { 87 va_list args; 88 89 #ifdef STDC_HEADERS 90 va_start(args, string); 91 #else 92 va_start(args); 93 #endif 94 fprintf(stderr, "\n "); 95 vfprintf(stderr, string, args); 96 fprintf(stderr, "\n"); 97 va_end(args); 98 99 return (0); 100 } 101 102 DBT * 103 MakeLargeKey(int32 num) 104 { 105 int32 low_bits; 106 static DBT rv; 107 static char *string_rv = 0; 108 int rep_char; 109 size_t size; 110 111 if (string_rv) 112 free(string_rv); 113 114 /* generate a really large text key derived from 115 * an int32 116 */ 117 low_bits = (num % 10000) + 1; 118 119 /* get the repeat char from the low 26 */ 120 rep_char = (char)((low_bits % 26) + 'a'); 121 122 /* malloc a string low_bits wide */ 123 size = low_bits * sizeof(char); 124 string_rv = (char *)malloc(size); 125 126 memset(string_rv, rep_char, size); 127 128 rv.data = string_rv; 129 rv.size = size; 130 131 return (&rv); 132 } 133 134 DBT * 135 MakeSmallKey(int32 num) 136 { 137 static DBT rv; 138 static char data_string[64]; 139 140 rv.data = data_string; 141 142 snprintf(data_string, sizeof(data_string), "%ld", (long)num); 143 rv.size = strlen(data_string); 144 145 return (&rv); 146 } 147 148 DBT * 149 GenKey(int32 num, key_type_enum key_type) 150 { 151 DBT *key; 152 153 switch (key_type) { 154 case USE_LARGE_KEY: 155 key = MakeLargeKey(num); 156 break; 157 case USE_SMALL_KEY: 158 key = MakeSmallKey(num); 159 break; 160 default: 161 abort(); 162 break; 163 } 164 165 return (key); 166 } 167 168 int 169 SeqDatabase() 170 { 171 int status; 172 DBT key, data; 173 174 ReportStatus("SEQuencing through database..."); 175 176 /* seq through the whole database */ 177 if (!(status = (*database->seq)(database, &key, &data, R_FIRST))) { 178 while (!(status = (database->seq)(database, &key, &data, R_NEXT))) 179 ; /* null body */ 180 } 181 182 if (status < 0) 183 ReportError("Error seq'ing database"); 184 185 return (status); 186 } 187 188 int 189 VerifyData(DBT *data, int32 num, key_type_enum key_type) 190 { 191 int32 count, compare_num; 192 size_t size; 193 int32 *int32_array; 194 195 /* The first int32 is count 196 * The other n entries should 197 * all equal num 198 */ 199 if (data->size < sizeof(int32)) { 200 ReportError("Data size corrupted"); 201 return -1; 202 } 203 204 memcpy(&count, data->data, sizeof(int32)); 205 206 size = sizeof(int32) * (count + 1); 207 208 if (size != data->size) { 209 ReportError("Data size corrupted"); 210 return -1; 211 } 212 213 int32_array = (int32 *)data->data; 214 215 for (; count > 0; count--) { 216 memcpy(&compare_num, &int32_array[count], sizeof(int32)); 217 218 if (compare_num != num) { 219 ReportError("Data corrupted"); 220 return -1; 221 } 222 } 223 224 return (0); 225 } 226 227 /* verify that a range of number strings exist 228 * or don't exist. And that the data is valid 229 */ 230 #define SHOULD_EXIST 1 231 #define SHOULD_NOT_EXIST 0 232 int 233 VerifyRange(int32 low, int32 high, int32 should_exist, key_type_enum key_type) 234 { 235 DBT *key, data; 236 int32 num; 237 int status; 238 239 TraceMe(1, ("Verifying: %ld to %ld, using %s keys", 240 low, high, key_type == USE_SMALL_KEY ? "SMALL" : "LARGE")); 241 242 for (num = low; num <= high; num++) { 243 244 key = GenKey(num, key_type); 245 246 status = (*database->get)(database, key, &data, 0); 247 248 if (status == 0) { 249 /* got the item */ 250 if (!should_exist) { 251 ReportError("Item exists but shouldn't: %ld", num); 252 } else { 253 /* else verify the data */ 254 VerifyData(&data, num, key_type); 255 } 256 } else if (status > 0) { 257 /* item not found */ 258 if (should_exist) { 259 ReportError("Item not found but should be: %ld", num); 260 } 261 } else { 262 /* database error */ 263 ReportError("Database error"); 264 return (-1); 265 } 266 } 267 268 TraceMe(1, ("Correctly verified: %ld to %ld", low, high)); 269 270 return (0); 271 } 272 273 DBT * 274 GenData(int32 num) 275 { 276 int32 n; 277 static DBT *data = 0; 278 int32 *int32_array; 279 size_t size; 280 281 if (!data) { 282 data = (DBT *)malloc(sizeof(DBT)); 283 data->size = 0; 284 data->data = 0; 285 } else if (data->data) { 286 free(data->data); 287 } 288 289 n = rand(); 290 291 n = n % 512; /* bound to a 2K size */ 292 293 size = sizeof(int32) * (n + 1); 294 int32_array = (int32 *)malloc(size); 295 296 memcpy(&int32_array[0], &n, sizeof(int32)); 297 298 for (; n > 0; n--) { 299 memcpy(&int32_array[n], &num, sizeof(int32)); 300 } 301 302 data->data = (void *)int32_array; 303 data->size = size; 304 305 return (data); 306 } 307 308 #define ADD_RANGE 1 309 #define DELETE_RANGE 2 310 311 int 312 AddOrDelRange(int32 low, int32 high, int action, key_type_enum key_type) 313 { 314 DBT *key, *data; 315 #if 0 /* only do this if your really analy checking the puts */ 316 DBT tmp_data; 317 #endif 318 int32 num; 319 int status; 320 321 if (action != ADD_RANGE && action != DELETE_RANGE) 322 assert(0); 323 324 if (action == ADD_RANGE) { 325 TraceMe(1, ("Adding: %ld to %ld: %s keys", low, high, 326 key_type == USE_SMALL_KEY ? "SMALL" : "LARGE")); 327 } else { 328 TraceMe(1, ("Deleting: %ld to %ld: %s keys", low, high, 329 key_type == USE_SMALL_KEY ? "SMALL" : "LARGE")); 330 } 331 332 for (num = low; num <= high; num++) { 333 334 key = GenKey(num, key_type); 335 336 if (action == ADD_RANGE) { 337 data = GenData(num); 338 status = (*database->put)(database, key, data, 0); 339 } else { 340 status = (*database->del)(database, key, 0); 341 } 342 343 if (status < 0) { 344 ReportError("Database error %s item: %ld", 345 action == ADD_RANGE ? "ADDING" : "DELETING", 346 num); 347 } else if (status > 0) { 348 ReportError("Could not %s item: %ld", 349 action == ADD_RANGE ? "ADD" : "DELETE", 350 num); 351 } else if (action == ADD_RANGE) { 352 #define SYNC_EVERY_TIME 353 #ifdef SYNC_EVERY_TIME 354 status = (*database->sync)(database, 0); 355 if (status != 0) 356 ReportError("Database error syncing after add"); 357 #endif 358 359 #if 0 /* only do this if your really analy checking the puts */ 360 361 /* make sure we can still get it 362 */ 363 status = (*database->get)(database, key, &tmp_data, 0); 364 365 if(status != 0) 366 { 367 ReportError("Database error checking item just added: %d", 368 num); 369 } 370 else 371 { 372 /* now verify that none of the ones we already 373 * put in have disappeared 374 */ 375 VerifyRange(low, num, SHOULD_EXIST, key_type); 376 } 377 #endif 378 } 379 } 380 381 if (action == ADD_RANGE) { 382 TraceMe(1, ("Successfully added: %ld to %ld", low, high)); 383 } else { 384 TraceMe(1, ("Successfully deleted: %ld to %ld", low, high)); 385 } 386 387 return (0); 388 } 389 390 int 391 TestRange(int32 low, int32 range, key_type_enum key_type) 392 { 393 int status; 394 int32 low_of_range1, high_of_range1; 395 int32 low_of_range2, high_of_range2; 396 int32 low_of_range3, high_of_range3; 397 398 status = AddOrDelRange(low, low + range, ADD_RANGE, key_type); 399 status = VerifyRange(low, low + range, SHOULD_EXIST, key_type); 400 401 TraceMe(1, ("Finished with sub test 1")); 402 403 SeqDatabase(); 404 405 low_of_range1 = low; 406 high_of_range1 = low + (range / 2); 407 low_of_range2 = high_of_range1 + 1; 408 high_of_range2 = low + range; 409 status = AddOrDelRange(low_of_range1, high_of_range1, DELETE_RANGE, key_type); 410 status = VerifyRange(low_of_range1, high_of_range1, SHOULD_NOT_EXIST, key_type); 411 status = VerifyRange(low_of_range2, low_of_range2, SHOULD_EXIST, key_type); 412 413 TraceMe(1, ("Finished with sub test 2")); 414 415 SeqDatabase(); 416 417 status = AddOrDelRange(low_of_range1, high_of_range1, ADD_RANGE, key_type); 418 /* the whole thing should exist now */ 419 status = VerifyRange(low, low + range, SHOULD_EXIST, key_type); 420 421 TraceMe(1, ("Finished with sub test 3")); 422 423 SeqDatabase(); 424 425 status = AddOrDelRange(low_of_range2, high_of_range2, DELETE_RANGE, key_type); 426 status = VerifyRange(low_of_range1, high_of_range1, SHOULD_EXIST, key_type); 427 status = VerifyRange(low_of_range2, high_of_range2, SHOULD_NOT_EXIST, key_type); 428 429 TraceMe(1, ("Finished with sub test 4")); 430 431 SeqDatabase(); 432 433 status = AddOrDelRange(low_of_range2, high_of_range2, ADD_RANGE, key_type); 434 /* the whole thing should exist now */ 435 status = VerifyRange(low, low + range, SHOULD_EXIST, key_type); 436 437 TraceMe(1, ("Finished with sub test 5")); 438 439 SeqDatabase(); 440 441 low_of_range1 = low; 442 high_of_range1 = low + (range / 3); 443 low_of_range2 = high_of_range1 + 1; 444 high_of_range2 = high_of_range1 + (range / 3); 445 low_of_range3 = high_of_range2 + 1; 446 high_of_range3 = low + range; 447 /* delete range 2 */ 448 status = AddOrDelRange(low_of_range2, high_of_range2, DELETE_RANGE, key_type); 449 status = VerifyRange(low_of_range1, high_of_range1, SHOULD_EXIST, key_type); 450 status = VerifyRange(low_of_range2, low_of_range2, SHOULD_NOT_EXIST, key_type); 451 status = VerifyRange(low_of_range3, low_of_range2, SHOULD_EXIST, key_type); 452 453 TraceMe(1, ("Finished with sub test 6")); 454 455 SeqDatabase(); 456 457 status = AddOrDelRange(low_of_range2, high_of_range2, ADD_RANGE, key_type); 458 /* the whole thing should exist now */ 459 status = VerifyRange(low, low + range, SHOULD_EXIST, key_type); 460 461 TraceMe(1, ("Finished with sub test 7")); 462 463 return (0); 464 } 465 466 #define START_RANGE 109876 467 int 468 main(int argc, char **argv) 469 { 470 int32 i, j = 0; 471 int quick_exit = 0; 472 int large_keys = 0; 473 HASHINFO hash_info = { 474 16 * 1024, 475 0, 476 0, 477 0, 478 0, 479 0 480 }; 481 482 if (argc > 1) { 483 while (argc > 1) { 484 if (!strcmp(argv[argc - 1], "-quick")) 485 quick_exit = 1; 486 else if (!strcmp(argv[argc - 1], "-large")) { 487 large_keys = 1; 488 } 489 argc--; 490 } 491 } 492 493 database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, &hash_info); 494 495 if (!database) { 496 ReportError("Could not open database"); 497 #ifdef unix 498 perror(""); 499 #endif 500 exit(1); 501 } 502 503 if (quick_exit) { 504 if (large_keys) 505 TestRange(START_RANGE, 200, USE_LARGE_KEY); 506 else 507 TestRange(START_RANGE, 200, USE_SMALL_KEY); 508 509 (*database->sync)(database, 0); 510 (*database->close)(database); 511 exit(0); 512 } 513 514 for (i = 100; i < 10000000; i += 200) { 515 if (1 || j) { 516 TestRange(START_RANGE, i, USE_LARGE_KEY); 517 j = 0; 518 } else { 519 TestRange(START_RANGE, i, USE_SMALL_KEY); 520 j = 1; 521 } 522 523 if (1 == rand() % 3) { 524 (*database->sync)(database, 0); 525 } 526 527 if (1 == rand() % 3) { 528 /* close and reopen */ 529 (*database->close)(database); 530 database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, 0); 531 if (!database) { 532 ReportError("Could not reopen database"); 533 #ifdef unix 534 perror(""); 535 #endif 536 exit(1); 537 } 538 } else { 539 /* reopen database without closeing the other */ 540 database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, 0); 541 if (!database) { 542 ReportError("Could not reopen database " 543 "after not closing the other"); 544 #ifdef unix 545 perror(""); 546 #endif 547 exit(1); 548 } 549 } 550 } 551 552 return (0); 553 }