Back to index

lightning-sunbird  0.9+nobinonly
lots.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Netscape Public License
00006  * Version 1.1 (the "License"); you may not use this file except in
00007  * compliance with the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/NPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is 
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the NPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the NPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /* use sequental numbers printed to strings
00040  * to store lots and lots of entries in the
00041  * database.
00042  *
00043  * Start with 100 entries, put them and then
00044  * read them out.  Then delete the first
00045  * half and verify that all of the first half
00046  * is gone and then verify that the second
00047  * half is still there.
00048  * Then add the first half back and verify
00049  * again.  Then delete the middle third
00050  * and verify again.
00051  * Then increase the size by 1000 and do
00052  * the whole add delete thing again.
00053  *
00054  * The data for each object is the number string translated
00055  * to hex and replicated a random number of times.  The
00056  * number of times that the data is replicated is the first
00057  * int32 in the data.
00058  */
00059 
00060 #include <stdio.h>
00061 
00062 #include <stdlib.h>
00063 #ifdef STDC_HEADERS
00064 #include <stdarg.h>
00065 #else
00066 #include <varargs.h>
00067 #endif
00068 
00069 #ifdef HAVE_MEMORY_H
00070 #include <memory.h>
00071 #endif
00072 #include <string.h>
00073 #include <assert.h>
00074 #include "mcom_db.h"
00075 
00076 DB *database=0;
00077 int MsgPriority=5;
00078 
00079 #if defined(_WINDOWS) && !defined(WIN32)
00080 #define int32 long
00081 #define uint32 unsigned long
00082 #else
00083 #define int32 int
00084 #define uint32 unsigned int
00085 #endif
00086 
00087 typedef enum {
00088 USE_LARGE_KEY,
00089 USE_SMALL_KEY
00090 } key_type_enum;
00091 
00092 #define TraceMe(priority, msg)            \
00093        do {                                             \
00094               if(priority <= MsgPriority) \
00095                 {                                              \
00096                      ReportStatus msg;           \
00097                 }                                              \
00098        } while(0)
00099 
00100 int
00101 ReportStatus(char *string, ...)
00102 {
00103     va_list args;
00104 
00105 #ifdef STDC_HEADERS
00106     va_start(args, string);
00107 #else
00108     va_start(args);
00109 #endif
00110     vfprintf(stderr, string, args);
00111     va_end(args);
00112 
00113        fprintf (stderr, "\n");
00114 
00115        return(0);
00116 }
00117 
00118 int
00119 ReportError(char *string, ...)
00120 {
00121     va_list args;
00122 
00123 #ifdef STDC_HEADERS
00124     va_start(args, string);
00125 #else
00126     va_start(args);
00127 #endif
00128        fprintf (stderr, "\n ");
00129     vfprintf(stderr, string, args);
00130        fprintf (stderr, "\n");
00131     va_end(args);
00132 
00133        return(0);
00134 }
00135 
00136 DBT * MakeLargeKey(int32 num)
00137 {
00138        int32 low_bits;
00139        static DBT rv;
00140        static char *string_rv=0;
00141        int rep_char;
00142        size_t size;
00143 
00144        if(string_rv)
00145               free(string_rv);
00146 
00147        /* generate a really large text key derived from
00148         * an int32
00149         */
00150        low_bits = (num % 10000) + 1;
00151 
00152        /* get the repeat char from the low 26 */
00153        rep_char = (char) ((low_bits % 26) + 'a');
00154 
00155        /* malloc a string low_bits wide */
00156        size = low_bits*sizeof(char);
00157        string_rv = (char *)malloc(size);
00158 
00159        memset(string_rv, rep_char, size);
00160 
00161        rv.data = string_rv;
00162        rv.size = size;
00163 
00164        return(&rv);
00165 }
00166 
00167 DBT * MakeSmallKey(int32 num)
00168 {
00169        static DBT rv;
00170        static char data_string[64];
00171 
00172        rv.data = data_string;
00173 
00174        sprintf(data_string, "%ld", (long)num);
00175        rv.size = strlen(data_string);
00176 
00177        return(&rv);
00178 
00179 }
00180 
00181 DBT * GenKey(int32 num, key_type_enum key_type)
00182 {
00183        DBT *key;
00184 
00185        switch(key_type)
00186          {
00187               case USE_LARGE_KEY:
00188                      key = MakeLargeKey(num);
00189                      break;
00190               case USE_SMALL_KEY:
00191                      key = MakeSmallKey(num);
00192                      break;
00193               default:
00194                      abort();
00195                      break;
00196          }
00197 
00198        return(key);
00199 }
00200 
00201 int
00202 SeqDatabase()
00203 {
00204        int status;
00205        DBT key, data;
00206 
00207        ReportStatus("SEQuencing through database...");
00208 
00209        /* seq throught the whole database */
00210     if(!(status = (*database->seq)(database, &key, &data, R_FIRST)))
00211          {
00212         while(!(status = (database->seq) (database, &key, &data, R_NEXT)));
00213                      ; /* null body */
00214          }
00215 
00216        if(status < 0)
00217               ReportError("Error seq'ing database");
00218 
00219        return(status);
00220 }
00221 
00222 int 
00223 VerifyData(DBT *data, int32 num, key_type_enum key_type)
00224 {
00225        int32 count, compare_num;
00226        size_t size;
00227        int32 *int32_array;
00228 
00229        /* The first int32 is count 
00230         * The other n entries should
00231         * all equal num
00232         */
00233        if(data->size < sizeof(int32))
00234          {
00235               ReportError("Data size corrupted");
00236               return -1;
00237          }
00238 
00239        memcpy(&count, data->data, sizeof(int32));
00240 
00241        size = sizeof(int32)*(count+1);
00242 
00243        if(size != data->size)
00244          {
00245               ReportError("Data size corrupted");
00246               return -1;
00247          }
00248 
00249        int32_array = (int32*)data->data;
00250 
00251        for(;count > 0; count--)
00252          {
00253               memcpy(&compare_num, &int32_array[count], sizeof(int32));
00254 
00255               if(compare_num != num)
00256              {
00257                   ReportError("Data corrupted");
00258                   return -1;
00259              }
00260          }
00261 
00262        return(0);
00263 }
00264 
00265 
00266 /* verify that a range of number strings exist
00267  * or don't exist. And that the data is valid
00268  */
00269 #define SHOULD_EXIST 1
00270 #define SHOULD_NOT_EXIST 0
00271 int
00272 VerifyRange(int32 low, int32 high, int32 should_exist, key_type_enum key_type)
00273 {
00274        DBT *key, data;
00275        int32 num;
00276        int status;
00277 
00278        TraceMe(1, ("Verifying: %ld to %ld, using %s keys", 
00279                   low, high, key_type == USE_SMALL_KEY ? "SMALL" : "LARGE"));
00280 
00281        for(num = low; num <= high; num++)
00282          {
00283 
00284               key = GenKey(num, key_type);
00285 
00286               status = (*database->get)(database, key, &data, 0);
00287 
00288               if(status == 0)
00289                 {
00290                      /* got the item */
00291                      if(!should_exist)
00292                        {
00293                             ReportError("Item exists but shouldn't: %ld", num);
00294                        }
00295                      else
00296                        {
00297                          /* else verify the data */
00298                          VerifyData(&data, num, key_type);
00299                        }
00300                 }
00301               else if(status > 0)
00302                 {
00303                      /* item not found */
00304                      if(should_exist)
00305                        {
00306                             ReportError("Item not found but should be: %ld", num);
00307                        }
00308                 }
00309               else
00310                 {
00311                      /* database error */
00312                      ReportError("Database error");
00313                      return(-1);
00314                 }
00315                      
00316          }
00317 
00318        TraceMe(1, ("Correctly verified: %ld to %ld", low, high));
00319 
00320        return(0);
00321 
00322 }
00323 
00324 DBT *
00325 GenData(int32 num)
00326 {
00327        int32 n;
00328        static DBT *data=0;
00329        int32 *int32_array;
00330        size_t size;
00331 
00332        if(!data)
00333          {
00334               data = (DBT*)malloc(sizeof(DBT));
00335               data->size = 0;
00336               data->data = 0;
00337          }
00338        else if(data->data)
00339          {
00340               free(data->data);
00341          }
00342 
00343        n = rand();
00344 
00345        n = n % 512;  /* bound to a 2K size */
00346 
00347        
00348        size = sizeof(int32)*(n+1);
00349        int32_array = (int32 *) malloc(size);
00350 
00351        memcpy(&int32_array[0], &n, sizeof(int32));
00352 
00353        for(; n > 0; n--)
00354          {
00355               memcpy(&int32_array[n], &num, sizeof(int32));
00356          }
00357 
00358        data->data = (void*)int32_array;
00359        data->size = size;
00360 
00361        return(data);
00362 }
00363 
00364 #define ADD_RANGE 1
00365 #define DELETE_RANGE 2
00366 
00367 int
00368 AddOrDelRange(int32 low, int32 high, int action, key_type_enum key_type)
00369 {
00370        DBT *key, *data;
00371 #if 0 /* only do this if your really analy checking the puts */
00372        DBT tmp_data;
00373 #endif 
00374        int32 num;
00375        int status;
00376 
00377        if(action != ADD_RANGE && action != DELETE_RANGE)
00378               assert(0);
00379 
00380        if(action == ADD_RANGE)
00381          {
00382               TraceMe(1, ("Adding: %ld to %ld: %s keys", low, high,
00383                      key_type == USE_SMALL_KEY ? "SMALL" : "LARGE"));
00384          }
00385        else
00386          {
00387               TraceMe(1, ("Deleting: %ld to %ld: %s keys", low, high,
00388                      key_type == USE_SMALL_KEY ? "SMALL" : "LARGE"));
00389          }
00390 
00391        for(num = low; num <= high; num++)
00392          {
00393 
00394               key = GenKey(num, key_type);
00395 
00396               if(action == ADD_RANGE)
00397                 {
00398                      data = GenData(num);
00399                      status = (*database->put)(database, key, data, 0);
00400                 }
00401               else
00402                 {
00403                      status = (*database->del)(database, key, 0);
00404                 }
00405 
00406               if(status < 0)
00407                 {
00408                      ReportError("Database error %s item: %ld",
00409                                                  action == ADD_RANGE ? "ADDING" : "DELETING", 
00410                                                  num);
00411                 }
00412               else if(status > 0)
00413                 {
00414                      ReportError("Could not %s item: %ld", 
00415                                                  action == ADD_RANGE ? "ADD" : "DELETE", 
00416                                                  num);
00417                 }
00418               else if(action == ADD_RANGE)
00419                 {
00420 #define SYNC_EVERY_TIME
00421 #ifdef SYNC_EVERY_TIME
00422                      status = (*database->sync)(database, 0);
00423                      if(status != 0)
00424                             ReportError("Database error syncing after add");
00425 #endif
00426 
00427 #if 0 /* only do this if your really analy checking the puts */
00428         
00429                      /* make sure we can still get it
00430                       */
00431                      status = (*database->get)(database, key, &tmp_data, 0);
00432 
00433                      if(status != 0)
00434                        {
00435                             ReportError("Database error checking item just added: %d",
00436                                                  num);
00437                        }
00438                      else
00439                        {
00440                             /* now verify that none of the ones we already
00441                              * put in have disappeared
00442                              */
00443                             VerifyRange(low, num, SHOULD_EXIST, key_type);
00444                        }
00445 #endif
00446                      
00447                 }
00448          }
00449 
00450 
00451        if(action == ADD_RANGE)
00452          {
00453               TraceMe(1, ("Successfully added: %ld to %ld", low, high));
00454          }
00455        else
00456          {
00457               TraceMe(1, ("Successfully deleted: %ld to %ld", low, high));
00458          }
00459 
00460        return(0);
00461 }
00462 
00463 int
00464 TestRange(int32 low, int32 range, key_type_enum key_type)
00465 {
00466        int status; int32 low_of_range1, high_of_range1; int32 low_of_range2, high_of_range2;
00467        int32 low_of_range3, high_of_range3;
00468 
00469        status = AddOrDelRange(low, low+range, ADD_RANGE, key_type);
00470        status = VerifyRange(low, low+range, SHOULD_EXIST, key_type);
00471 
00472        TraceMe(1, ("Finished with sub test 1"));
00473 
00474        SeqDatabase();
00475 
00476        low_of_range1 = low;
00477        high_of_range1 = low+(range/2);
00478        low_of_range2 = high_of_range1+1;
00479        high_of_range2 = low+range;
00480        status = AddOrDelRange(low_of_range1, high_of_range1, DELETE_RANGE, key_type);
00481        status = VerifyRange(low_of_range1, high_of_range1, SHOULD_NOT_EXIST, key_type);
00482        status = VerifyRange(low_of_range2, low_of_range2, SHOULD_EXIST, key_type);
00483 
00484        TraceMe(1, ("Finished with sub test 2"));
00485 
00486        SeqDatabase();
00487 
00488        status = AddOrDelRange(low_of_range1, high_of_range1, ADD_RANGE, key_type);
00489        /* the whole thing should exist now */
00490        status = VerifyRange(low, low+range, SHOULD_EXIST, key_type);
00491 
00492        TraceMe(1, ("Finished with sub test 3"));
00493 
00494        SeqDatabase();
00495 
00496        status = AddOrDelRange(low_of_range2, high_of_range2, DELETE_RANGE, key_type);
00497        status = VerifyRange(low_of_range1, high_of_range1, SHOULD_EXIST, key_type);
00498        status = VerifyRange(low_of_range2, high_of_range2, SHOULD_NOT_EXIST, key_type);
00499 
00500        TraceMe(1, ("Finished with sub test 4"));
00501 
00502        SeqDatabase();
00503 
00504        status = AddOrDelRange(low_of_range2, high_of_range2, ADD_RANGE, key_type);
00505        /* the whole thing should exist now */
00506        status = VerifyRange(low, low+range, SHOULD_EXIST, key_type);
00507 
00508        TraceMe(1, ("Finished with sub test 5"));
00509 
00510        SeqDatabase();
00511 
00512        low_of_range1 = low;
00513        high_of_range1 = low+(range/3);
00514        low_of_range2 = high_of_range1+1;
00515        high_of_range2 = high_of_range1+(range/3);
00516        low_of_range3 = high_of_range2+1;
00517        high_of_range3 = low+range;
00518        /* delete range 2 */
00519        status = AddOrDelRange(low_of_range2, high_of_range2, DELETE_RANGE, key_type);
00520        status = VerifyRange(low_of_range1, high_of_range1, SHOULD_EXIST, key_type);
00521        status = VerifyRange(low_of_range2, low_of_range2, SHOULD_NOT_EXIST, key_type);
00522        status = VerifyRange(low_of_range3, low_of_range2, SHOULD_EXIST, key_type);
00523 
00524        TraceMe(1, ("Finished with sub test 6"));
00525 
00526        SeqDatabase();
00527 
00528        status = AddOrDelRange(low_of_range2, high_of_range2, ADD_RANGE, key_type);
00529        /* the whole thing should exist now */
00530        status = VerifyRange(low, low+range, SHOULD_EXIST, key_type);
00531 
00532        TraceMe(1, ("Finished with sub test 7"));
00533 
00534        return(0);
00535 }
00536 
00537 #define START_RANGE 109876
00538 int
00539 main(int argc, char **argv)
00540 {
00541        int32 i, j=0;
00542     int quick_exit = 0;
00543     int large_keys = 0;
00544     HASHINFO hash_info = {
00545         16*1024,
00546         0,
00547         0,
00548         0,
00549         0,
00550         0};
00551 
00552 
00553     if(argc > 1)
00554       {
00555         while(argc > 1)
00556          {
00557             if(!strcmp(argv[argc-1], "-quick"))
00558                 quick_exit = 1;
00559             else if(!strcmp(argv[argc-1], "-large"))
00560                        {
00561                 large_keys = 1;
00562                        }
00563             argc--;
00564           }
00565       }
00566 
00567        database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, &hash_info);
00568 
00569        if(!database)
00570          {
00571               ReportError("Could not open database");
00572 #ifdef unix
00573               perror("");
00574 #endif
00575               exit(1);
00576          }
00577 
00578        if(quick_exit)
00579          {
00580               if(large_keys)
00581                      TestRange(START_RANGE, 200, USE_LARGE_KEY);
00582               else
00583                      TestRange(START_RANGE, 200, USE_SMALL_KEY);
00584 
00585               (*database->sync)(database, 0);
00586               (*database->close)(database);
00587         exit(0);
00588          }
00589 
00590        for(i=100; i < 10000000; i+=200)
00591          {
00592               if(1 || j)
00593                 {
00594                      TestRange(START_RANGE, i, USE_LARGE_KEY);
00595                      j = 0;
00596                 }
00597               else
00598                 {
00599                      TestRange(START_RANGE, i, USE_SMALL_KEY);
00600                      j = 1;
00601                 }
00602 
00603               if(1 == rand() % 3)
00604                 {
00605                      (*database->sync)(database, 0);
00606                 }
00607               
00608               if(1 == rand() % 3)
00609                 {
00610                      /* close and reopen */
00611                      (*database->close)(database);
00612                      database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, 0);
00613                      if(!database)
00614                      {
00615                             ReportError("Could not reopen database");
00616 #ifdef unix
00617                             perror("");
00618 #endif
00619                             exit(1);
00620                      }
00621                 }
00622               else
00623                 {
00624                      /* reopen database without closeing the other */
00625                      database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, 0);
00626                      if(!database)
00627                      {
00628                             ReportError("Could not reopen database "
00629                                                  "after not closing the other");
00630 #ifdef unix
00631                             perror("");
00632 #endif
00633                             exit(1);
00634                      }
00635                 }
00636          }
00637 
00638        return(0);
00639 }