URI:
       tndbmkhash.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tndbmkhash.c (2898B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <ndb.h>
            5 
            6 /*
            7  *  make the hash table completely in memory and then write as a file
            8  */
            9 
           10 uchar *ht;
           11 ulong hlen;
           12 Ndb *db;
           13 ulong nextchain;
           14 
           15 char*
           16 syserr(void)
           17 {
           18         static char buf[ERRMAX];
           19 
           20         errstr(buf, sizeof buf);
           21         return buf;
           22 }
           23 
           24 void
           25 enter(char *val, ulong dboff)
           26 {
           27         ulong h;
           28         uchar *last;
           29         ulong ptr;
           30 
           31         h = ndbhash(val, hlen);
           32         h *= NDBPLEN;
           33         last = &ht[h];
           34         ptr = NDBGETP(last);
           35         if(ptr == NDBNAP){
           36                 NDBPUTP(dboff, last);
           37                 return;
           38         }
           39 
           40         if(ptr & NDBCHAIN){
           41                 /* walk the chain to the last entry */
           42                 for(;;){
           43                         ptr &= ~NDBCHAIN;
           44                         last = &ht[ptr+NDBPLEN];
           45                         ptr = NDBGETP(last);
           46                         if(ptr == NDBNAP){
           47                                 NDBPUTP(dboff, last);
           48                                 return;
           49                         }
           50                         if(!(ptr & NDBCHAIN)){
           51                                 NDBPUTP(nextchain|NDBCHAIN, last);
           52                                 break;
           53                         }
           54                 }
           55         } else
           56                 NDBPUTP(nextchain|NDBCHAIN, last);
           57 
           58         /* add a chained entry */
           59         NDBPUTP(ptr, &ht[nextchain]);
           60         NDBPUTP(dboff, &ht[nextchain + NDBPLEN]);
           61         nextchain += 2*NDBPLEN;
           62 }
           63 
           64 uchar nbuf[16*1024];
           65 
           66 void
           67 main(int argc, char **argv)
           68 {
           69         Ndbtuple *t, *nt;
           70         int n;
           71         Dir *d;
           72         uchar buf[8];
           73         char file[128];
           74         int fd;
           75         ulong off;
           76         uchar *p;
           77 
           78         if(argc != 3){
           79                 fprint(2, "mkhash: usage file attribute\n");
           80                 exits("usage");
           81         }
           82         db = ndbopen(argv[1]);
           83         if(db == 0){
           84                 fprint(2, "mkhash: can't open %s\n", argv[1]);
           85                 exits(syserr());
           86         }
           87 
           88         /* try a bigger than normal buffer */
           89         Binits(&db->b, Bfildes(&db->b), OREAD, nbuf, sizeof(nbuf));
           90 
           91         /* count entries to calculate hash size */
           92         n = 0;
           93 
           94         while(nt = ndbparse(db)){
           95                 for(t = nt; t; t = t->entry){
           96                         if(strcmp(t->attr, argv[2]) == 0)
           97                                 n++;
           98                 }
           99                 ndbfree(nt);
          100         }
          101 
          102         /* allocate an array large enough for worst case */
          103         hlen = 2*n+1;
          104         n = hlen*NDBPLEN + hlen*2*NDBPLEN;
          105         ht = mallocz(n, 1);
          106         if(ht == 0){
          107                 fprint(2, "mkhash: not enough memory\n");
          108                 exits(syserr());
          109         }
          110         for(p = ht; p < &ht[n]; p += NDBPLEN)
          111                 NDBPUTP(NDBNAP, p);
          112         nextchain = hlen*NDBPLEN;
          113 
          114         /* create the in core hash table */
          115         Bseek(&db->b, 0, 0);
          116         off = 0;
          117         while(nt = ndbparse(db)){
          118                 for(t = nt; t; t = t->entry){
          119                         if(strcmp(t->attr, argv[2]) == 0)
          120                                 enter(t->val, off);
          121                 }
          122                 ndbfree(nt);
          123                 off = Boffset(&db->b);
          124         }
          125 
          126         /* create the hash file */
          127         snprint(file, sizeof(file), "%s.%s", argv[1], argv[2]);
          128         fd = create(file, ORDWR, 0664);
          129         if(fd < 0){
          130                 fprint(2, "mkhash: can't create %s\n", file);
          131                 exits(syserr());
          132         }
          133         NDBPUTUL(db->mtime, buf);
          134         NDBPUTUL(hlen, buf+NDBULLEN);
          135         if(write(fd, buf, NDBHLEN) != NDBHLEN){
          136                 fprint(2, "mkhash: writing %s\n", file);
          137                 exits(syserr());
          138         }
          139         if(write(fd, ht, nextchain) != nextchain){
          140                 fprint(2, "mkhash: writing %s\n", file);
          141                 exits(syserr());
          142         }
          143         close(fd);
          144 
          145         /* make sure file didn't change while we were making the hash */
          146         d = dirstat(argv[1]);
          147         if(d == nil || d->qid.path != db->qid.path
          148            || d->qid.vers != db->qid.vers){
          149                 fprint(2, "mkhash: %s changed underfoot\n", argv[1]);
          150                 remove(file);
          151                 exits("changed");
          152         }
          153 
          154         exits(0);
          155 }