orestes.bloomfilter.redis.RedisBitSet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bloom-filter Show documentation
Show all versions of bloom-filter Show documentation
Library of different Bloom filters in Java with optional Redis-backing, counting and many hashing options.
The newest version!
package orestes.bloomfilter.redis;
import orestes.bloomfilter.redis.helper.RedisPool;
import redis.clients.jedis.Pipeline;
import redis.clients.util.SafeEncoder;
import java.util.BitSet;
import java.util.List;
import java.util.stream.Stream;
/**
* A persistent BitSet backed by Redis. Not all methods of the superclass are implemented. If needed they can be used
* converting the RedisBitSet to a regular BitSet by calling {@link #asBitSet()}.
External transactions or
* pipeline can be propagated for use by modifying methods (e.g. {@link #set(int)}).
*/
public class RedisBitSet extends BitSet {
private final RedisPool pool;
private String name;
private int size;
/**
* Constructs a new RedisBitSet.
*
* @param pool the redis connection pool
* @param name the name used as key in the database
* @param size the initial size of the RedisBitSet
*/
public RedisBitSet(RedisPool pool, String name, int size) {
this.pool = pool;
this.name = name;
this.size = size;
}
@Override
public boolean get(int bitIndex) {
return pool.allowingSlaves().safelyReturn(jedis -> jedis.getbit(name, bitIndex));
}
/**
* Fetches the values at the given index positions in a multi transaction. This guarantees a consistent view.
*
* @param indexes the index positions to query
* @return an array containing the values at the given index positions
*/
public Boolean[] getBulk(int... indexes) {
List results = pool.allowingSlaves().transactionallyDo(p -> {
for (int index : indexes) {
get(p, index);
}
});
return results.toArray(new Boolean[indexes.length]);
}
@Override
public void set(int bitIndex, boolean value) {
pool.safelyDo(jedis -> jedis.setbit(name, bitIndex, value));
}
public void get(Pipeline p, int position) {
p.getbit(name, position);
}
/**
* Performs the normal {@link #set(int, boolean)} operation using the given pipeline.
*
* @param p the propagated pipeline
* @param bitIndex a bit index
* @param value a boolean value to set
*/
public void set(Pipeline p, int bitIndex, boolean value) {
p.setbit(name, bitIndex, value);
}
@Override
public void set(int bitIndex) {
set(bitIndex, true);
}
@Override
public void clear(int bitIndex) {
set(bitIndex, false);
}
@Override
public void clear() {
pool.safelyDo(jedis -> {
jedis.del(name);
});
}
@Override
public int cardinality() {
return pool.safelyReturn(jedis -> jedis.bitcount(name)).intValue();
}
@Override
public int size() {
return size;
}
@Override
public byte[] toByteArray() {
return pool.allowingSlaves().safelyReturn(jedis -> {
byte[] bytes = jedis.get(SafeEncoder.encode(name));
if (bytes == null) {
//prevent null values
bytes = new byte[(int) Math.ceil(size / 8)];
}
return bytes;
});
}
/**
* Returns the RedisBitSet as a regular BitSet.
*
* @return this RedisBitSet as a regular BitSet
*/
public BitSet asBitSet() {
return fromByteArrayReverse(toByteArray());
}
/**
* Overwrite the contents of this RedisBitSet by the given BitSet.
*
* @param bits a regular BitSet used to overwrite this RedisBitSet
*/
public void overwriteBitSet(BitSet bits) {
pool.safelyDo(jedis -> jedis.set(SafeEncoder.encode(name), toByteArrayReverse(bits)));
}
@Override
public String toString() {
return asBitSet().toString();
}
public String getRedisKey() {
return name;
}
/**
* Tests whether the provided bit positions are all set.
*
* @param positions the positions to test
* @return true if all positions are set
*/
public boolean isAllSet(int... positions) {
Boolean[] results = getBulk(positions);
return Stream.of(results).allMatch(b -> b);
}
/**
* Set all bits
*
* @param positions The positions to set
* @return {@code true} if any of the bits was previously unset.
*/
public boolean setAll(int... positions) {
List