diff options
Diffstat (limited to '')
-rw-r--r-- | security/nss/lib/dbm/tests/lots.c | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/security/nss/lib/dbm/tests/lots.c b/security/nss/lib/dbm/tests/lots.c new file mode 100644 index 0000000000..4a12884ba0 --- /dev/null +++ b/security/nss/lib/dbm/tests/lots.c @@ -0,0 +1,553 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* use sequental numbers printed to strings + * to store lots and lots of entries in the + * database. + * + * Start with 100 entries, put them and then + * read them out. Then delete the first + * half and verify that all of the first half + * is gone and then verify that the second + * half is still there. + * Then add the first half back and verify + * again. Then delete the middle third + * and verify again. + * Then increase the size by 1000 and do + * the whole add delete thing again. + * + * The data for each object is the number string translated + * to hex and replicated a random number of times. The + * number of times that the data is replicated is the first + * int32 in the data. + */ + +#include <stdio.h> + +#include <stdlib.h> +#ifdef STDC_HEADERS +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#ifdef HAVE_MEMORY_H +#include <memory.h> +#endif +#include <string.h> +#include <assert.h> +#include "mcom_db.h" + +DB *database = 0; +int MsgPriority = 5; + +#if defined(_WINDOWS) && !defined(WIN32) +#define int32 long +#define uint32 unsigned long +#else +#define int32 int +#define uint32 unsigned int +#endif + +typedef enum { + USE_LARGE_KEY, + USE_SMALL_KEY +} key_type_enum; + +#define TraceMe(priority, msg) \ + do { \ + if (priority <= MsgPriority) { \ + ReportStatus msg; \ + } \ + } while (0) + +int +ReportStatus(char *string, ...) +{ + va_list args; + +#ifdef STDC_HEADERS + va_start(args, string); +#else + va_start(args); +#endif + vfprintf(stderr, string, args); + va_end(args); + + fprintf(stderr, "\n"); + + return (0); +} + +int +ReportError(char *string, ...) +{ + va_list args; + +#ifdef STDC_HEADERS + va_start(args, string); +#else + va_start(args); +#endif + fprintf(stderr, "\n "); + vfprintf(stderr, string, args); + fprintf(stderr, "\n"); + va_end(args); + + return (0); +} + +DBT * +MakeLargeKey(int32 num) +{ + int32 low_bits; + static DBT rv; + static char *string_rv = 0; + int rep_char; + size_t size; + + if (string_rv) + free(string_rv); + + /* generate a really large text key derived from + * an int32 + */ + low_bits = (num % 10000) + 1; + + /* get the repeat char from the low 26 */ + rep_char = (char)((low_bits % 26) + 'a'); + + /* malloc a string low_bits wide */ + size = low_bits * sizeof(char); + string_rv = (char *)malloc(size); + + memset(string_rv, rep_char, size); + + rv.data = string_rv; + rv.size = size; + + return (&rv); +} + +DBT * +MakeSmallKey(int32 num) +{ + static DBT rv; + static char data_string[64]; + + rv.data = data_string; + + snprintf(data_string, sizeof(data_string), "%ld", (long)num); + rv.size = strlen(data_string); + + return (&rv); +} + +DBT * +GenKey(int32 num, key_type_enum key_type) +{ + DBT *key; + + switch (key_type) { + case USE_LARGE_KEY: + key = MakeLargeKey(num); + break; + case USE_SMALL_KEY: + key = MakeSmallKey(num); + break; + default: + abort(); + break; + } + + return (key); +} + +int +SeqDatabase() +{ + int status; + DBT key, data; + + ReportStatus("SEQuencing through database..."); + + /* seq through the whole database */ + if (!(status = (*database->seq)(database, &key, &data, R_FIRST))) { + while (!(status = (database->seq)(database, &key, &data, R_NEXT))) + ; /* null body */ + } + + if (status < 0) + ReportError("Error seq'ing database"); + + return (status); +} + +int +VerifyData(DBT *data, int32 num, key_type_enum key_type) +{ + int32 count, compare_num; + size_t size; + int32 *int32_array; + + /* The first int32 is count + * The other n entries should + * all equal num + */ + if (data->size < sizeof(int32)) { + ReportError("Data size corrupted"); + return -1; + } + + memcpy(&count, data->data, sizeof(int32)); + + size = sizeof(int32) * (count + 1); + + if (size != data->size) { + ReportError("Data size corrupted"); + return -1; + } + + int32_array = (int32 *)data->data; + + for (; count > 0; count--) { + memcpy(&compare_num, &int32_array[count], sizeof(int32)); + + if (compare_num != num) { + ReportError("Data corrupted"); + return -1; + } + } + + return (0); +} + +/* verify that a range of number strings exist + * or don't exist. And that the data is valid + */ +#define SHOULD_EXIST 1 +#define SHOULD_NOT_EXIST 0 +int +VerifyRange(int32 low, int32 high, int32 should_exist, key_type_enum key_type) +{ + DBT *key, data; + int32 num; + int status; + + TraceMe(1, ("Verifying: %ld to %ld, using %s keys", + low, high, key_type == USE_SMALL_KEY ? "SMALL" : "LARGE")); + + for (num = low; num <= high; num++) { + + key = GenKey(num, key_type); + + status = (*database->get)(database, key, &data, 0); + + if (status == 0) { + /* got the item */ + if (!should_exist) { + ReportError("Item exists but shouldn't: %ld", num); + } else { + /* else verify the data */ + VerifyData(&data, num, key_type); + } + } else if (status > 0) { + /* item not found */ + if (should_exist) { + ReportError("Item not found but should be: %ld", num); + } + } else { + /* database error */ + ReportError("Database error"); + return (-1); + } + } + + TraceMe(1, ("Correctly verified: %ld to %ld", low, high)); + + return (0); +} + +DBT * +GenData(int32 num) +{ + int32 n; + static DBT *data = 0; + int32 *int32_array; + size_t size; + + if (!data) { + data = (DBT *)malloc(sizeof(DBT)); + data->size = 0; + data->data = 0; + } else if (data->data) { + free(data->data); + } + + n = rand(); + + n = n % 512; /* bound to a 2K size */ + + size = sizeof(int32) * (n + 1); + int32_array = (int32 *)malloc(size); + + memcpy(&int32_array[0], &n, sizeof(int32)); + + for (; n > 0; n--) { + memcpy(&int32_array[n], &num, sizeof(int32)); + } + + data->data = (void *)int32_array; + data->size = size; + + return (data); +} + +#define ADD_RANGE 1 +#define DELETE_RANGE 2 + +int +AddOrDelRange(int32 low, int32 high, int action, key_type_enum key_type) +{ + DBT *key, *data; +#if 0 /* only do this if your really analy checking the puts */ + DBT tmp_data; +#endif + int32 num; + int status; + + if (action != ADD_RANGE && action != DELETE_RANGE) + assert(0); + + if (action == ADD_RANGE) { + TraceMe(1, ("Adding: %ld to %ld: %s keys", low, high, + key_type == USE_SMALL_KEY ? "SMALL" : "LARGE")); + } else { + TraceMe(1, ("Deleting: %ld to %ld: %s keys", low, high, + key_type == USE_SMALL_KEY ? "SMALL" : "LARGE")); + } + + for (num = low; num <= high; num++) { + + key = GenKey(num, key_type); + + if (action == ADD_RANGE) { + data = GenData(num); + status = (*database->put)(database, key, data, 0); + } else { + status = (*database->del)(database, key, 0); + } + + if (status < 0) { + ReportError("Database error %s item: %ld", + action == ADD_RANGE ? "ADDING" : "DELETING", + num); + } else if (status > 0) { + ReportError("Could not %s item: %ld", + action == ADD_RANGE ? "ADD" : "DELETE", + num); + } else if (action == ADD_RANGE) { +#define SYNC_EVERY_TIME +#ifdef SYNC_EVERY_TIME + status = (*database->sync)(database, 0); + if (status != 0) + ReportError("Database error syncing after add"); +#endif + +#if 0 /* only do this if your really analy checking the puts */ + + /* make sure we can still get it + */ + status = (*database->get)(database, key, &tmp_data, 0); + + if(status != 0) + { + ReportError("Database error checking item just added: %d", + num); + } + else + { + /* now verify that none of the ones we already + * put in have disappeared + */ + VerifyRange(low, num, SHOULD_EXIST, key_type); + } +#endif + } + } + + if (action == ADD_RANGE) { + TraceMe(1, ("Successfully added: %ld to %ld", low, high)); + } else { + TraceMe(1, ("Successfully deleted: %ld to %ld", low, high)); + } + + return (0); +} + +int +TestRange(int32 low, int32 range, key_type_enum key_type) +{ + int status; + int32 low_of_range1, high_of_range1; + int32 low_of_range2, high_of_range2; + int32 low_of_range3, high_of_range3; + + status = AddOrDelRange(low, low + range, ADD_RANGE, key_type); + status = VerifyRange(low, low + range, SHOULD_EXIST, key_type); + + TraceMe(1, ("Finished with sub test 1")); + + SeqDatabase(); + + low_of_range1 = low; + high_of_range1 = low + (range / 2); + low_of_range2 = high_of_range1 + 1; + high_of_range2 = low + range; + status = AddOrDelRange(low_of_range1, high_of_range1, DELETE_RANGE, key_type); + status = VerifyRange(low_of_range1, high_of_range1, SHOULD_NOT_EXIST, key_type); + status = VerifyRange(low_of_range2, low_of_range2, SHOULD_EXIST, key_type); + + TraceMe(1, ("Finished with sub test 2")); + + SeqDatabase(); + + status = AddOrDelRange(low_of_range1, high_of_range1, ADD_RANGE, key_type); + /* the whole thing should exist now */ + status = VerifyRange(low, low + range, SHOULD_EXIST, key_type); + + TraceMe(1, ("Finished with sub test 3")); + + SeqDatabase(); + + status = AddOrDelRange(low_of_range2, high_of_range2, DELETE_RANGE, key_type); + status = VerifyRange(low_of_range1, high_of_range1, SHOULD_EXIST, key_type); + status = VerifyRange(low_of_range2, high_of_range2, SHOULD_NOT_EXIST, key_type); + + TraceMe(1, ("Finished with sub test 4")); + + SeqDatabase(); + + status = AddOrDelRange(low_of_range2, high_of_range2, ADD_RANGE, key_type); + /* the whole thing should exist now */ + status = VerifyRange(low, low + range, SHOULD_EXIST, key_type); + + TraceMe(1, ("Finished with sub test 5")); + + SeqDatabase(); + + low_of_range1 = low; + high_of_range1 = low + (range / 3); + low_of_range2 = high_of_range1 + 1; + high_of_range2 = high_of_range1 + (range / 3); + low_of_range3 = high_of_range2 + 1; + high_of_range3 = low + range; + /* delete range 2 */ + status = AddOrDelRange(low_of_range2, high_of_range2, DELETE_RANGE, key_type); + status = VerifyRange(low_of_range1, high_of_range1, SHOULD_EXIST, key_type); + status = VerifyRange(low_of_range2, low_of_range2, SHOULD_NOT_EXIST, key_type); + status = VerifyRange(low_of_range3, low_of_range2, SHOULD_EXIST, key_type); + + TraceMe(1, ("Finished with sub test 6")); + + SeqDatabase(); + + status = AddOrDelRange(low_of_range2, high_of_range2, ADD_RANGE, key_type); + /* the whole thing should exist now */ + status = VerifyRange(low, low + range, SHOULD_EXIST, key_type); + + TraceMe(1, ("Finished with sub test 7")); + + return (0); +} + +#define START_RANGE 109876 +int +main(int argc, char **argv) +{ + int32 i, j = 0; + int quick_exit = 0; + int large_keys = 0; + HASHINFO hash_info = { + 16 * 1024, + 0, + 0, + 0, + 0, + 0 + }; + + if (argc > 1) { + while (argc > 1) { + if (!strcmp(argv[argc - 1], "-quick")) + quick_exit = 1; + else if (!strcmp(argv[argc - 1], "-large")) { + large_keys = 1; + } + argc--; + } + } + + database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, &hash_info); + + if (!database) { + ReportError("Could not open database"); +#ifdef unix + perror(""); +#endif + exit(1); + } + + if (quick_exit) { + if (large_keys) + TestRange(START_RANGE, 200, USE_LARGE_KEY); + else + TestRange(START_RANGE, 200, USE_SMALL_KEY); + + (*database->sync)(database, 0); + (*database->close)(database); + exit(0); + } + + for (i = 100; i < 10000000; i += 200) { + if (1 || j) { + TestRange(START_RANGE, i, USE_LARGE_KEY); + j = 0; + } else { + TestRange(START_RANGE, i, USE_SMALL_KEY); + j = 1; + } + + if (1 == rand() % 3) { + (*database->sync)(database, 0); + } + + if (1 == rand() % 3) { + /* close and reopen */ + (*database->close)(database); + database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, 0); + if (!database) { + ReportError("Could not reopen database"); +#ifdef unix + perror(""); +#endif + exit(1); + } + } else { + /* reopen database without closeing the other */ + database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, 0); + if (!database) { + ReportError("Could not reopen database " + "after not closing the other"); +#ifdef unix + perror(""); +#endif + exit(1); + } + } + } + + return (0); +} |