plan9port

[fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port # fast
git clone https://src.adamsgaard.dk/plan9port.git # slow
Log | Files | Refs | README | LICENSE Back to index

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 }