ndbmkhash.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 }