#include #include #include #include #include #include #include #include #include #include #include #include #include "gdbmdefs.h" static unsigned long get_size (char const *str) { char *p; unsigned long n, m; errno = 0; n = strtoul (str, &p, 10); if (errno) { perror (str); exit (1); } switch (*p) { case 0: m = 1; break; case 'k': case 'K': p++; m = 1024; break; case 'm': case 'M': p++; m = 1024 * 1024; break; } if (*p) { fprintf (stderr, "%s: bad number (near %s)\n", str, p); exit (1); } if (ULONG_MAX / m < n) { fprintf (stderr, "%s: number too big\n", str); exit (1); } return m * n; } #ifdef DUMPSTATS static void dump_stats (GDBM_FILE dbf, size_t n) { static size_t cache_size; static struct gdbm_cache_stat *stat; size_t access_count, cache_count; FILE *fp; char fname[80]; size_t i; if (cache_size == 0) { if (gdbm_setopt (dbf, GDBM_GETCACHESIZE, &cache_size, sizeof(cache_size))) { fprintf (stderr, "GDBM_GETCACHESIZE: %s\n", gdbm_strerror (gdbm_errno)); exit (1); } stat = calloc (cache_size, sizeof (stat[0])); assert (stat != NULL); } gdbm_get_cache_stats (dbf, &access_count, &cache_count, stat, cache_size); snprintf (fname, sizeof (fname), "%zu.stat", n); fp = fopen (fname, "w"); assert (fp != NULL); fprintf (fp, "%zu\n", access_count); fprintf (fp, "%zu\n", cache_count); for (i = 0; i < cache_count; i++) { fprintf (fp, "%zu %zu\n", stat[i].adr, stat[i].hits); } fclose (fp); fprintf (stderr, "%80.80s\rDump file %s\n", "", fname); } static volatile int statsig; void sighan (int sig) { statsig = 1; signal (sig, sighan); } #endif char *dbname = "a.gdbm"; char *kfname = "keys.txt"; int percent; int verbose = 0; int time_verbose = 1; char *keybuf; char *keyptr; char *keyend; size_t nkeys; char * nextkey (void) { char *ret = keyptr; if (keyptr >= keyend) return NULL; keyptr += strlen (keyptr) + 1; return ret; } void readkeys (char const *name) { FILE *fp; size_t n; struct stat st; char *p; if (stat (name, &st)) { fprintf (stderr, "%s: can't stat: %s\n", name, strerror (errno)); exit (1); } fp = fopen (name, "r"); if (!fp) { fprintf (stderr, "%s: can't read: %s\n", name, strerror (errno)); exit (1); } keybuf = malloc (st.st_size + 1); assert (keybuf != NULL); keyend = keybuf + st.st_size; *keyend = 0; if (fread (keybuf, st.st_size, 1, fp) != 1) { fprintf (stderr, "%s: read error: %s\n", name, strerror (errno)); exit (1); } fclose (fp); keyptr = keybuf; nkeys = 0; for (p = keybuf; p < keyend; p++) if (*p == '\n') { *p = 0; nkeys++; } } static struct timeval get_cpu_time (void) { struct rusage usage; struct timeval res; assert (getrusage (RUSAGE_SELF, &usage) == 0); timeradd (&usage.ru_utime, &usage.ru_stime, &res); return res; } int main (int argc, char **argv) { GDBM_FILE dbf; datum key; datum data; int status = 0; int i; int print = 0; unsigned long maxsize = 0; int flags = 0; struct timeval t_start, t_open, t_now, td; char *keystr; int b_opt = 0; while ((i = getopt (argc, argv, "bc:t:nTpVv")) != EOF) { switch (i) { case 'b': b_opt = 1; break; case 'n': flags |= GDBM_NOMMAP; break; case 'p': print = 1; break; case 'c': maxsize = get_size (optarg); break; case 'T': time_verbose = 0; break; case 'v': verbose = 1; break; case 'V': printf ("gdbm header version: %d.%d", GDBM_VERSION_MAJOR, GDBM_VERSION_MINOR); #ifdef GDBM_VERSION_PATCH #if GDBM_VERSION_PATCH > 0 printf (".%d", GDBM_VERSION_PATCH); # endif #endif putchar ('\n'); printf ("gdbm library version: %d.%d", gdbm_version_number[0], gdbm_version_number[1]); if (gdbm_version_number[2]) printf (".%d", gdbm_version_number[2]); putchar ('\n'); exit (0); default: exit (1); } } argc -= optind; argv += optind; switch (argc) { case 2: kfname = argv[1]; case 1: dbname = argv[0]; break; case 0: break; default: fprintf (stderr, "too many arguments\n"); exit (1); } if (verbose) printf ("PID %u\n", getpid ()); #ifdef DUMPSTATS signal (SIGUSR1, sighan); #endif t_start = get_cpu_time (); dbf = gdbm_open (dbname, 0, GDBM_READER | flags, 00664, NULL); assert (dbf != NULL); t_open = get_cpu_time (); if (maxsize) { int rc = gdbm_setopt (dbf, GDBM_SETCACHESIZE, &maxsize, sizeof (maxsize)); if (rc) { fprintf (stderr, "GDBM_SETCACHESIZE: %s\n", gdbm_strerror (gdbm_errno)); return 1; } } readkeys (kfname); i = 0; while ((keystr = nextkey ()) != NULL) { i++; if (verbose) { unsigned long long k = (unsigned long long) i * 100 / nkeys; t_now = get_cpu_time (); timersub (&t_now, &t_start, &td); printf ("%8u %6zu / %6zu % 2d%%\r", td.tv_sec, i, nkeys, k); fflush (stdout); } #ifdef DUMPSTATS if (statsig) { dump_stats (dbf, i); statsig = 0; } #endif key.dptr = keystr; key.dsize = strlen (key.dptr); if (b_opt) { int new_hash_val; /* Computed hash value for the key */ int bucket_dir; /* Number of the bucket in directory. */ int elem_loc; /* The location in the bucket. */ _gdbm_hash_key (dbf, key, &new_hash_val, &bucket_dir, &elem_loc); if (_gdbm_get_bucket (dbf, bucket_dir)) { status = 2; fprintf (stderr, "%s: error: %s\n", keystr, gdbm_strerror (gdbm_errno)); } } else { data = gdbm_fetch (dbf, key); if (data.dptr == NULL) { status = 2; if (gdbm_errno == GDBM_ITEM_NOT_FOUND) { fprintf (stderr, "%s: not found\n", keystr); } else { fprintf (stderr, "%s: error: %s\n", keystr, gdbm_strerror (gdbm_errno)); } } else { if (print) printf ("%s: %*.*s\n", keystr, data.dsize, data.dsize, data.dptr); free (data.dptr); } } } if (verbose) putchar ('\n'); if (time_verbose) { t_now = get_cpu_time (); timersub (&t_now, &t_start, &td); printf ("%lu.%06lu\n", td.tv_sec, td.tv_usec); timersub (&t_open, &t_start, &td); printf ("%lu.%06lu\n", td.tv_sec, td.tv_usec); timersub (&t_now, &t_open, &td); printf ("%lu.%06lu\n", td.tv_sec, td.tv_usec); } gdbm_close (dbf); return status; }