Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ndb.h>
6 /*
7 * make the hash table completely in memory and then write as a file
8 */
10 uchar *ht;
11 ulong hlen;
12 Ndb *db;
13 ulong nextchain;
15 char*
16 syserr(void)
17 {
18 static char buf[ERRMAX];
20 errstr(buf, sizeof buf);
21 return buf;
22 }
24 void
25 enter(char *val, ulong dboff)
26 {
27 ulong h;
28 uchar *last;
29 ulong ptr;
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 }
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);
58 /* add a chained entry */
59 NDBPUTP(ptr, &ht[nextchain]);
60 NDBPUTP(dboff, &ht[nextchain + NDBPLEN]);
61 nextchain += 2*NDBPLEN;
62 }
64 uchar nbuf[16*1024];
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;
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 }
88 /* try a bigger than normal buffer */
89 Binits(&db->b, Bfildes(&db->b), OREAD, nbuf, sizeof(nbuf));
91 /* count entries to calculate hash size */
92 n = 0;
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);
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());
110 for(p = ht; p < &ht[n]; p += NDBPLEN)
111 NDBPUTP(NDBNAP, p);
112 nextchain = hlen*NDBPLEN;
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);
122 ndbfree(nt);
123 off = Boffset(&db->b);
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());
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());
139 if(write(fd, ht, nextchain) != nextchain){
140 fprint(2, "mkhash: writing %s\n", file);
141 exits(syserr());
143 close(fd);
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");
154 exits(0);