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[ERRLEN]; 19 20 errstr(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[3*NAMELEN+2]; 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 break; 99 } 100 } 101 ndbfree(nt); 102 } 103 104 /* allocate an array large enough for worst case */ 105 hlen = 2*n+1; 106 n = hlen*NDBPLEN + hlen*2*NDBPLEN; 107 ht = malloc(n); 108 if(ht == 0){ 109 fprint(2, "mkhash: not enough memory\n"); 110 exits(syserr()); 111 } 112 for(p = ht; p < &ht[n]; p += NDBPLEN) 113 NDBPUTP(NDBNAP, p); 114 nextchain = hlen*NDBPLEN; 115 116 /* create the in core hash table */ 117 Bseek(&db->b, 0, 0); 118 off = 0; 119 while(nt = ndbparse(db)){ 120 for(t = nt; t; t = t->entry){ 121 if(strcmp(t->attr, argv[2]) == 0) 122 enter(t->val, off); 123 } 124 ndbfree(nt); 125 off = Boffset(&db->b); 126 } 127 128 /* create the hash file */ 129 snprint(file, sizeof(file), "%s.%s", argv[1], argv[2]); 130 fd = create(file, ORDWR, 0664); 131 if(fd < 0){ 132 fprint(2, "mkhash: can't create %s\n", file); 133 exits(syserr()); 134 } 135 NDBPUTUL(db->mtime, buf); 136 NDBPUTUL(hlen, buf+NDBULLEN); 137 if(write(fd, buf, NDBHLEN) != NDBHLEN){ 138 fprint(2, "mkhash: writing %s\n", file); 139 exits(syserr()); 140 } 141 if(write(fd, ht, nextchain) != nextchain){ 142 fprint(2, "mkhash: writing %s\n", file); 143 exits(syserr()); 144 } 145 close(fd); 146 147 /* make sure file didn't change while we were making the hash */ 148 if(dirstat(argv[1], &d) < 0 || d.qid.path != db->qid.path 149 || d.qid.vers != db->qid.vers){ 150 fprint(2, "mkhash: %s changed underfoot\n", argv[1]); 151 remove(file); 152 exits("changed"); 153 } 154 155 exits(0); 156 } 157