Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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, "usage: mkhash 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
}