Skip to content

Commit

Permalink
add getbit/setbit (non-counting) redis filter backend
Browse files Browse the repository at this point in the history
  • Loading branch information
igrigorik committed Jan 5, 2011
1 parent cceceee commit cd55541
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 5 deletions.
6 changes: 3 additions & 3 deletions Gemfile.lock
Expand Up @@ -2,14 +2,14 @@ PATH
remote: .
specs:
bloomfilter (1.3.1)
redis
redis (>= 2.1.1)

GEM
remote: http://rubygems.org/
specs:
diff-lcs (1.1.2)
rake (0.8.7)
redis (2.0.5)
redis (2.1.1)
rspec (2.3.0)
rspec-core (~> 2.3.0)
rspec-expectations (~> 2.3.0)
Expand All @@ -25,5 +25,5 @@ PLATFORMS
DEPENDENCIES
bloomfilter!
rake
redis
redis (>= 2.1.1)
rspec
2 changes: 1 addition & 1 deletion bloomfilter.gemspec
Expand Up @@ -13,7 +13,7 @@ Gem::Specification.new do |s|
s.description = s.summary
s.rubyforge_project = "bloomfilter"

s.add_dependency "redis"
s.add_dependency "redis", ">= 2.1.1"
s.add_development_dependency "rspec"
s.add_development_dependency "rake"

Expand Down
3 changes: 2 additions & 1 deletion lib/bloomfilter.rb
Expand Up @@ -5,4 +5,5 @@
require 'bloomfilter/filter'
require 'bloomfilter/native'
require 'bloomfilter/counting_redis'
require 'bloomfilter/version'
require 'bloomfilter/redis'
require 'bloomfilter/version'
63 changes: 63 additions & 0 deletions lib/bloomfilter/redis.rb
@@ -0,0 +1,63 @@
module BloomFilter
class Redis < Filter

def initialize(opts = {})
@opts = {
:size => 100,
:hashes => 4,
:seed => Time.now.to_i,
:bucket => 3,
:ttl => false,
:server => {}
}.merge opts
@db = ::Redis.new(@opts[:server])
end

def insert(key, ttl=nil)
indexes_for(key) { |idx| @db.setbit 'redis', idx, 1 }
end
alias :[]= :insert

def include?(*keys)
keys.each do |key|
indexes_for(key) do |idx|
return false if @db.getbit('redis', idx).zero?
end
end

true
end
alias :key? :include?

def delete(key)
indexes_for(key) do |idx|
@db.setbit 'redis', idx, 0
end
end

def clear
@db.set 'redis', 0
end

def num_set
@db.strlen 'redis'
end
alias :size :num_set

def stats
printf "Number of filter buckets (m): %d\n" % @opts[:size]
printf "Number of filter hashes (k) : %d\n" % @opts[:hashes]
end

private

# compute index offsets for provided key
def indexes_for(key)
indexes = []
@opts[:hashes].times do |i|
yield Zlib.crc32("#{key}:#{i+@opts[:seed]}") % @opts[:size]
end
end

end
end
45 changes: 45 additions & 0 deletions spec/redis_spec.rb
@@ -0,0 +1,45 @@
require 'helper'

describe BloomFilter::Redis do
include BloomFilter

context "use Redis bitstring for storage" do
let(:bf) { Redis.new }

it "should store data in Redis" do
bf.insert(:abcd)
bf.insert('test')
bf.include?('test').should be_true
bf.key?('test').should be_true

bf.include?('test', 'test2').should be_false
bf.include?('test', 'abcd').should be_true
end

it "should delete keys from Redis" do
bf.insert('test')
bf.include?('test').should be_true

bf.delete('test')
bf.include?('test').should be_false
end

it "should clear Redis filter" do
bf.insert('test')
bf.include?('test').should be_true

bf.clear
bf.include?('test').should be_false
end

it "should output current stats" do
bf.clear
bf.insert('test')
lambda { bf.stats }.should_not raise_error
end

it "should connect to remote redis server" do
lambda { Redis.new }.should_not raise_error
end
end
end

0 comments on commit cd55541

Please sign in to comment.