package bloomtime;
import jelectrum.DaemonThreadFactory;
import jelectrum.TimeRecord;
import java.util.Set;
import java.util.TreeSet;
import java.util.BitSet;
import java.util.HashMap;
import org.junit.Assert;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.Semaphore;
public class LongBitSetThreaded implements LongBitSet
{
private long file_bits;
private LongFile long_file;
private HashMap<Long, TreeSet<Long> > bits_to_set;
private int in_memory=0;
private long segment_len;
private static final int THREADS=8;
private static final long SEGMENTS=1024;
private static final int MEM_MAX=1000000;
private static ThreadPoolExecutor executor;
public LongBitSetThreaded(LongFile long_file, long file_bits)
{
this.long_file = long_file;
this.file_bits = file_bits;
segment_len = file_bits / SEGMENTS;
bits_to_set = new HashMap<Long, TreeSet<Long> >(2048, 0.6f);
initExec();
}
private static synchronized void initExec()
{
if (executor == null)
{
executor = new ThreadPoolExecutor(THREADS, THREADS, 2, TimeUnit.DAYS,
new LinkedBlockingQueue<Runnable>(), new DaemonThreadFactory());
}
}
public synchronized void setBit(long index)
{
long segment = index / segment_len;
if (!bits_to_set.containsKey(segment))
{
bits_to_set.put(segment, new TreeSet<Long>());
}
bits_to_set.get(segment).add(index);
in_memory++;
if (in_memory >= MEM_MAX)
{
flush();
}
}
public synchronized boolean getBit(long index)
{
long segment = index / segment_len;
if (bits_to_set.containsKey(segment))
{
if (bits_to_set.get(segment).contains(index)) return true;
}
byte[] buff=new byte[1];
long location = index/8;
int bit_in_byte = (int) (index % 8);
long_file.getBytes(location, buff);
BitSet bs = BitSet.valueOf(buff);
return bs.get(bit_in_byte);
}
public BitSet getBitSetRange(long start, int len)
{
Assert.assertEquals(0, start % 8);
int byte_len = len / 8;
if (len % 8 != 0) byte_len++;
byte[] buff = new byte[byte_len];
long location = start / 8;
long_file.getBytes(location, buff);
BitSet bs = BitSet.valueOf(buff);
long segment = start / segment_len;
long end = start + len;
for(long seg = segment; seg * segment_len <= end; seg++)
{
if (bits_to_set.containsKey(seg))
{
Set<Long> moar_bits = bits_to_set.get(seg).subSet(start, start+len);
for(long v : moar_bits)
{
int idx = (int)(v - start);
bs.set(idx);
}
}
}
return bs;
}
/**
* Ensure that all setBit operations are on disk
*/
public synchronized void flush()
{
long t1 = System.nanoTime();
final Semaphore sem = new Semaphore(0);
int count = 0;
for(final Set<Long> bitset : bits_to_set.values())
{
count++;
executor.execute(new Runnable(){
public void run()
{
long t1_flush_seg = System.nanoTime();
byte[] buff = new byte[1];
for(long index : bitset)
{
long location = index/8;
int bit_in_byte = (int) (index % 8);
long_file.getBytes(location, buff);
BitSet bs = BitSet.valueOf(buff);
bs.set(bit_in_byte);
byte[] save = bs.toByteArray();
long_file.putBytes(location, save);
}
sem.release();
TimeRecord.record(t1_flush_seg, "LongBitSetThreaded_flushseg");
}
});
}
TimeRecord.record(t1, "LongBitSetThreaded_flushstart");
try{
sem.acquire(count);
}catch(InterruptedException e){e.printStackTrace();}
bits_to_set.clear();
in_memory = 0;
TimeRecord.record(t1, "LongBitSetThreaded_flush");
}
public void cleanup()
{
flush();
}
}