Back to home page

Enduro/X

 
 

    


0001 /* edb_stat.c - memory-mapped database status tool */
0002 /*
0003  * Copyright 2011-2020 Howard Chu, Symas Corp.
0004  * All rights reserved.
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted only as authorized by the OpenLDAP
0008  * Public License.
0009  *
0010  * A copy of this license is available in the file LICENSE in the
0011  * top-level directory of the distribution or, alternatively, at
0012  * <http://www.OpenLDAP.org/license.html>.
0013  */
0014 #include <stdio.h>
0015 #include <stdlib.h>
0016 #include <string.h>
0017 #include <unistd.h>
0018 #include "exdb.h"
0019 
0020 #define Z   EDB_FMT_Z
0021 #define Yu  EDB_PRIy(u)
0022 
0023 static void prstat(EDB_stat *ms)
0024 {
0025 #if 0
0026     printf("  Page size: %u\n", ms->ms_psize);
0027 #endif
0028     printf("  Tree depth: %u\n", ms->ms_depth);
0029     printf("  Branch pages: %"Yu"\n",   ms->ms_branch_pages);
0030     printf("  Leaf pages: %"Yu"\n",     ms->ms_leaf_pages);
0031     printf("  Overflow pages: %"Yu"\n", ms->ms_overflow_pages);
0032     printf("  Entries: %"Yu"\n",        ms->ms_entries);
0033 }
0034 
0035 static void usage(char *prog)
0036 {
0037     fprintf(stderr, "usage: %s [-V] [-n] [-e] [-r[r]] [-f[f[f]]] [-v] [-a|-s subdb] dbpath\n", prog);
0038     exit(EXIT_FAILURE);
0039 }
0040 
0041 int main(int argc, char *argv[])
0042 {
0043     int i, rc;
0044     EDB_env *env;
0045     EDB_txn *txn;
0046     EDB_dbi dbi;
0047     EDB_stat mst;
0048     EDB_envinfo mei;
0049     char *prog = argv[0];
0050     char *envname;
0051     char *subname = NULL;
0052     int alldbs = 0, envinfo = 0, envflags = 0, freinfo = 0, rdrinfo = 0;
0053 
0054     if (argc < 2) {
0055         usage(prog);
0056     }
0057 
0058     /* -a: print stat of main DB and all subDBs
0059      * -s: print stat of only the named subDB
0060      * -e: print env info
0061      * -f: print freelist info
0062      * -r: print reader info
0063      * -n: use NOSUBDIR flag on env_open
0064      * -v: use previous snapshot
0065      * -V: print version and exit
0066      * (default) print stat of only the main DB
0067      */
0068     while ((i = getopt(argc, argv, "Vaefnrs:v")) != EOF) {
0069         switch(i) {
0070         case 'V':
0071             printf("%s\n", EDB_VERSION_STRING);
0072             exit(0);
0073             break;
0074         case 'a':
0075             if (subname)
0076                 usage(prog);
0077             alldbs++;
0078             break;
0079         case 'e':
0080             envinfo++;
0081             break;
0082         case 'f':
0083             freinfo++;
0084             break;
0085         case 'n':
0086             envflags |= EDB_NOSUBDIR;
0087             break;
0088         case 'v':
0089             envflags |= EDB_PREVSNAPSHOT;
0090             break;
0091         case 'r':
0092             rdrinfo++;
0093             break;
0094         case 's':
0095             if (alldbs)
0096                 usage(prog);
0097             subname = optarg;
0098             break;
0099         default:
0100             usage(prog);
0101         }
0102     }
0103 
0104     if (optind != argc - 1)
0105         usage(prog);
0106 
0107     envname = argv[optind];
0108     rc = edb_env_create(&env);
0109     if (rc) {
0110         fprintf(stderr, "edb_env_create failed, error %d %s\n", rc, edb_strerror(rc));
0111         return EXIT_FAILURE;
0112     }
0113 
0114     if (alldbs || subname) {
0115         edb_env_set_maxdbs(env, 4);
0116     }
0117 
0118     rc = edb_env_open(env, envname, envflags | EDB_RDONLY, 0664);
0119     if (rc) {
0120         fprintf(stderr, "edb_env_open failed, error %d %s\n", rc, edb_strerror(rc));
0121         goto env_close;
0122     }
0123 
0124     if (envinfo) {
0125         (void)edb_env_stat(env, &mst);
0126         (void)edb_env_info(env, &mei);
0127         printf("Environment Info\n");
0128         printf("  Map address: %p\n", mei.me_mapaddr);
0129         printf("  Map size: %"Yu"\n", mei.me_mapsize);
0130         printf("  Page size: %u\n", mst.ms_psize);
0131         printf("  Max pages: %"Yu"\n", mei.me_mapsize / mst.ms_psize);
0132         printf("  Number of pages used: %"Yu"\n", mei.me_last_pgno+1);
0133         printf("  Last transaction ID: %"Yu"\n", mei.me_last_txnid);
0134         printf("  Max readers: %u\n", mei.me_maxreaders);
0135         printf("  Number of readers used: %u\n", mei.me_numreaders);
0136     }
0137 
0138     if (rdrinfo) {
0139         printf("Reader Table Status\n");
0140         rc = edb_reader_list(env, (EDB_msg_func *)fputs, stdout);
0141         if (rdrinfo > 1) {
0142             int dead;
0143             edb_reader_check(env, &dead);
0144             printf("  %d stale readers cleared.\n", dead);
0145             rc = edb_reader_list(env, (EDB_msg_func *)fputs, stdout);
0146         }
0147         if (!(subname || alldbs || freinfo))
0148             goto env_close;
0149     }
0150 
0151     rc = edb_txn_begin(env, NULL, EDB_RDONLY, &txn);
0152     if (rc) {
0153         fprintf(stderr, "edb_txn_begin failed, error %d %s\n", rc, edb_strerror(rc));
0154         goto env_close;
0155     }
0156 
0157     if (freinfo) {
0158         EDB_cursor *cursor;
0159         EDB_val key, data;
0160         edb_size_t pages = 0, *iptr;
0161 
0162         printf("Freelist Status\n");
0163         dbi = 0;
0164         rc = edb_cursor_open(txn, dbi, &cursor);
0165         if (rc) {
0166             fprintf(stderr, "edb_cursor_open failed, error %d %s\n", rc, edb_strerror(rc));
0167             goto txn_abort;
0168         }
0169         rc = edb_stat(txn, dbi, &mst);
0170         if (rc) {
0171             fprintf(stderr, "edb_stat failed, error %d %s\n", rc, edb_strerror(rc));
0172             goto txn_abort;
0173         }
0174         prstat(&mst);
0175         while ((rc = edb_cursor_get(cursor, &key, &data, EDB_NEXT)) == 0) {
0176             iptr = data.mv_data;
0177             pages += *iptr;
0178             if (freinfo > 1) {
0179                 char *bad = "";
0180                 edb_size_t pg, prev;
0181                 ssize_t i, j, span = 0;
0182                 j = *iptr++;
0183                 for (i = j, prev = 1; --i >= 0; ) {
0184                     pg = iptr[i];
0185                     if (pg <= prev)
0186                         bad = " [bad sequence]";
0187                     prev = pg;
0188                     pg += span;
0189                     for (; i >= span && iptr[i-span] == pg; span++, pg++) ;
0190                 }
0191                 printf("    Transaction %"Yu", %"Z"d pages, maxspan %"Z"d%s\n",
0192                     *(edb_size_t *)key.mv_data, j, span, bad);
0193                 if (freinfo > 2) {
0194                     for (--j; j >= 0; ) {
0195                         pg = iptr[j];
0196                         for (span=1; --j >= 0 && iptr[j] == pg+span; span++) ;
0197                         printf(span>1 ? "     %9"Yu"[%"Z"d]\n" : "     %9"Yu"\n",
0198                             pg, span);
0199                     }
0200                 }
0201             }
0202         }
0203         edb_cursor_close(cursor);
0204         printf("  Free pages: %"Yu"\n", pages);
0205     }
0206 
0207     rc = edb_open(txn, subname, 0, &dbi);
0208     if (rc) {
0209         fprintf(stderr, "edb_open failed, error %d %s\n", rc, edb_strerror(rc));
0210         goto txn_abort;
0211     }
0212 
0213     rc = edb_stat(txn, dbi, &mst);
0214     if (rc) {
0215         fprintf(stderr, "edb_stat failed, error %d %s\n", rc, edb_strerror(rc));
0216         goto txn_abort;
0217     }
0218     printf("Status of %s\n", subname ? subname : "Main DB");
0219     prstat(&mst);
0220 
0221     if (alldbs) {
0222         EDB_cursor *cursor;
0223         EDB_val key;
0224 
0225         rc = edb_cursor_open(txn, dbi, &cursor);
0226         if (rc) {
0227             fprintf(stderr, "edb_cursor_open failed, error %d %s\n", rc, edb_strerror(rc));
0228             goto txn_abort;
0229         }
0230         while ((rc = edb_cursor_get(cursor, &key, NULL, EDB_NEXT_NODUP)) == 0) {
0231             char *str;
0232             EDB_dbi db2;
0233             if (memchr(key.mv_data, '\0', key.mv_size))
0234                 continue;
0235             str = malloc(key.mv_size+1);
0236             memcpy(str, key.mv_data, key.mv_size);
0237             str[key.mv_size] = '\0';
0238             rc = edb_open(txn, str, 0, &db2);
0239             if (rc == EDB_SUCCESS)
0240                 printf("Status of %s\n", str);
0241             free(str);
0242             if (rc) continue;
0243             rc = edb_stat(txn, db2, &mst);
0244             if (rc) {
0245                 fprintf(stderr, "edb_stat failed, error %d %s\n", rc, edb_strerror(rc));
0246                 goto txn_abort;
0247             }
0248             prstat(&mst);
0249             edb_close(env, db2);
0250         }
0251         edb_cursor_close(cursor);
0252     }
0253 
0254     if (rc == EDB_NOTFOUND)
0255         rc = EDB_SUCCESS;
0256 
0257     edb_close(env, dbi);
0258 txn_abort:
0259     edb_txn_abort(txn);
0260 env_close:
0261     edb_env_close(env);
0262 
0263     return rc ? EXIT_FAILURE : EXIT_SUCCESS;
0264 }