xref: /plan9/sys/src/cmd/venti/srv/bloom.c (revision c1f17d8f6a55b8f5415c1fba8976f206f9768f00)
1368c31abSDavid du Colombier /*
2368c31abSDavid du Colombier  * Bloom filter tracking which scores are present in our arenas
3368c31abSDavid du Colombier  * and (more importantly) which are not.
4368c31abSDavid du Colombier  */
5368c31abSDavid du Colombier 
6368c31abSDavid du Colombier #include "stdinc.h"
7368c31abSDavid du Colombier #include "dat.h"
8368c31abSDavid du Colombier #include "fns.h"
9368c31abSDavid du Colombier 
10368c31abSDavid du Colombier int ignorebloom;
11368c31abSDavid du Colombier 
12368c31abSDavid du Colombier int
bloominit(Bloom * b,vlong vsize,u8int * data)13368c31abSDavid du Colombier bloominit(Bloom *b, vlong vsize, u8int *data)
14368c31abSDavid du Colombier {
15368c31abSDavid du Colombier 	ulong size;
16368c31abSDavid du Colombier 
17368c31abSDavid du Colombier 	size = vsize;
18368c31abSDavid du Colombier 	if(size != vsize){	/* truncation */
19368c31abSDavid du Colombier 		werrstr("bloom data too big");
20368c31abSDavid du Colombier 		return -1;
21368c31abSDavid du Colombier 	}
22368c31abSDavid du Colombier 
23368c31abSDavid du Colombier 	b->size = size;
24368c31abSDavid du Colombier 	b->nhash = 32;	/* will be fixed by caller on initialization */
25368c31abSDavid du Colombier 	if(data != nil)
26368c31abSDavid du Colombier 		if(unpackbloomhead(b, data) < 0)
27368c31abSDavid du Colombier 			return -1;
28368c31abSDavid du Colombier 
29368c31abSDavid du Colombier 	b->bitmask = (b->size<<3) - 1;
30368c31abSDavid du Colombier 	b->data = data;
31368c31abSDavid du Colombier 	return 0;
32368c31abSDavid du Colombier }
33368c31abSDavid du Colombier 
34368c31abSDavid du Colombier void
wbbloomhead(Bloom * b)35368c31abSDavid du Colombier wbbloomhead(Bloom *b)
36368c31abSDavid du Colombier {
37368c31abSDavid du Colombier 	packbloomhead(b, b->data);
38368c31abSDavid du Colombier }
39368c31abSDavid du Colombier 
40368c31abSDavid du Colombier Bloom*
readbloom(Part * p)41368c31abSDavid du Colombier readbloom(Part *p)
42368c31abSDavid du Colombier {
43368c31abSDavid du Colombier 	uchar buf[512];
44368c31abSDavid du Colombier 	Bloom *b;
45368c31abSDavid du Colombier 
46368c31abSDavid du Colombier 	b = vtmallocz(sizeof *b);
47368c31abSDavid du Colombier 	if(readpart(p, 0, buf, sizeof buf) < 0)
48368c31abSDavid du Colombier 		return nil;
49368c31abSDavid du Colombier 	/*
50368c31abSDavid du Colombier 	 * pass buf as b->data so that bloominit
51368c31abSDavid du Colombier 	 * can parse header.  won't be used for
52368c31abSDavid du Colombier 	 * accessing bits (cleared below).
53368c31abSDavid du Colombier 	 */
54368c31abSDavid du Colombier 	if(bloominit(b, 0, buf) < 0){
55368c31abSDavid du Colombier 		vtfree(b);
56368c31abSDavid du Colombier 		return nil;
57368c31abSDavid du Colombier 	}else{
58368c31abSDavid du Colombier 		/*
59368c31abSDavid du Colombier 		 * default block size is system page size.
60368c31abSDavid du Colombier 		 * the bloom filter is usually very big.
61368c31abSDavid du Colombier 		 * bump the block size up to speed i/o.
62368c31abSDavid du Colombier 		 */
63368c31abSDavid du Colombier 		if(p->blocksize < (1<<20)){
64368c31abSDavid du Colombier 			p->blocksize = 1<<20;
65368c31abSDavid du Colombier 			if(p->blocksize > p->size)
66368c31abSDavid du Colombier 				p->blocksize = p->size;
67368c31abSDavid du Colombier 		}
68368c31abSDavid du Colombier 	}
69368c31abSDavid du Colombier 	b->part = p;
70368c31abSDavid du Colombier 	b->data = nil;
71368c31abSDavid du Colombier 	return b;
72368c31abSDavid du Colombier }
73368c31abSDavid du Colombier 
74368c31abSDavid du Colombier int
resetbloom(Bloom * b)75368c31abSDavid du Colombier resetbloom(Bloom *b)
76368c31abSDavid du Colombier {
77368c31abSDavid du Colombier 	uchar *data;
78368c31abSDavid du Colombier 
79368c31abSDavid du Colombier 	data = vtmallocz(b->size);
80368c31abSDavid du Colombier 	b->data = data;
81368c31abSDavid du Colombier 	if(b->size == MaxBloomSize)	/* 2^32 overflows ulong */
82368c31abSDavid du Colombier 		addstat(StatBloomBits, b->size*8-1);
83368c31abSDavid du Colombier 	else
84368c31abSDavid du Colombier 		addstat(StatBloomBits, b->size*8);
85368c31abSDavid du Colombier 	return 0;
86368c31abSDavid du Colombier }
87368c31abSDavid du Colombier 
88368c31abSDavid du Colombier int
loadbloom(Bloom * b)89368c31abSDavid du Colombier loadbloom(Bloom *b)
90368c31abSDavid du Colombier {
91368c31abSDavid du Colombier 	int i, n;
92368c31abSDavid du Colombier 	uint ones;
93368c31abSDavid du Colombier 	uchar *data;
94368c31abSDavid du Colombier 	u32int *a;
95368c31abSDavid du Colombier 
96368c31abSDavid du Colombier 	data = vtmallocz(b->size);
97368c31abSDavid du Colombier 	if(readpart(b->part, 0, data, b->size) < 0){
98368c31abSDavid du Colombier 		vtfree(b);
99368c31abSDavid du Colombier 		vtfree(data);
100368c31abSDavid du Colombier 		return -1;
101368c31abSDavid du Colombier 	}
102368c31abSDavid du Colombier 	b->data = data;
103368c31abSDavid du Colombier 
104368c31abSDavid du Colombier 	a = (u32int*)b->data;
105368c31abSDavid du Colombier 	n = b->size/4;
106368c31abSDavid du Colombier 	ones = 0;
107368c31abSDavid du Colombier 	for(i=0; i<n; i++)
108368c31abSDavid du Colombier 		ones += countbits(a[i]);
109368c31abSDavid du Colombier 	addstat(StatBloomOnes, ones);
110368c31abSDavid du Colombier 
111368c31abSDavid du Colombier 	if(b->size == MaxBloomSize)	/* 2^32 overflows ulong */
112368c31abSDavid du Colombier 		addstat(StatBloomBits, b->size*8-1);
113368c31abSDavid du Colombier 	else
114368c31abSDavid du Colombier 		addstat(StatBloomBits, b->size*8);
115368c31abSDavid du Colombier 
116368c31abSDavid du Colombier 	return 0;
117368c31abSDavid du Colombier }
118368c31abSDavid du Colombier 
119368c31abSDavid du Colombier int
writebloom(Bloom * b)120368c31abSDavid du Colombier writebloom(Bloom *b)
121368c31abSDavid du Colombier {
122368c31abSDavid du Colombier 	wbbloomhead(b);
123368c31abSDavid du Colombier 	if(writepart(b->part, 0, b->data, b->size) < 0)
124368c31abSDavid du Colombier 		return -1;
125368c31abSDavid du Colombier 	if(flushpart(b->part) < 0)
126368c31abSDavid du Colombier 		return -1;
127368c31abSDavid du Colombier 	return 0;
128368c31abSDavid du Colombier }
129368c31abSDavid du Colombier 
130368c31abSDavid du Colombier /*
131368c31abSDavid du Colombier  * Derive two random 32-bit quantities a, b from the score
132368c31abSDavid du Colombier  * and then use a+b*i as a sequence of bloom filter indices.
133368c31abSDavid du Colombier  * Michael Mitzenmacher has a recent (2005) paper saying this is okay.
134368c31abSDavid du Colombier  * We reserve the bottom bytes (BloomHeadSize*8 bits) for the header.
135368c31abSDavid du Colombier  */
136368c31abSDavid du Colombier static void
gethashes(u8int * score,ulong * h)137368c31abSDavid du Colombier gethashes(u8int *score, ulong *h)
138368c31abSDavid du Colombier {
139368c31abSDavid du Colombier 	int i;
140368c31abSDavid du Colombier 	u32int a, b;
141368c31abSDavid du Colombier 
142368c31abSDavid du Colombier 	a = 0;
143368c31abSDavid du Colombier 	b = 0;
144368c31abSDavid du Colombier 	for(i=4; i+8<=VtScoreSize; i+=8){
145368c31abSDavid du Colombier 		a ^= *(u32int*)(score+i);
146368c31abSDavid du Colombier 		b ^= *(u32int*)(score+i+4);
147368c31abSDavid du Colombier 	}
148368c31abSDavid du Colombier 	if(i+4 <= VtScoreSize)	/* 20 is not 4-aligned */
149368c31abSDavid du Colombier 		a ^= *(u32int*)(score+i);
150368c31abSDavid du Colombier 	for(i=0; i<BloomMaxHash; i++, a+=b)
151368c31abSDavid du Colombier 		h[i] = a < BloomHeadSize*8 ? BloomHeadSize*8 : a;
152368c31abSDavid du Colombier }
153368c31abSDavid du Colombier 
154368c31abSDavid du Colombier static void
_markbloomfilter(Bloom * b,u8int * score)155368c31abSDavid du Colombier _markbloomfilter(Bloom *b, u8int *score)
156368c31abSDavid du Colombier {
157368c31abSDavid du Colombier 	int i, nnew;
158368c31abSDavid du Colombier 	ulong h[BloomMaxHash];
159368c31abSDavid du Colombier 	u32int x, *y, z, *tab;
160368c31abSDavid du Colombier 
161368c31abSDavid du Colombier 	trace("markbloomfilter", "markbloomfilter %V", score);
162368c31abSDavid du Colombier 	gethashes(score, h);
163368c31abSDavid du Colombier 	nnew = 0;
164368c31abSDavid du Colombier 	tab = (u32int*)b->data;
165368c31abSDavid du Colombier 	for(i=0; i<b->nhash; i++){
166368c31abSDavid du Colombier 		x = h[i];
167368c31abSDavid du Colombier 		y = &tab[(x&b->bitmask)>>5];
168368c31abSDavid du Colombier 		z = 1<<(x&31);
169368c31abSDavid du Colombier 		if(!(*y&z)){
170368c31abSDavid du Colombier 			nnew++;
171368c31abSDavid du Colombier 			*y |= z;
172368c31abSDavid du Colombier 		}
173368c31abSDavid du Colombier 	}
174368c31abSDavid du Colombier 	if(nnew)
175368c31abSDavid du Colombier 		addstat(StatBloomOnes, nnew);
176368c31abSDavid du Colombier 
177368c31abSDavid du Colombier 	trace("markbloomfilter", "markbloomfilter exit");
178368c31abSDavid du Colombier }
179368c31abSDavid du Colombier 
180368c31abSDavid du Colombier static int
_inbloomfilter(Bloom * b,u8int * score)181368c31abSDavid du Colombier _inbloomfilter(Bloom *b, u8int *score)
182368c31abSDavid du Colombier {
183368c31abSDavid du Colombier 	int i;
184368c31abSDavid du Colombier 	ulong h[BloomMaxHash], x;
185368c31abSDavid du Colombier 	u32int *tab;
186368c31abSDavid du Colombier 
187368c31abSDavid du Colombier 	gethashes(score, h);
188368c31abSDavid du Colombier 	tab = (u32int*)b->data;
189368c31abSDavid du Colombier 	for(i=0; i<b->nhash; i++){
190368c31abSDavid du Colombier 		x = h[i];
191368c31abSDavid du Colombier 		if(!(tab[(x&b->bitmask)>>5] & (1<<(x&31))))
192368c31abSDavid du Colombier 			return 0;
193368c31abSDavid du Colombier 	}
194368c31abSDavid du Colombier 	return 1;
195368c31abSDavid du Colombier }
196368c31abSDavid du Colombier 
197368c31abSDavid du Colombier int
inbloomfilter(Bloom * b,u8int * score)198368c31abSDavid du Colombier inbloomfilter(Bloom *b, u8int *score)
199368c31abSDavid du Colombier {
200368c31abSDavid du Colombier 	int r;
201368c31abSDavid du Colombier 
202368c31abSDavid du Colombier 	if(b == nil || b->data == nil)
203368c31abSDavid du Colombier 		return 1;
204368c31abSDavid du Colombier 
205368c31abSDavid du Colombier 	if(ignorebloom)
206368c31abSDavid du Colombier 		return 1;
207368c31abSDavid du Colombier 
208368c31abSDavid du Colombier 	rlock(&b->lk);
209368c31abSDavid du Colombier 	r = _inbloomfilter(b, score);
210368c31abSDavid du Colombier 	runlock(&b->lk);
21123566e0cSDavid du Colombier 	addstat(StatBloomLookup, 1);
212368c31abSDavid du Colombier 	if(r)
213368c31abSDavid du Colombier 		addstat(StatBloomMiss, 1);
214368c31abSDavid du Colombier 	else
215368c31abSDavid du Colombier 		addstat(StatBloomHit, 1);
216368c31abSDavid du Colombier 	return r;
217368c31abSDavid du Colombier }
218368c31abSDavid du Colombier 
219368c31abSDavid du Colombier void
markbloomfilter(Bloom * b,u8int * score)220368c31abSDavid du Colombier markbloomfilter(Bloom *b, u8int *score)
221368c31abSDavid du Colombier {
222368c31abSDavid du Colombier 	if(b == nil || b->data == nil)
223368c31abSDavid du Colombier 		return;
224368c31abSDavid du Colombier 
225368c31abSDavid du Colombier 	rlock(&b->lk);
226368c31abSDavid du Colombier 	qlock(&b->mod);
227368c31abSDavid du Colombier 	_markbloomfilter(b, score);
228368c31abSDavid du Colombier 	qunlock(&b->mod);
229368c31abSDavid du Colombier 	runlock(&b->lk);
230368c31abSDavid du Colombier }
231368c31abSDavid du Colombier 
232368c31abSDavid du Colombier static void
bloomwriteproc(void * v)233368c31abSDavid du Colombier bloomwriteproc(void *v)
234368c31abSDavid du Colombier {
235368c31abSDavid du Colombier 	int ret;
236368c31abSDavid du Colombier 	Bloom *b;
237368c31abSDavid du Colombier 
238368c31abSDavid du Colombier 	threadsetname("bloomwriteproc");
239368c31abSDavid du Colombier 	b = v;
240368c31abSDavid du Colombier 	for(;;){
241368c31abSDavid du Colombier 		recv(b->writechan, 0);
242368c31abSDavid du Colombier 		if((ret=writebloom(b)) < 0)
243368c31abSDavid du Colombier 			fprint(2, "oops! writing bloom: %r\n");
244368c31abSDavid du Colombier 		else
245368c31abSDavid du Colombier 			ret = 0;
246368c31abSDavid du Colombier 		sendul(b->writedonechan, ret);
247368c31abSDavid du Colombier 	}
248368c31abSDavid du Colombier }
249368c31abSDavid du Colombier 
250368c31abSDavid du Colombier void
startbloomproc(Bloom * b)251368c31abSDavid du Colombier startbloomproc(Bloom *b)
252368c31abSDavid du Colombier {
253368c31abSDavid du Colombier 	b->writechan = chancreate(sizeof(void*), 0);
254*c1f17d8fSDavid du Colombier 	b->writedonechan = chancreate(sizeof(ulong), 0);
255368c31abSDavid du Colombier 	vtproc(bloomwriteproc, b);
256368c31abSDavid du Colombier }
257