Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/opt/bbmap-39.01-1/current/bloom/KCountArray7MTA.java @ 68:5028fdace37b
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 16:23:26 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 68:5028fdace37b |
---|---|
1 package bloom; | |
2 | |
3 import java.lang.Thread.State; | |
4 import java.util.ArrayList; | |
5 import java.util.Arrays; | |
6 import java.util.Random; | |
7 import java.util.concurrent.atomic.AtomicIntegerArray; | |
8 import java.util.concurrent.locks.Lock; | |
9 import java.util.concurrent.locks.ReentrantLock; | |
10 | |
11 import shared.KillSwitch; | |
12 import shared.Primes; | |
13 import shared.Shared; | |
14 import shared.Timer; | |
15 import shared.Tools; | |
16 import structures.ByteBuilder; | |
17 | |
18 | |
19 /** | |
20 * | |
21 * Uses prime numbers for array lengths. | |
22 * Uses atomic integers for concurrency control. | |
23 * Allows an optional prefilter. | |
24 * | |
25 * @author Brian Bushnell | |
26 * @date Aug 17, 2012 | |
27 * | |
28 */ | |
29 public final class KCountArray7MTA extends KCountArray { | |
30 | |
31 /** | |
32 * | |
33 */ | |
34 private static final long serialVersionUID = 568264681638739631L; | |
35 | |
36 public static void main(String[] args){ | |
37 long cells=Long.parseLong(args[0]); | |
38 int bits=Integer.parseInt(args[1]); | |
39 int hashes=Integer.parseInt(args[2]); | |
40 | |
41 verbose=false; | |
42 | |
43 KCountArray7MTA kca=new KCountArray7MTA(cells, bits, hashes, null, 0); | |
44 | |
45 System.out.println(kca.read(0)); | |
46 kca.increment(0); | |
47 System.out.println(kca.read(0)); | |
48 kca.increment(0); | |
49 System.out.println(kca.read(0)); | |
50 System.out.println(); | |
51 | |
52 System.out.println(kca.read(1)); | |
53 kca.increment(1); | |
54 System.out.println(kca.read(1)); | |
55 kca.increment(1); | |
56 System.out.println(kca.read(1)); | |
57 System.out.println(); | |
58 | |
59 System.out.println(kca.read(100)); | |
60 kca.increment(100); | |
61 System.out.println(kca.read(100)); | |
62 kca.increment(100); | |
63 System.out.println(kca.read(100)); | |
64 kca.increment(100); | |
65 System.out.println(kca.read(100)); | |
66 System.out.println(); | |
67 | |
68 | |
69 System.out.println(kca.read(150)); | |
70 kca.increment(150); | |
71 System.out.println(kca.read(150)); | |
72 System.out.println(); | |
73 | |
74 } | |
75 | |
76 public KCountArray7MTA(long cells_, int bits_, int hashes_, KCountArray prefilter_, int prefilterLimit_){ | |
77 super(getPrimeCells(cells_, bits_), bits_, getDesiredArrays(cells_, bits_)); | |
78 // verbose=false; | |
79 // System.out.println(cells); | |
80 cellsPerArray=cells/numArrays; | |
81 wordsPerArray=(int)((cellsPerArray%cellsPerWord)==0 ? (cellsPerArray/cellsPerWord) : (cellsPerArray/cellsPerWord+1)); | |
82 cellMod=cellsPerArray; | |
83 hashes=hashes_; | |
84 prefilter=prefilter_; | |
85 prefilterLimit=(prefilter==null ? 0 : Tools.min(prefilter.maxValue, prefilterLimit_)); | |
86 // System.out.println("cells="+cells+", words="+words+", wordsPerArray="+wordsPerArray+", numArrays="+numArrays+", hashes="+hashes); | |
87 | |
88 matrix=allocMatrix(numArrays, wordsPerArray); | |
89 | |
90 useLocks=(cellBits>1 && hashes>1) && (LOCKED_INCREMENT || !SET_LOCKED_INCREMENT); | |
91 if(useLocks){ | |
92 locks=new Lock[NUM_LOCKS]; | |
93 for(int i=0; i<NUM_LOCKS; i++){locks[i]=new ReentrantLock();} | |
94 }else{locks=null;} | |
95 | |
96 // matrix=new AtomicIntegerArray[numArrays]; | |
97 // for(int i=0; i<matrix.length; i++){ | |
98 // matrix[i]=new AtomicIntegerArray(wordsPerArray); | |
99 // } | |
100 | |
101 assert(hashes>0 && hashes<=hashMasks.length); | |
102 } | |
103 | |
104 private static int getDesiredArrays(long desiredCells, int bits){ | |
105 | |
106 long words=Tools.max((desiredCells*bits+31)/32, minArrays); | |
107 int arrays=minArrays; | |
108 while(words/arrays>=Integer.MAX_VALUE){ | |
109 arrays*=2; | |
110 } | |
111 // assert(false) : arrays; | |
112 return arrays; | |
113 // return Tools.max(arrays, Data.LOGICAL_PROCESSORS*4); | |
114 } | |
115 | |
116 private static long getPrimeCells(long desiredCells, int bits){ | |
117 | |
118 int arrays=getDesiredArrays(desiredCells, bits); | |
119 | |
120 long x=(desiredCells+arrays-1)/arrays; | |
121 long x2=Primes.primeAtMost(x); | |
122 return x2*arrays; | |
123 } | |
124 | |
125 @Override | |
126 public final int read(final long rawKey){ | |
127 if(verbose){System.err.println("Reading raw key "+rawKey);} | |
128 if(prefilter!=null){ | |
129 int pre=prefilter.read(rawKey); | |
130 if(pre<prefilterLimit){return pre;} | |
131 } | |
132 long key2=hash(rawKey, 0); | |
133 int min=readHashed(key2); | |
134 for(int i=1; i<hashes && min>0; i++){ | |
135 if(verbose){System.err.println("Reading. i="+i+", key2="+key2);} | |
136 key2=Long.rotateRight(key2, hashBits); | |
137 key2=hash(key2, i); | |
138 if(verbose){System.err.println("Rot/hash. i="+i+", key2="+key2);} | |
139 min=min(min, readHashed(key2)); | |
140 } | |
141 return min; | |
142 } | |
143 | |
144 @Override | |
145 public final int read(final long[] rawKeys){ | |
146 if(verbose){System.err.println("Reading raw key "+Arrays.toString(rawKeys));} | |
147 if(prefilter!=null){ | |
148 int pre=prefilter.read(rawKeys); | |
149 if(pre<prefilterLimit){return pre;} | |
150 } | |
151 long key2=hash(rawKeys[0], (int)(1+(rawKeys[0])%5)); | |
152 int min=maxValue; | |
153 for(int i=0; i<hashes; i++){ | |
154 for(int keynum=0; keynum<rawKeys.length; keynum++){ | |
155 if(verbose){System.err.println("Reading. i="+i+", key2="+key2);} | |
156 key2=hash(key2^rawKeys[keynum], i); | |
157 if(verbose){System.err.println("Rot/hash. i="+i+", key2="+key2);} | |
158 } | |
159 min=min(min, readHashed(key2)); | |
160 key2=Long.rotateRight(key2, hashBits); | |
161 } | |
162 return min; | |
163 } | |
164 | |
165 @Override | |
166 public final int readLeft(final long key, final int k, boolean makeCanonical){ | |
167 assert(k<=32); | |
168 final long key2=key>>>2; | |
169 final int shift=2*(k-1); | |
170 final long akey=key2|(0L<<shift); | |
171 final long ckey=key2|(1L<<shift); | |
172 final long gkey=key2|(2L<<shift); | |
173 final long tkey=key2|(3L<<shift); | |
174 final int a=read(makeCanonical ? makeCanonical2(akey, k) : akey); | |
175 final int c=read(makeCanonical ? makeCanonical2(ckey, k) : ckey); | |
176 final int g=read(makeCanonical ? makeCanonical2(gkey, k) : gkey); | |
177 final int t=read(makeCanonical ? makeCanonical2(tkey, k) : tkey); | |
178 return a+c+g+t; | |
179 } | |
180 | |
181 @Override | |
182 public final int readRight(final long key, final int k, boolean makeCanonical){ | |
183 assert(k<=32); | |
184 final long mask=(k>=32 ? -1L : ~((-1L)<<(2*k))); | |
185 final long key2=(key<<2)&mask; | |
186 final long akey=key2|0L; | |
187 final long ckey=key2|1L; | |
188 final long gkey=key2|2L; | |
189 final long tkey=key2|3L; | |
190 final int a=read(makeCanonical ? makeCanonical2(akey, k) : akey); | |
191 final int c=read(makeCanonical ? makeCanonical2(ckey, k) : ckey); | |
192 final int g=read(makeCanonical ? makeCanonical2(gkey, k) : gkey); | |
193 final int t=read(makeCanonical ? makeCanonical2(tkey, k) : tkey); | |
194 return a+c+g+t; | |
195 } | |
196 | |
197 @Override | |
198 public final int[] readAllLeft(final long key, final int k, boolean makeCanonical, int[] rvec){ | |
199 assert(k<=32); | |
200 if(rvec==null){rvec=KillSwitch.allocInt1D(4);} | |
201 final long key2=key>>>2; | |
202 final int shift=2*(k-1); | |
203 final long akey=key2|(0L<<shift); | |
204 final long ckey=key2|(1L<<shift); | |
205 final long gkey=key2|(2L<<shift); | |
206 final long tkey=key2|(3L<<shift); | |
207 rvec[0]=read(makeCanonical ? makeCanonical2(akey, k) : akey); | |
208 rvec[1]=read(makeCanonical ? makeCanonical2(ckey, k) : ckey); | |
209 rvec[2]=read(makeCanonical ? makeCanonical2(gkey, k) : gkey); | |
210 rvec[3]=read(makeCanonical ? makeCanonical2(tkey, k) : tkey); | |
211 return rvec; | |
212 } | |
213 | |
214 @Override | |
215 public final int[] readAllRight(final long key, final int k, boolean makeCanonical, int[] rvec){ | |
216 assert(k<=32); | |
217 final long mask=(k>=32 ? -1L : ~((-1L)<<(2*k))); | |
218 final long key2=(key<<2)&mask; | |
219 final long akey=key2|0L; | |
220 final long ckey=key2|1L; | |
221 final long gkey=key2|2L; | |
222 final long tkey=key2|3L; | |
223 rvec[0]=read(makeCanonical ? makeCanonical2(akey, k) : akey); | |
224 rvec[1]=read(makeCanonical ? makeCanonical2(ckey, k) : ckey); | |
225 rvec[2]=read(makeCanonical ? makeCanonical2(gkey, k) : gkey); | |
226 rvec[3]=read(makeCanonical ? makeCanonical2(tkey, k) : tkey); | |
227 return rvec; | |
228 } | |
229 | |
230 private final int readHashed(long key){ | |
231 if(verbose){System.err.print("Reading hashed key "+key);} | |
232 // System.out.println("key="+key); | |
233 int arrayNum=(int)(key&arrayMask); | |
234 key=(key>>>arrayBits)%(cellMod); | |
235 // key=(key>>>(arrayBits+1))%(cellMod); | |
236 // System.out.println("array="+arrayNum); | |
237 // System.out.println("key2="+key); | |
238 AtomicIntegerArray array=matrix[arrayNum]; | |
239 int index=(int)(key>>>indexShift); | |
240 // assert(false) : indexShift; | |
241 // System.out.println("index="+index); | |
242 int word=array.get(index); | |
243 // System.out.println("word="+Integer.toHexString(word)); | |
244 assert(word>>>(cellBits*key) == word>>>(cellBits*(key&cellMask))); | |
245 // int cellShift=(int)(cellBits*(key&cellMask)); | |
246 int cellShift=(int)(cellBits*key); | |
247 if(verbose){System.err.println(", array="+arrayNum+", index="+index+", cellShift="+(cellShift%32)+", value="+((int)((word>>>cellShift)&valueMask)));} | |
248 // System.out.println("cellShift="+cellShift); | |
249 return (int)((word>>>cellShift)&valueMask); | |
250 } | |
251 | |
252 @Override | |
253 public final void write(final long key, int value){ | |
254 throw new RuntimeException("Not allowed for this class."); | |
255 } | |
256 | |
257 @Override | |
258 public final void increment(long[] keys){ | |
259 // assert(false) : "This method is not really needed."; | |
260 for(int i=0; i<keys.length; i++){ | |
261 increment(keys[i]); | |
262 // keys[i]=hash(keys[i], 0); | |
263 // incrementPartiallyHashed(hash(keys[i], 0)); | |
264 } | |
265 } | |
266 | |
267 @Override | |
268 public final void increment(final long rawKey, final int amt){ | |
269 // if(verbose){System.err.println("\n*** Incrementing raw key "+rawKey+" ***");} | |
270 // | |
271 // if(prefilter!=null){ | |
272 // int x=prefilter.read(rawKey); | |
273 // if(x<prefilterLimit){return;/* x;*/} | |
274 // } | |
275 // | |
276 // if(useLocks){incrementLocked(rawKey, amt);} | |
277 // else{incrementUnlocked(rawKey, amt);} | |
278 incrementAndReturnUnincremented(rawKey, amt); | |
279 } | |
280 | |
281 /* | |
282 private void incrementUnlocked(long rawKey, int amt){ | |
283 long key2=rawKey; | |
284 // int min=maxValue; | |
285 for(int i=0; i<hashes; i++){ | |
286 key2=hash(key2, i); | |
287 if(verbose){System.err.println("key2="+key2+", value="+readHashed(key2));} | |
288 // min=min(min, incrementHashedLocal(key2, amt)); | |
289 incrementHashedLocal(key2, amt); | |
290 key2=Long.rotateRight(key2, hashBits); | |
291 } | |
292 // return min; | |
293 } | |
294 | |
295 private void incrementLocked(long rawKey, int amt){ | |
296 assert(amt>0) : "Don't increment by zero, and negatives should use decrement amt="+amt; | |
297 final Lock lock=getLock(rawKey); | |
298 lock.lock(); | |
299 final int min=read(rawKey); | |
300 final long newMinL=Tools.min(min+amt, maxValue); | |
301 final int newMin=(int)newMinL; | |
302 assert(newMin==newMinL && newMin>0) : newMin+", "+newMinL+", "+min+", "+amt; | |
303 if(newMin<=min){ | |
304 assert(newMin==min) : min; | |
305 lock.unlock(); | |
306 return; | |
307 } | |
308 long key2=rawKey; | |
309 for(int i=0; i<hashes; i++){ | |
310 key2=hash(key2, i); | |
311 if(verbose){System.err.println("key2="+key2+", value="+readHashed(key2));} | |
312 //incrementHashedLocal_ifAtMost(key2, min); | |
313 incrementHashedLocal_toAtLeast(key2, newMin); | |
314 key2=Long.rotateRight(key2, hashBits); | |
315 } | |
316 lock.unlock(); | |
317 // return max(min, newMin); | |
318 } | |
319 */ | |
320 | |
321 @Override | |
322 public final void decrement(final long rawKey, int amt){ | |
323 if(verbose){System.err.println("\n*** Decrementing raw key "+rawKey+" ***");} | |
324 | |
325 assert(prefilter!=null); //Why? | |
326 | |
327 long key2=rawKey; | |
328 // int min=maxValue; | |
329 for(int i=0; i<hashes; i++){ | |
330 key2=hash(key2, i); | |
331 if(verbose){System.err.println("key2="+key2+", value="+readHashed(key2));} | |
332 | |
333 decrementHashedLocal(key2, amt); | |
334 // min=min(min, decrementHashedLocal(key2, amt)); | |
335 key2=Long.rotateRight(key2, hashBits); | |
336 } | |
337 // return min; | |
338 } | |
339 | |
340 @Override | |
341 public int incrementAndReturnUnincremented(final long rawKey, final int incr){ | |
342 | |
343 if(verbose){System.err.println("\n*** Incrementing raw key "+rawKey+" ***");} | |
344 | |
345 if(prefilter!=null){ | |
346 int x=prefilter.read(rawKey); | |
347 if(x<prefilterLimit){return x;} | |
348 } | |
349 | |
350 if(useLocks){return incrementAndReturnUnincrementedLocked(rawKey, incr);} | |
351 else{return incrementAndReturnUnincrementedUnlocked(rawKey, incr);} | |
352 } | |
353 | |
354 private int incrementAndReturnUnincrementedLocked(final long rawKey, final int incr){ | |
355 assert(incr>0) : incr; | |
356 final Lock lock=getLock(rawKey); | |
357 lock.lock(); | |
358 final int min=read(rawKey); | |
359 if(min>=maxValue){ | |
360 lock.unlock(); | |
361 return min; | |
362 } | |
363 final int newMin=(int)Tools.min(min+(long)incr, maxValue); | |
364 long key2=rawKey; | |
365 int value=maxValue; | |
366 for(int i=0; i<hashes; i++){ | |
367 key2=hash(key2, i); | |
368 if(verbose){System.err.println("key2="+key2+", value="+readHashed(key2));} | |
369 int x=incrementHashedLocalAndReturnUnincremented_toAtLeast(key2, newMin); | |
370 value=min(value, x); | |
371 key2=Long.rotateRight(key2, hashBits); | |
372 } | |
373 lock.unlock(); | |
374 return value; | |
375 } | |
376 | |
377 private int incrementAndReturnUnincrementedUnlocked(final long rawKey, final int incr){ | |
378 long key2=rawKey; | |
379 int value=maxValue; | |
380 for(int i=0; i<hashes; i++){ | |
381 key2=hash(key2, i); | |
382 if(verbose){System.err.println("key2="+key2+", value="+readHashed(key2));} | |
383 int x=incrementHashedLocalAndReturnUnincremented(key2, incr); | |
384 value=min(value, x); | |
385 key2=Long.rotateRight(key2, hashBits); | |
386 } | |
387 return value; | |
388 } | |
389 | |
390 @Override | |
391 public int incrementAndReturnUnincremented(final long[] rawKeys, final int incr){ | |
392 | |
393 if(verbose){System.err.println("\n*** Incrementing raw keys "+Arrays.toString(rawKeys)+" ***");} | |
394 | |
395 if(prefilter!=null){ | |
396 int x=prefilter.read(rawKeys); | |
397 if(x<prefilterLimit){return x;} | |
398 } | |
399 | |
400 long key2=hash(rawKeys[0], (int)(1+(rawKeys[0])%5)); | |
401 int value=maxValue; | |
402 for(int i=0; i<hashes; i++){ | |
403 for(int keynum=0; keynum<rawKeys.length; keynum++){ | |
404 key2=hash(key2^rawKeys[keynum], i); | |
405 if(verbose){System.err.println("key2="+key2+", value="+readHashed(key2));} | |
406 } | |
407 int x=incrementHashedLocalAndReturnUnincremented(key2, incr); | |
408 value=min(value, x); | |
409 key2=Long.rotateRight(key2, hashBits); | |
410 } | |
411 // assert(value+1==read(rawKeys) || value==maxValue) : value+", "+read(rawKeys); | |
412 return value; | |
413 } | |
414 | |
415 @Override | |
416 public long[] transformToFrequency(){ | |
417 return transformToFrequency(matrix); | |
418 } | |
419 | |
420 @Override | |
421 public ByteBuilder toContentsString(){ | |
422 ByteBuilder sb=new ByteBuilder(); | |
423 sb.append('['); | |
424 String comma=""; | |
425 for(AtomicIntegerArray array : matrix){ | |
426 for(int i=0; i<array.length(); i++){ | |
427 int word=array.get(i); | |
428 for(int j=0; j<cellsPerWord; j++){ | |
429 int x=word&valueMask; | |
430 sb.append(comma); | |
431 sb.append(x); | |
432 word>>>=cellBits; | |
433 comma=", "; | |
434 } | |
435 } | |
436 } | |
437 sb.append(']'); | |
438 return sb; | |
439 } | |
440 | |
441 @Override | |
442 public double usedFraction(){return cellsUsed()/(double)cells;} | |
443 | |
444 @Override | |
445 public double usedFraction(int mindepth){return cellsUsed(mindepth)/(double)cells;} | |
446 | |
447 @Override | |
448 public long cellsUsed(int mindepth){ | |
449 return cellsUsedMT(mindepth); | |
450 } | |
451 | |
452 public long cellsUsedMT(int mindepth){ | |
453 // assert(false) : matrix.length; | |
454 ArrayList<CountUsedThread> list=new ArrayList<CountUsedThread>(matrix.length); | |
455 for(AtomicIntegerArray aia : matrix){ | |
456 CountUsedThread ctt=new CountUsedThread(aia, mindepth); | |
457 ctt.start(); | |
458 list.add(ctt); | |
459 } | |
460 long x=0; | |
461 for(CountUsedThread ctt : list){ | |
462 while(ctt.getState()!=State.TERMINATED){ | |
463 try { | |
464 ctt.join(); | |
465 } catch (InterruptedException e) { | |
466 // TODO Auto-generated catch block | |
467 e.printStackTrace(); | |
468 } | |
469 } | |
470 x+=ctt.count; | |
471 } | |
472 return x; | |
473 } | |
474 | |
475 private class CountUsedThread extends Thread{ | |
476 public CountUsedThread(AtomicIntegerArray a_, int mindepth_){ | |
477 array=a_; | |
478 mindepth=mindepth_; | |
479 } | |
480 @Override | |
481 public void run(){ | |
482 long temp=0; | |
483 if(array!=null){ | |
484 // System.out.println("C"); | |
485 // assert(false) : Integer.toBinaryString(valueMask); | |
486 if(cellBits==32){ | |
487 for(int i=0, max=array.length(); i<max; i++){ | |
488 int word=array.get(i); | |
489 if(word!=0){ | |
490 int x=word&valueMask; | |
491 if(x>=mindepth){temp++;} | |
492 } | |
493 } | |
494 }else{ | |
495 for(int i=0, max=array.length(); i<max; i++){ | |
496 // System.out.println("D: "+Integer.toHexString(word)); | |
497 int word=array.get(i); | |
498 while(word!=0){ | |
499 int x=word&valueMask; | |
500 // System.out.println("E: "+x+", "+mindepth); | |
501 if(x>=mindepth){temp++;} | |
502 word=word>>>cellBits; | |
503 } | |
504 } | |
505 } | |
506 } | |
507 count=temp; | |
508 } | |
509 private final AtomicIntegerArray array; | |
510 private final int mindepth; | |
511 public long count; | |
512 } | |
513 | |
514 | |
515 @Override | |
516 final long hash(long key, int row){ | |
517 int cell=(int)((Long.MAX_VALUE&key)%(hashArrayLength-1)); | |
518 // int cell=(int)(hashCellMask&(key)); | |
519 | |
520 if(row==0){//Doublehash only first time | |
521 key=key^hashMasks[(row+4)&7][cell]; | |
522 // key=key^hashMasks[4][cell]; | |
523 cell=(int)(hashCellMask&(key>>5)); | |
524 // cell=(int)(hashCellMask&(key>>hashBits)); | |
525 // cell=(int)((Long.MAX_VALUE&key)%(hashArrayLength-1)); | |
526 } | |
527 | |
528 assert(row>=0 && row<hashMasks.length) : row+", "+hashMasks.length; | |
529 assert(cell>=0 && cell<hashMasks[0].length) : cell+", "+hashMasks[0].length; | |
530 return key^hashMasks[row][cell]; | |
531 } | |
532 | |
533 | |
534 // @Override | |
535 // final long hash(long key, int row){ | |
536 // long code=key; | |
537 // for(int i=0; i<6; i++){ | |
538 // int row2=((row+i)&7); | |
539 // int cell=(int)(key&hashCellMask); | |
540 // code^=hashMasks[row2][cell]; | |
541 // key>>=6; | |
542 // } | |
543 // return code; | |
544 // } | |
545 | |
546 /** | |
547 * @param i | |
548 * @param j | |
549 * @return | |
550 */ | |
551 private static long[][] makeMasks(int rows, int cols) { | |
552 | |
553 long seed; | |
554 synchronized(KCountArray7MTA.class){ | |
555 seed=counter^SEEDMASK; | |
556 counter+=7; | |
557 } | |
558 | |
559 Timer t=new Timer(); | |
560 long[][] r=new long[rows][cols]; | |
561 Random randy=Shared.threadLocalRandom(seed); | |
562 for(int i=0; i<r.length; i++){ | |
563 fillMasks(r[i], randy); | |
564 } | |
565 t.stop(); | |
566 if(t.elapsed>200000000L){System.out.println("Mask-creation time: "+t);} | |
567 return r; | |
568 } | |
569 | |
570 private static void fillMasks(long[] r, Random randy) { | |
571 // for(int i=0; i<r.length; i++){ | |
572 // long x=0; | |
573 // while(Long.bitCount(x&0xFFFFFFFF)!=16){ | |
574 // x=randy.nextLong(); | |
575 // } | |
576 // r[i]=(x&Long.MAX_VALUE); | |
577 // } | |
578 | |
579 final int hlen=(1<<hashBits); | |
580 assert(r.length==hlen); | |
581 int[] count1=new int[hlen]; | |
582 int[] count2=new int[hlen]; | |
583 final long mask=hlen-1; | |
584 | |
585 for(int i=0; i<r.length; i++){ | |
586 long x=0; | |
587 int y=0; | |
588 int z=0; | |
589 while(Long.bitCount(x&0xFFFFFFFFL)!=16){ | |
590 x=randy.nextLong(); | |
591 while(Long.bitCount(x&0xFFFFFFFFL)<16){ | |
592 x|=(1L<<randy.nextInt(32)); | |
593 } | |
594 while(Long.bitCount(x&0xFFFFFFFFL)>16){ | |
595 x&=(~(1L<<randy.nextInt(32))); | |
596 } | |
597 while(Long.bitCount(x&0xFFFFFFFF00000000L)<16){ | |
598 x|=(1L<<(randy.nextInt(32)+32)); | |
599 } | |
600 while(Long.bitCount(x&0xFFFFFFFF00000000L)>16){ | |
601 x&=(~(1L<<(randy.nextInt(32)+32))); | |
602 } | |
603 | |
604 // System.out.print("."); | |
605 // y=(((int)(x&mask))^i); | |
606 y=(((int)(x&mask))); | |
607 z=(int)((x>>hashBits)&mask); | |
608 if(count1[y]>0 || count2[z]>0){ | |
609 x=0; | |
610 } | |
611 } | |
612 // System.out.println(Long.toBinaryString(x)); | |
613 r[i]=(x&Long.MAX_VALUE); | |
614 count1[y]++; | |
615 count2[z]++; | |
616 } | |
617 | |
618 } | |
619 | |
620 | |
621 @Override | |
622 public void initialize(){} | |
623 | |
624 @Override | |
625 public void shutdown(){ | |
626 if(finished){return;} | |
627 synchronized(this){ | |
628 if(finished){return;} | |
629 | |
630 cellsUsed=-1; | |
631 // for(int i=0; i<numArrays; i++){ | |
632 // cellsUsed+=cellsUsedPersonal.get(i); | |
633 // } | |
634 cellsUsed(); | |
635 | |
636 assert(!finished); | |
637 finished=true; | |
638 } | |
639 } | |
640 | |
641 private final Lock getLock(long rawKey){ | |
642 final Lock lock=locks[(int)((rawKey&Long.MAX_VALUE)%(NUM_LOCKS))]; | |
643 return lock; | |
644 } | |
645 | |
646 private int incrementHashedLocal(long key, int amt){ | |
647 final int num=(int)(key&arrayMask); | |
648 final AtomicIntegerArray array=matrix[num]; | |
649 key=(key>>>arrayBits)%(cellMod); | |
650 // key=(key>>>(arrayBits+1))%(cellMod); | |
651 int index=(int)(key>>>indexShift); | |
652 int cellShift=(int)(cellBits*key); | |
653 int value, word, word2; | |
654 do{ | |
655 assert(index>=0) : key+", "+cellMod+", "+cellBits+", "+valueMask+", "+arrayMask+", "+index+", "+num; | |
656 word=array.get(index); | |
657 value=((word>>>cellShift)&valueMask); | |
658 value=(int)min(value+(long)amt, maxValue); | |
659 word2=(value<<cellShift)|(word&~((valueMask)<<cellShift)); | |
660 }while(word!=word2 && !array.compareAndSet(index, word, word2)); | |
661 // if(value==1){cellsUsedPersonal.incrementAndGet(num);} | |
662 return value; | |
663 } | |
664 | |
665 // private int incrementHashedLocal_ifAtMost(long key, final int thresh){ | |
666 // final int num=(int)(key&arrayMask); | |
667 // final AtomicIntegerArray array=matrix[num]; | |
668 // key=(key>>>arrayBits)%(cellMod); | |
669 //// key=(key>>>(arrayBits+1))%(cellMod); | |
670 // int index=(int)(key>>>indexShift); | |
671 // int cellShift=(int)(cellBits*key); | |
672 // int value, word, word2; | |
673 // do{ | |
674 // assert(index>=0) : key+", "+cellMod+", "+cellBits+", "+valueMask+", "+arrayMask+", "+index+", "+num; | |
675 // word=array.get(index); | |
676 // value=((word>>>cellShift)&valueMask); | |
677 // if(value>thresh){return value;}//Too high; don't increment | |
678 // value=min(value+1, maxValue); | |
679 // word2=(value<<cellShift)|(word&~((valueMask)<<cellShift)); | |
680 // }while(word!=word2 && !array.compareAndSet(index, word, word2)); | |
681 // return value; | |
682 // } | |
683 | |
684 private int incrementHashedLocal_toAtLeast(long key, final int newMin){ | |
685 assert(newMin<=maxValue); | |
686 final int num=(int)(key&arrayMask); | |
687 final AtomicIntegerArray array=matrix[num]; | |
688 key=(key>>>arrayBits)%(cellMod); | |
689 // key=(key>>>(arrayBits+1))%(cellMod); | |
690 int index=(int)(key>>>indexShift); | |
691 int cellShift=(int)(cellBits*key); | |
692 int value, word, word2; | |
693 do{ | |
694 assert(index>=0) : key+", "+cellMod+", "+cellBits+", "+valueMask+", "+arrayMask+", "+index+", "+num; | |
695 word=array.get(index); | |
696 value=((word>>>cellShift)&valueMask); | |
697 if(value>=newMin){return value;}//Too high; don't increment | |
698 value=min(value+1, maxValue); | |
699 word2=(value<<cellShift)|(word&~((valueMask)<<cellShift)); | |
700 }while(word!=word2 && !array.compareAndSet(index, word, word2)); | |
701 return value; | |
702 } | |
703 | |
704 private int incrementHashedLocalAndReturnUnincremented(long key, int incr){ | |
705 assert(incr>=0); | |
706 final int num=(int)(key&arrayMask); | |
707 final AtomicIntegerArray array=matrix[num]; | |
708 key=(key>>>arrayBits)%(cellMod); | |
709 // key=(key>>>(arrayBits+1))%(cellMod); | |
710 int index=(int)(key>>>indexShift); | |
711 int cellShift=(int)(cellBits*key); | |
712 int value, word, word2; | |
713 do{ | |
714 word=array.get(index); | |
715 value=((word>>>cellShift)&valueMask); | |
716 int value2=min(value+incr, maxValue); | |
717 word2=(value2<<cellShift)|(word&~((valueMask)<<cellShift)); | |
718 }while(word!=word2 && !array.compareAndSet(index, word, word2)); | |
719 // if(value==1){cellsUsedPersonal.incrementAndGet(num);} | |
720 return value; | |
721 } | |
722 | |
723 // private int incrementHashedLocalAndReturnUnincremented_ifAtMost(long key, int incr, final int thresh){ | |
724 // assert(incr>=0); | |
725 // final int num=(int)(key&arrayMask); | |
726 // final AtomicIntegerArray array=matrix[num]; | |
727 // key=(key>>>arrayBits)%(cellMod); | |
728 //// key=(key>>>(arrayBits+1))%(cellMod); | |
729 // int index=(int)(key>>>indexShift); | |
730 // int cellShift=(int)(cellBits*key); | |
731 // int value, word, word2; | |
732 // do{ | |
733 // word=array.get(index); | |
734 // value=((word>>>cellShift)&valueMask); | |
735 // if(value>thresh){return value;}//Too high; don't increment | |
736 // int value2=min(value+incr, maxValue); | |
737 // word2=(value2<<cellShift)|(word&~((valueMask)<<cellShift)); | |
738 // }while(word!=word2 && !array.compareAndSet(index, word, word2)); | |
739 //// if(value==1){cellsUsedPersonal.incrementAndGet(num);} | |
740 // return value; | |
741 // } | |
742 | |
743 private int incrementHashedLocalAndReturnUnincremented_toAtLeast(long key, int newMin){ | |
744 assert(newMin>0 && newMin<=maxValue) : newMin; | |
745 final int num=(int)(key&arrayMask); | |
746 final AtomicIntegerArray array=matrix[num]; | |
747 key=(key>>>arrayBits)%(cellMod); | |
748 // key=(key>>>(arrayBits+1))%(cellMod); | |
749 int index=(int)(key>>>indexShift); | |
750 int cellShift=(int)(cellBits*key); | |
751 int value, word, word2; | |
752 final int value2s=newMin<<cellShift; | |
753 do{ | |
754 word=array.get(index); | |
755 value=((word>>>cellShift)&valueMask); | |
756 if(value>=newMin){return value;}//Too high; don't increment | |
757 word2=value2s|(word&~((valueMask)<<cellShift)); | |
758 }while(word!=word2 && !array.compareAndSet(index, word, word2)); | |
759 // if(value==1){cellsUsedPersonal.incrementAndGet(num);} | |
760 return value; | |
761 } | |
762 | |
763 private int decrementHashedLocal(long key, int amt){ | |
764 final int num=(int)(key&arrayMask); | |
765 final AtomicIntegerArray array=matrix[num]; | |
766 key=(key>>>arrayBits)%(cellMod); | |
767 // key=(key>>>(arrayBits+1))%(cellMod); | |
768 int index=(int)(key>>>indexShift); | |
769 int cellShift=(int)(cellBits*key); | |
770 int value, word, word2; | |
771 do{ | |
772 word=array.get(index); | |
773 value=((word>>>cellShift)&valueMask); | |
774 value=max(value-amt, 0); | |
775 word2=(value<<cellShift)|(word&~((valueMask)<<cellShift)); | |
776 }while(word!=word2 && !array.compareAndSet(index, word, word2)); | |
777 // if(value==1){cellsUsedPersonal.incrementAndGet(num);} | |
778 return value; | |
779 } | |
780 | |
781 public long cellsUsed(){ | |
782 if(cellsUsed<0){ | |
783 synchronized(this){ | |
784 if(cellsUsed<0){ | |
785 cellsUsed=cellsUsed(1); | |
786 } | |
787 } | |
788 } | |
789 return cellsUsed; | |
790 } | |
791 | |
792 @Override | |
793 public KCountArray prefilter(){ | |
794 return prefilter; | |
795 } | |
796 | |
797 @Override | |
798 public void purgeFilter(){ | |
799 prefilter=null; | |
800 } | |
801 | |
802 public static synchronized void setSeed(long seed){ | |
803 if(seed>=0){SEEDMASK=seed;} | |
804 else{ | |
805 Random randy=new Random(); | |
806 SEEDMASK=randy.nextLong(); | |
807 } | |
808 } | |
809 | |
810 private boolean finished=false; | |
811 | |
812 private long cellsUsed; | |
813 private final AtomicIntegerArray[] matrix; | |
814 private final int hashes; | |
815 private final int wordsPerArray; | |
816 private final long cellsPerArray; | |
817 private final long cellMod; | |
818 private final long[][] hashMasks=makeMasks(8, hashArrayLength); | |
819 private final int prefilterLimit; | |
820 | |
821 private static final int hashBits=6; | |
822 private static final int hashArrayLength=1<<hashBits; | |
823 private static final int hashCellMask=hashArrayLength-1; | |
824 | |
825 private KCountArray prefilter; | |
826 | |
827 private final transient boolean useLocks; | |
828 private final transient Lock[] locks; | |
829 private static final transient int NUM_LOCKS=1999; | |
830 | |
831 private static long counter=0; | |
832 private static long SEEDMASK=0; | |
833 | |
834 } |