13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier #include <ndb.h>
53e12c5d1SDavid du Colombier
63e12c5d1SDavid du Colombier /*
73e12c5d1SDavid du Colombier * make the hash table completely in memory and then write as a file
83e12c5d1SDavid du Colombier */
93e12c5d1SDavid du Colombier
103e12c5d1SDavid du Colombier uchar *ht;
113e12c5d1SDavid du Colombier ulong hlen;
123e12c5d1SDavid du Colombier Ndb *db;
133e12c5d1SDavid du Colombier ulong nextchain;
143e12c5d1SDavid du Colombier
153e12c5d1SDavid du Colombier char*
syserr(void)163e12c5d1SDavid du Colombier syserr(void)
173e12c5d1SDavid du Colombier {
189a747e4fSDavid du Colombier static char buf[ERRMAX];
193e12c5d1SDavid du Colombier
209a747e4fSDavid du Colombier errstr(buf, sizeof buf);
213e12c5d1SDavid du Colombier return buf;
223e12c5d1SDavid du Colombier }
233e12c5d1SDavid du Colombier
243e12c5d1SDavid du Colombier void
enter(char * val,ulong dboff)253e12c5d1SDavid du Colombier enter(char *val, ulong dboff)
263e12c5d1SDavid du Colombier {
273e12c5d1SDavid du Colombier ulong h;
283e12c5d1SDavid du Colombier uchar *last;
293e12c5d1SDavid du Colombier ulong ptr;
303e12c5d1SDavid du Colombier
313e12c5d1SDavid du Colombier h = ndbhash(val, hlen);
323e12c5d1SDavid du Colombier h *= NDBPLEN;
333e12c5d1SDavid du Colombier last = &ht[h];
343e12c5d1SDavid du Colombier ptr = NDBGETP(last);
353e12c5d1SDavid du Colombier if(ptr == NDBNAP){
363e12c5d1SDavid du Colombier NDBPUTP(dboff, last);
373e12c5d1SDavid du Colombier return;
383e12c5d1SDavid du Colombier }
393e12c5d1SDavid du Colombier
403e12c5d1SDavid du Colombier if(ptr & NDBCHAIN){
413e12c5d1SDavid du Colombier /* walk the chain to the last entry */
423e12c5d1SDavid du Colombier for(;;){
433e12c5d1SDavid du Colombier ptr &= ~NDBCHAIN;
443e12c5d1SDavid du Colombier last = &ht[ptr+NDBPLEN];
453e12c5d1SDavid du Colombier ptr = NDBGETP(last);
463e12c5d1SDavid du Colombier if(ptr == NDBNAP){
473e12c5d1SDavid du Colombier NDBPUTP(dboff, last);
483e12c5d1SDavid du Colombier return;
493e12c5d1SDavid du Colombier }
503e12c5d1SDavid du Colombier if(!(ptr & NDBCHAIN)){
513e12c5d1SDavid du Colombier NDBPUTP(nextchain|NDBCHAIN, last);
523e12c5d1SDavid du Colombier break;
533e12c5d1SDavid du Colombier }
543e12c5d1SDavid du Colombier }
553e12c5d1SDavid du Colombier } else
563e12c5d1SDavid du Colombier NDBPUTP(nextchain|NDBCHAIN, last);
573e12c5d1SDavid du Colombier
583e12c5d1SDavid du Colombier /* add a chained entry */
593e12c5d1SDavid du Colombier NDBPUTP(ptr, &ht[nextchain]);
603e12c5d1SDavid du Colombier NDBPUTP(dboff, &ht[nextchain + NDBPLEN]);
613e12c5d1SDavid du Colombier nextchain += 2*NDBPLEN;
623e12c5d1SDavid du Colombier }
633e12c5d1SDavid du Colombier
64219b2ee8SDavid du Colombier uchar nbuf[16*1024];
653e12c5d1SDavid du Colombier
663e12c5d1SDavid du Colombier void
main(int argc,char ** argv)673e12c5d1SDavid du Colombier main(int argc, char **argv)
683e12c5d1SDavid du Colombier {
693e12c5d1SDavid du Colombier Ndbtuple *t, *nt;
703e12c5d1SDavid du Colombier int n;
719a747e4fSDavid du Colombier Dir *d;
723e12c5d1SDavid du Colombier uchar buf[8];
739a747e4fSDavid du Colombier char file[128];
743e12c5d1SDavid du Colombier int fd;
753e12c5d1SDavid du Colombier ulong off;
763e12c5d1SDavid du Colombier uchar *p;
773e12c5d1SDavid du Colombier
783e12c5d1SDavid du Colombier if(argc != 3){
79*1206f3fcSDavid du Colombier fprint(2, "usage: mkhash file attribute\n");
803e12c5d1SDavid du Colombier exits("usage");
813e12c5d1SDavid du Colombier }
823e12c5d1SDavid du Colombier db = ndbopen(argv[1]);
833e12c5d1SDavid du Colombier if(db == 0){
843e12c5d1SDavid du Colombier fprint(2, "mkhash: can't open %s\n", argv[1]);
853e12c5d1SDavid du Colombier exits(syserr());
863e12c5d1SDavid du Colombier }
87219b2ee8SDavid du Colombier
88219b2ee8SDavid du Colombier /* try a bigger than normal buffer */
89219b2ee8SDavid du Colombier Binits(&db->b, Bfildes(&db->b), OREAD, nbuf, sizeof(nbuf));
903e12c5d1SDavid du Colombier
913e12c5d1SDavid du Colombier /* count entries to calculate hash size */
923e12c5d1SDavid du Colombier n = 0;
93219b2ee8SDavid du Colombier
943e12c5d1SDavid du Colombier while(nt = ndbparse(db)){
953e12c5d1SDavid du Colombier for(t = nt; t; t = t->entry){
967dd7cddfSDavid du Colombier if(strcmp(t->attr, argv[2]) == 0)
973e12c5d1SDavid du Colombier n++;
983e12c5d1SDavid du Colombier }
993e12c5d1SDavid du Colombier ndbfree(nt);
1003e12c5d1SDavid du Colombier }
1013e12c5d1SDavid du Colombier
1023e12c5d1SDavid du Colombier /* allocate an array large enough for worst case */
1033e12c5d1SDavid du Colombier hlen = 2*n+1;
1043e12c5d1SDavid du Colombier n = hlen*NDBPLEN + hlen*2*NDBPLEN;
1057dd7cddfSDavid du Colombier ht = mallocz(n, 1);
1063e12c5d1SDavid du Colombier if(ht == 0){
1073e12c5d1SDavid du Colombier fprint(2, "mkhash: not enough memory\n");
1083e12c5d1SDavid du Colombier exits(syserr());
1093e12c5d1SDavid du Colombier }
110bd389b36SDavid du Colombier for(p = ht; p < &ht[n]; p += NDBPLEN)
111bd389b36SDavid du Colombier NDBPUTP(NDBNAP, p);
112bd389b36SDavid du Colombier nextchain = hlen*NDBPLEN;
1133e12c5d1SDavid du Colombier
1143e12c5d1SDavid du Colombier /* create the in core hash table */
115219b2ee8SDavid du Colombier Bseek(&db->b, 0, 0);
116219b2ee8SDavid du Colombier off = 0;
1173e12c5d1SDavid du Colombier while(nt = ndbparse(db)){
1183e12c5d1SDavid du Colombier for(t = nt; t; t = t->entry){
1193e12c5d1SDavid du Colombier if(strcmp(t->attr, argv[2]) == 0)
1203e12c5d1SDavid du Colombier enter(t->val, off);
1213e12c5d1SDavid du Colombier }
1223e12c5d1SDavid du Colombier ndbfree(nt);
123219b2ee8SDavid du Colombier off = Boffset(&db->b);
1243e12c5d1SDavid du Colombier }
1253e12c5d1SDavid du Colombier
1263e12c5d1SDavid du Colombier /* create the hash file */
127bd389b36SDavid du Colombier snprint(file, sizeof(file), "%s.%s", argv[1], argv[2]);
1283e12c5d1SDavid du Colombier fd = create(file, ORDWR, 0664);
1293e12c5d1SDavid du Colombier if(fd < 0){
1303e12c5d1SDavid du Colombier fprint(2, "mkhash: can't create %s\n", file);
1313e12c5d1SDavid du Colombier exits(syserr());
1323e12c5d1SDavid du Colombier }
133219b2ee8SDavid du Colombier NDBPUTUL(db->mtime, buf);
1343e12c5d1SDavid du Colombier NDBPUTUL(hlen, buf+NDBULLEN);
1353e12c5d1SDavid du Colombier if(write(fd, buf, NDBHLEN) != NDBHLEN){
1363e12c5d1SDavid du Colombier fprint(2, "mkhash: writing %s\n", file);
1373e12c5d1SDavid du Colombier exits(syserr());
1383e12c5d1SDavid du Colombier }
1393e12c5d1SDavid du Colombier if(write(fd, ht, nextchain) != nextchain){
1403e12c5d1SDavid du Colombier fprint(2, "mkhash: writing %s\n", file);
1413e12c5d1SDavid du Colombier exits(syserr());
1423e12c5d1SDavid du Colombier }
1433e12c5d1SDavid du Colombier close(fd);
1443e12c5d1SDavid du Colombier
145219b2ee8SDavid du Colombier /* make sure file didn't change while we were making the hash */
1469a747e4fSDavid du Colombier d = dirstat(argv[1]);
1479a747e4fSDavid du Colombier if(d == nil || d->qid.path != db->qid.path
1489a747e4fSDavid du Colombier || d->qid.vers != db->qid.vers){
149219b2ee8SDavid du Colombier fprint(2, "mkhash: %s changed underfoot\n", argv[1]);
150219b2ee8SDavid du Colombier remove(file);
151219b2ee8SDavid du Colombier exits("changed");
152219b2ee8SDavid du Colombier }
153219b2ee8SDavid du Colombier
1543e12c5d1SDavid du Colombier exits(0);
1553e12c5d1SDavid du Colombier }
156