security/nss/lib/dbm/tests/lots.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     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  */
    27 #include <stdio.h>
    29 #include <stdlib.h>
    30 #ifdef STDC_HEADERS
    31 #include <stdarg.h>
    32 #else
    33 #include <varargs.h>
    34 #endif
    36 #ifdef HAVE_MEMORY_H
    37 #include <memory.h>
    38 #endif
    39 #include <string.h>
    40 #include <assert.h>
    41 #include "mcom_db.h"
    43 DB *database=0;
    44 int MsgPriority=5;
    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
    54 typedef enum {
    55 USE_LARGE_KEY,
    56 USE_SMALL_KEY
    57 } key_type_enum;
    59 #define TraceMe(priority, msg) 		\
    60 	do {							\
    61 		if(priority <= MsgPriority)	\
    62 		  {							\
    63 			ReportStatus msg;		\
    64 		  }							\
    65 	} while(0)
    67 int
    68 ReportStatus(char *string, ...)
    69 {
    70     va_list args;
    72 #ifdef STDC_HEADERS
    73     va_start(args, string);
    74 #else
    75     va_start(args);
    76 #endif
    77     vfprintf(stderr, string, args);
    78     va_end(args);
    80 	fprintf (stderr, "\n");
    82 	return(0);
    83 }
    85 int
    86 ReportError(char *string, ...)
    87 {
    88     va_list args;
    90 #ifdef STDC_HEADERS
    91     va_start(args, string);
    92 #else
    93     va_start(args);
    94 #endif
    95 	fprintf (stderr, "\n	");
    96     vfprintf(stderr, string, args);
    97 	fprintf (stderr, "\n");
    98     va_end(args);
   100 	return(0);
   101 }
   103 DBT * 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;
   111 	if(string_rv)
   112 		free(string_rv);
   114 	/* generate a really large text key derived from
   115 	 * an int32
   116 	 */
   117 	low_bits = (num % 10000) + 1;
   119 	/* get the repeat char from the low 26 */
   120 	rep_char = (char) ((low_bits % 26) + 'a');
   122 	/* malloc a string low_bits wide */
   123 	size = low_bits*sizeof(char);
   124 	string_rv = (char *)malloc(size);
   126 	memset(string_rv, rep_char, size);
   128 	rv.data = string_rv;
   129 	rv.size = size;
   131 	return(&rv);
   132 }
   134 DBT * MakeSmallKey(int32 num)
   135 {
   136 	static DBT rv;
   137 	static char data_string[64];
   139 	rv.data = data_string;
   141 	sprintf(data_string, "%ld", (long)num);
   142 	rv.size = strlen(data_string);
   144 	return(&rv);
   146 }
   148 DBT * GenKey(int32 num, key_type_enum key_type)
   149 {
   150 	DBT *key;
   152 	switch(key_type)
   153 	  {
   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 	  }
   165 	return(key);
   166 }
   168 int
   169 SeqDatabase()
   170 {
   171 	int status;
   172 	DBT key, data;
   174 	ReportStatus("SEQuencing through database...");
   176 	/* seq through the whole database */
   177     if(!(status = (*database->seq)(database, &key, &data, R_FIRST)))
   178 	  {
   179         while(!(status = (database->seq) (database, &key, &data, R_NEXT)))
   180 			; /* null body */
   181 	  }
   183 	if(status < 0)
   184 		ReportError("Error seq'ing database");
   186 	return(status);
   187 }
   189 int 
   190 VerifyData(DBT *data, int32 num, key_type_enum key_type)
   191 {
   192 	int32 count, compare_num;
   193 	size_t size;
   194 	int32 *int32_array;
   196 	/* The first int32 is count 
   197 	 * The other n entries should
   198 	 * all equal num
   199 	 */
   200 	if(data->size < sizeof(int32))
   201 	  {
   202 		ReportError("Data size corrupted");
   203 		return -1;
   204 	  }
   206 	memcpy(&count, data->data, sizeof(int32));
   208 	size = sizeof(int32)*(count+1);
   210 	if(size != data->size)
   211 	  {
   212 		ReportError("Data size corrupted");
   213 		return -1;
   214 	  }
   216 	int32_array = (int32*)data->data;
   218 	for(;count > 0; count--)
   219 	  {
   220 		memcpy(&compare_num, &int32_array[count], sizeof(int32));
   222 		if(compare_num != num)
   223 	      {
   224 		    ReportError("Data corrupted");
   225 		    return -1;
   226 	      }
   227 	  }
   229 	return(0);
   230 }
   233 /* verify that a range of number strings exist
   234  * or don't exist. And that the data is valid
   235  */
   236 #define SHOULD_EXIST 1
   237 #define SHOULD_NOT_EXIST 0
   238 int
   239 VerifyRange(int32 low, int32 high, int32 should_exist, key_type_enum key_type)
   240 {
   241 	DBT *key, data;
   242 	int32 num;
   243 	int status;
   245 	TraceMe(1, ("Verifying: %ld to %ld, using %s keys", 
   246 		    low, high, key_type == USE_SMALL_KEY ? "SMALL" : "LARGE"));
   248 	for(num = low; num <= high; num++)
   249 	  {
   251 		key = GenKey(num, key_type);
   253 		status = (*database->get)(database, key, &data, 0);
   255 		if(status == 0)
   256 		  {
   257 			/* got the item */
   258 			if(!should_exist)
   259 			  {
   260 				ReportError("Item exists but shouldn't: %ld", num);
   261 			  }
   262 			else
   263 			  {
   264 			    /* else verify the data */
   265 			    VerifyData(&data, num, key_type);
   266 			  }
   267 		  }
   268 		else if(status > 0)
   269 		  {
   270 			/* item not found */
   271 			if(should_exist)
   272 			  {
   273 				ReportError("Item not found but should be: %ld", num);
   274 			  }
   275 		  }
   276 		else
   277 		  {
   278 			/* database error */
   279 			ReportError("Database error");
   280 			return(-1);
   281 		  }
   283 	  }
   285 	TraceMe(1, ("Correctly verified: %ld to %ld", low, high));
   287 	return(0);
   289 }
   291 DBT *
   292 GenData(int32 num)
   293 {
   294 	int32 n;
   295 	static DBT *data=0;
   296 	int32 *int32_array;
   297 	size_t size;
   299 	if(!data)
   300 	  {
   301 		data = (DBT*)malloc(sizeof(DBT));
   302 		data->size = 0;
   303 		data->data = 0;
   304 	  }
   305 	else if(data->data)
   306 	  {
   307 		free(data->data);
   308 	  }
   310 	n = rand();
   312 	n = n % 512;  /* bound to a 2K size */
   315 	size = sizeof(int32)*(n+1);
   316 	int32_array = (int32 *) malloc(size);
   318 	memcpy(&int32_array[0], &n, sizeof(int32));
   320 	for(; n > 0; n--)
   321 	  {
   322 		memcpy(&int32_array[n], &num, sizeof(int32));
   323 	  }
   325 	data->data = (void*)int32_array;
   326 	data->size = size;
   328 	return(data);
   329 }
   331 #define ADD_RANGE 1
   332 #define DELETE_RANGE 2
   334 int
   335 AddOrDelRange(int32 low, int32 high, int action, key_type_enum key_type)
   336 {
   337 	DBT *key, *data;
   338 #if 0 /* only do this if your really analy checking the puts */
   339 	DBT tmp_data;
   340 #endif 
   341 	int32 num;
   342 	int status;
   344 	if(action != ADD_RANGE && action != DELETE_RANGE)
   345 		assert(0);
   347 	if(action == ADD_RANGE)
   348 	  {
   349 		TraceMe(1, ("Adding: %ld to %ld: %s keys", low, high,
   350 		    	key_type == USE_SMALL_KEY ? "SMALL" : "LARGE"));
   351 	  }
   352 	else
   353 	  {
   354 		TraceMe(1, ("Deleting: %ld to %ld: %s keys", low, high,
   355 		    	key_type == USE_SMALL_KEY ? "SMALL" : "LARGE"));
   356 	  }
   358 	for(num = low; num <= high; num++)
   359 	  {
   361 		key = GenKey(num, key_type);
   363 		if(action == ADD_RANGE)
   364 		  {
   365 			data = GenData(num);
   366 			status = (*database->put)(database, key, data, 0);
   367 		  }
   368 		else
   369 		  {
   370 			status = (*database->del)(database, key, 0);
   371 		  }
   373 		if(status < 0)
   374 		  {
   375 			ReportError("Database error %s item: %ld",
   376 							action == ADD_RANGE ? "ADDING" : "DELETING", 
   377 							num);
   378 		  }
   379 		else if(status > 0)
   380 		  {
   381 			ReportError("Could not %s item: %ld", 
   382 							action == ADD_RANGE ? "ADD" : "DELETE", 
   383 							num);
   384 		  }
   385 		else if(action == ADD_RANGE)
   386 		  {
   387 #define SYNC_EVERY_TIME
   388 #ifdef SYNC_EVERY_TIME
   389 			status = (*database->sync)(database, 0);
   390 			if(status != 0)
   391 				ReportError("Database error syncing after add");
   392 #endif
   394 #if 0 /* only do this if your really analy checking the puts */
   396 			/* make sure we can still get it
   397 			 */
   398 			status = (*database->get)(database, key, &tmp_data, 0);
   400 			if(status != 0)
   401 			  {
   402 				ReportError("Database error checking item just added: %d",
   403 							num);
   404 			  }
   405 			else
   406 			  {
   407 				/* now verify that none of the ones we already
   408 				 * put in have disappeared
   409 				 */
   410 				VerifyRange(low, num, SHOULD_EXIST, key_type);
   411 			  }
   412 #endif
   414 		  }
   415 	  }
   418 	if(action == ADD_RANGE)
   419 	  {
   420 		TraceMe(1, ("Successfully added: %ld to %ld", low, high));
   421 	  }
   422 	else
   423 	  {
   424 		TraceMe(1, ("Successfully deleted: %ld to %ld", low, high));
   425 	  }
   427 	return(0);
   428 }
   430 int
   431 TestRange(int32 low, int32 range, key_type_enum key_type)
   432 {
   433 	int status; int32 low_of_range1, high_of_range1; int32 low_of_range2, high_of_range2;
   434 	int32 low_of_range3, high_of_range3;
   436 	status = AddOrDelRange(low, low+range, ADD_RANGE, key_type);
   437 	status = VerifyRange(low, low+range, SHOULD_EXIST, key_type);
   439 	TraceMe(1, ("Finished with sub test 1"));
   441 	SeqDatabase();
   443 	low_of_range1 = low;
   444 	high_of_range1 = low+(range/2);
   445 	low_of_range2 = high_of_range1+1;
   446 	high_of_range2 = low+range;
   447 	status = AddOrDelRange(low_of_range1, high_of_range1, DELETE_RANGE, key_type);
   448 	status = VerifyRange(low_of_range1, high_of_range1, SHOULD_NOT_EXIST, key_type);
   449 	status = VerifyRange(low_of_range2, low_of_range2, SHOULD_EXIST, key_type);
   451 	TraceMe(1, ("Finished with sub test 2"));
   453 	SeqDatabase();
   455 	status = AddOrDelRange(low_of_range1, high_of_range1, ADD_RANGE, key_type);
   456 	/* the whole thing should exist now */
   457 	status = VerifyRange(low, low+range, SHOULD_EXIST, key_type);
   459 	TraceMe(1, ("Finished with sub test 3"));
   461 	SeqDatabase();
   463 	status = AddOrDelRange(low_of_range2, high_of_range2, DELETE_RANGE, key_type);
   464 	status = VerifyRange(low_of_range1, high_of_range1, SHOULD_EXIST, key_type);
   465 	status = VerifyRange(low_of_range2, high_of_range2, SHOULD_NOT_EXIST, key_type);
   467 	TraceMe(1, ("Finished with sub test 4"));
   469 	SeqDatabase();
   471 	status = AddOrDelRange(low_of_range2, high_of_range2, ADD_RANGE, key_type);
   472 	/* the whole thing should exist now */
   473 	status = VerifyRange(low, low+range, SHOULD_EXIST, key_type);
   475 	TraceMe(1, ("Finished with sub test 5"));
   477 	SeqDatabase();
   479 	low_of_range1 = low;
   480 	high_of_range1 = low+(range/3);
   481 	low_of_range2 = high_of_range1+1;
   482 	high_of_range2 = high_of_range1+(range/3);
   483 	low_of_range3 = high_of_range2+1;
   484 	high_of_range3 = low+range;
   485 	/* delete range 2 */
   486 	status = AddOrDelRange(low_of_range2, high_of_range2, DELETE_RANGE, key_type);
   487 	status = VerifyRange(low_of_range1, high_of_range1, SHOULD_EXIST, key_type);
   488 	status = VerifyRange(low_of_range2, low_of_range2, SHOULD_NOT_EXIST, key_type);
   489 	status = VerifyRange(low_of_range3, low_of_range2, SHOULD_EXIST, key_type);
   491 	TraceMe(1, ("Finished with sub test 6"));
   493 	SeqDatabase();
   495 	status = AddOrDelRange(low_of_range2, high_of_range2, ADD_RANGE, key_type);
   496 	/* the whole thing should exist now */
   497 	status = VerifyRange(low, low+range, SHOULD_EXIST, key_type);
   499 	TraceMe(1, ("Finished with sub test 7"));
   501 	return(0);
   502 }
   504 #define START_RANGE 109876
   505 int
   506 main(int argc, char **argv)
   507 {
   508 	int32 i, j=0;
   509     int quick_exit = 0;
   510     int large_keys = 0;
   511     HASHINFO hash_info = {
   512         16*1024,
   513         0,
   514         0,
   515         0,
   516         0,
   517         0};
   520     if(argc > 1)
   521       {
   522         while(argc > 1)
   523 	  {
   524             if(!strcmp(argv[argc-1], "-quick"))
   525                 quick_exit = 1;
   526             else if(!strcmp(argv[argc-1], "-large"))
   527 			  {
   528                 large_keys = 1;
   529 			  }
   530             argc--;
   531           }
   532       }
   534 	database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, &hash_info);
   536 	if(!database)
   537 	  {
   538 		ReportError("Could not open database");
   539 #ifdef unix
   540 		perror("");
   541 #endif
   542 		exit(1);
   543 	  }
   545 	if(quick_exit)
   546 	  {
   547 		if(large_keys)
   548 			TestRange(START_RANGE, 200, USE_LARGE_KEY);
   549 		else
   550 			TestRange(START_RANGE, 200, USE_SMALL_KEY);
   552 		(*database->sync)(database, 0);
   553 		(*database->close)(database);
   554         exit(0);
   555 	  }
   557 	for(i=100; i < 10000000; i+=200)
   558 	  {
   559 		if(1 || j)
   560 		  {
   561 			TestRange(START_RANGE, i, USE_LARGE_KEY);
   562 			j = 0;
   563 		  }
   564 		else
   565 		  {
   566 			TestRange(START_RANGE, i, USE_SMALL_KEY);
   567 			j = 1;
   568 		  }
   570 		if(1 == rand() % 3)
   571 		  {
   572 			(*database->sync)(database, 0);
   573 		  }
   575 		if(1 == rand() % 3)
   576 	 	  {
   577 			/* close and reopen */
   578 			(*database->close)(database);
   579 			database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, 0);
   580 			if(!database)
   581 	  		{
   582 				ReportError("Could not reopen database");
   583 #ifdef unix
   584 				perror("");
   585 #endif
   586 				exit(1);
   587 	  		}
   588 	 	  }
   589 		else
   590 		  {
   591 			/* reopen database without closeing the other */
   592 			database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, 0);
   593 			if(!database)
   594 	  		{
   595 				ReportError("Could not reopen database "
   596 							"after not closing the other");
   597 #ifdef unix
   598 				perror("");
   599 #endif
   600 				exit(1);
   601 	  		}
   602 	 	  }
   603 	  }
   605 	return(0);
   606 }

mercurial