xref: /plan9/sys/src/cmd/ndb/mkhash.c (revision 1206f3fc1b0aab3e32fa15899d31a9b5bfa82d9f)
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