bloom_filter 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -48,6 +48,7 @@ Remote service:
48
48
  * CLI errors
49
49
  * CLI help command
50
50
  * Improve load/dump workflow
51
+ * periodic dumps
51
52
 
52
53
 
53
54
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.1
1
+ 0.6.2
data/bloom_filter.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{bloom_filter}
8
- s.version = "0.6.1"
8
+ s.version = "0.6.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Arya Asemanfar"]
12
- s.date = %q{2010-01-26}
12
+ s.date = %q{2010-01-27}
13
13
  s.default_executable = %q{bloom_filter_server}
14
14
  s.description = %q{}
15
15
  s.email = %q{misterfunnyarsal@gmail.com}
@@ -28,9 +28,11 @@ Gem::Specification.new do |s|
28
28
  "bin/bloom_filter_server",
29
29
  "bloom_filter.gemspec",
30
30
  "lib/bloom_filter.rb",
31
+ "lib/bloom_filter/bit_vector.rb",
31
32
  "lib/bloom_filter/client.rb",
32
33
  "lib/bloom_filter/protocol.rb",
33
34
  "lib/bloom_filter/server.rb",
35
+ "test/bloom_filter_bit_vector_test.rb",
34
36
  "test/bloom_filter_client_test.rb",
35
37
  "test/bloom_filter_server_test.rb",
36
38
  "test/bloom_filter_test.rb",
@@ -42,7 +44,8 @@ Gem::Specification.new do |s|
42
44
  s.rubygems_version = %q{1.3.5}
43
45
  s.summary = %q{A simple BloomFilter implementation, usable in-process or as an EventMachine daemon.}
44
46
  s.test_files = [
45
- "test/bloom_filter_client_test.rb",
47
+ "test/bloom_filter_bit_vector_test.rb",
48
+ "test/bloom_filter_client_test.rb",
46
49
  "test/bloom_filter_server_test.rb",
47
50
  "test/bloom_filter_test.rb",
48
51
  "test/test_helper.rb"
@@ -0,0 +1,48 @@
1
+ class BloomFilter
2
+ class BitVector
3
+ attr_reader :size
4
+
5
+ def initialize(bits, from_str = nil)
6
+ @bytes = Array.new((bits.to_f / 8).ceil, 0)
7
+ @size = bits
8
+
9
+ if from_str
10
+ from_str.size.times do |i|
11
+ @bytes[i] = from_str[i].ord
12
+ end
13
+ end
14
+ end
15
+
16
+ def [](index)
17
+ (@bytes[index.to_i / 8] >> (index % 8)) & 0b1
18
+ end
19
+
20
+ def []=(index, value)
21
+ new_value = value && value != 0 ? 1 : 0
22
+ current_value = self[index]
23
+ if current_value != new_value
24
+ if new_value == 0
25
+ @bytes[index.to_i / 8] -= 1 << (index % 8)
26
+ else
27
+ @bytes[index.to_i / 8] += 1 << (index % 8)
28
+ end
29
+ end
30
+ end
31
+
32
+ def to_s
33
+ str = ""
34
+ @bytes.each { |byte| str << byte.chr }
35
+ str
36
+ end
37
+
38
+ def eql?(o)
39
+ return false unless o.size == self.size
40
+ self.size.times do |i|
41
+ return false unless self[i] == o[i]
42
+ end
43
+ true
44
+ end
45
+ alias_method :==, :eql?
46
+
47
+ end
48
+ end
@@ -1,12 +1,13 @@
1
1
  require 'socket'
2
2
  require 'bloom_filter/protocol'
3
+ require 'bloom_filter/bit_vector'
3
4
 
4
5
  class BloomFilter
5
6
  class Timeout < StandardError; end
6
7
 
7
8
  class Client
8
-
9
9
  PACK_N = "N"
10
+
10
11
  def initialize(host, port, options = {})
11
12
  @host, @port = host, port
12
13
  @timeout = options[:timeout]
@@ -40,10 +41,10 @@ class BloomFilter
40
41
  @socket.write("#{[elements.size + 1].pack(PACK_N)}#{Protocol::INCLUDE_MANY}#{elements}")
41
42
 
42
43
  timeout_or_default(els) do
43
- response = @socket.read(@socket.read(4).unpack(PACK_N).first)
44
+ response = BitVector.new(els.size, @socket.read(@socket.read(4).unpack(PACK_N).first))
44
45
  result = []
45
46
  els.size.times do |i|
46
- result << els[i] if response[i,1] == Protocol::TRUE
47
+ result << els[i] if response[i] == 1
47
48
  end
48
49
  result
49
50
  end
@@ -1,7 +1,6 @@
1
1
  class BloomFilter
2
2
  module Protocol
3
- FALSE = "0"
4
- TRUE = "1"
3
+ TRUE = 1.chr
5
4
  DEFAULT_SEPARATOR = ","
6
5
  ADD = 0
7
6
  INCLUDE = 1
@@ -1,5 +1,6 @@
1
1
  require 'bloom_filter'
2
2
  require 'bloom_filter/protocol'
3
+ require 'bloom_filter/bit_vector'
3
4
  require 'eventmachine'
4
5
 
5
6
 
@@ -86,7 +87,10 @@ class BloomFilter
86
87
  end
87
88
 
88
89
  def write_response(response)
89
- str = Array(response).inject("") { |s, t| s << (t ? Protocol::TRUE : Protocol::FALSE) }
90
+ response = Array(response)
91
+ vector = BitVector.new(response.size)
92
+ response.each_with_index { |t, index| vector[index] = t }
93
+ str = vector.to_s
90
94
  send_data([str.size].pack(PACK_N) + str)
91
95
  end
92
96
  end
@@ -0,0 +1,44 @@
1
+ require 'test_helper'
2
+ require 'bloom_filter/bit_vector'
3
+
4
+ class BloomFilterBitVectorTest < Test::Unit::TestCase
5
+ context "with a bit vector of size 16" do
6
+ setup do
7
+ @bit_vector = BloomFilter::BitVector.new(16)
8
+ end
9
+
10
+ should "return all 0s at first" do
11
+ @bit_vector.size.times do |i|
12
+ fail "returned #{@bit_vector[i]} for bit #{i}" if @bit_vector[i] != 0
13
+ end
14
+ end
15
+
16
+ should "sets bits to 1 and returns 1 when retrieved" do
17
+ @bit_vector.size.times do |i|
18
+ @bit_vector[i] = 1
19
+ assert_equal 1, @bit_vector[i]
20
+ end
21
+ end
22
+
23
+ should "sets bits back to 0" do
24
+ @bit_vector.size.times do |i|
25
+ @bit_vector[i] = 1
26
+ @bit_vector[i] = 0
27
+ assert_equal 0, @bit_vector[i]
28
+ end
29
+ end
30
+
31
+ should "convert the bit vector into a string" do
32
+ assert @bit_vector.to_s.is_a?(String)
33
+ end
34
+
35
+ should "convert back to the same bit vector" do
36
+ [0,3,6,7].each do |bit|
37
+ @bit_vector[bit] = 1
38
+ end
39
+
40
+ assert_equal @bit_vector, BloomFilter::BitVector.new(16, @bit_vector.to_s)
41
+ end
42
+ end
43
+
44
+ end
@@ -13,42 +13,48 @@ class BloomFilterClientTest < Test::Unit::TestCase
13
13
  should "add elements" do
14
14
  @socket.expects(:write).with("#{[6].pack("N")}#{BloomFilter::Protocol::ADD}hello")
15
15
  @socket.expects(:read).with(4).returns([1].pack("N"))
16
- @socket.expects(:read).with(1).returns("1")
16
+ @socket.expects(:read).with(1).returns(BloomFilter::Protocol::TRUE)
17
17
  assert @client.add("hello")
18
18
  end
19
19
 
20
20
  should "check for elements" do
21
21
  @socket.expects(:write).with("#{[6].pack("N")}#{BloomFilter::Protocol::INCLUDE}hello")
22
22
  @socket.expects(:read).with(4).returns([1].pack("N"))
23
- @socket.expects(:read).with(1).returns("1")
23
+ @socket.expects(:read).with(1).returns(BloomFilter::Protocol::TRUE)
24
24
  assert @client.include?("hello")
25
25
  end
26
26
 
27
27
  should "return false for elements that arent there" do
28
28
  @socket.expects(:write).with("#{[4].pack("N")}#{BloomFilter::Protocol::INCLUDE}bye")
29
29
  @socket.expects(:read).with(4).returns([1].pack("N"))
30
- @socket.expects(:read).with(1).returns("0")
30
+ @socket.expects(:read).with(1).returns(0.chr)
31
31
  assert !@client.include?("bye")
32
32
  end
33
33
 
34
34
  should "check for multiple elements" do
35
35
  @socket.expects(:write).with("#{[10].pack("N")}#{BloomFilter::Protocol::INCLUDE_MANY}hello,bye")
36
- @socket.expects(:read).with(4).returns([2].pack("N"))
37
- @socket.expects(:read).with(2).returns("10")
36
+ @socket.expects(:read).with(4).returns([1].pack("N"))
37
+ @socket.expects(:read).with(1).returns(1.chr)
38
38
  assert_equal ["hello"], @client & ["hello", "bye"]
39
+
40
+ @socket.expects(:write).with("#{[10].pack("N")}#{BloomFilter::Protocol::INCLUDE_MANY}bye,hello")
41
+ @socket.expects(:read).with(4).returns([1].pack("N"))
42
+ @socket.expects(:read).with(1).returns(2.chr)
43
+ assert_equal ["hello"], @client & ["bye", "hello"]
44
+
39
45
  end
40
46
 
41
47
  should "send dump" do
42
48
  @socket.expects(:write).with("#{[7].pack("N")}#{BloomFilter::Protocol::DUMP}/tmp/f")
43
49
  @socket.expects(:read).with(4).returns([1].pack("N"))
44
- @socket.expects(:read).with(1).returns("1")
50
+ @socket.expects(:read).with(1).returns(BloomFilter::Protocol::TRUE)
45
51
  assert @client.dump("/tmp/f")
46
52
  end
47
53
 
48
54
  should "send load" do
49
55
  @socket.expects(:write).with("#{[7].pack("N")}#{BloomFilter::Protocol::LOAD}/tmp/f")
50
56
  @socket.expects(:read).with(4).returns([1].pack("N"))
51
- @socket.expects(:read).with(1).returns("1")
57
+ @socket.expects(:read).with(1).returns(BloomFilter::Protocol::TRUE)
52
58
  assert @client.load("/tmp/f")
53
59
  end
54
60
 
@@ -15,22 +15,24 @@ class BloomFilterServerTest < Test::Unit::TestCase
15
15
 
16
16
  should "add elements" do
17
17
  @filter.expects(:add).with("hello")
18
- expects_send_data("#{[1].pack('N')}1")
18
+ expects_send_data("#{[1].pack('N')}#{BloomFilter::Protocol::TRUE}")
19
19
 
20
20
  @server.receive_data("#{[6].pack("N")}#{BloomFilter::Protocol::ADD}hello")
21
21
  end
22
22
 
23
23
  should "check for elements" do
24
24
  @filter.expects(:include?).with("hello").returns(true)
25
- expects_send_data("#{[1].pack("N")}1")
25
+ expects_send_data("#{[1].pack("N")}#{BloomFilter::Protocol::TRUE}")
26
26
  @server.receive_data("#{[6].pack("N")}#{BloomFilter::Protocol::INCLUDE}hello")
27
27
  end
28
28
 
29
29
  should "check for multiple elements" do
30
- @filter.expects(:include?).with("hello").returns(true)
31
- @filter.expects(:include?).with("bye").returns(false)
32
- expects_send_data("#{[2].pack("N")}10")
30
+ @filter.expects(:include?).with("hello").returns(true).twice
31
+ @filter.expects(:include?).with("bye").returns(false).twice
32
+ expects_send_data("#{[1].pack("N")}#{1.chr}") # 1.chr => false, true
33
+ expects_send_data("#{[1].pack("N")}#{2.chr}") # 2.chr => true, false
33
34
  @server.receive_data("#{[10].pack("N")}#{BloomFilter::Protocol::INCLUDE_MANY}hello,bye")
35
+ @server.receive_data("#{[10].pack("N")}#{BloomFilter::Protocol::INCLUDE_MANY}bye,hello")
34
36
  end
35
37
 
36
38
 
@@ -42,7 +44,7 @@ class BloomFilterServerTest < Test::Unit::TestCase
42
44
  File.expects(:open).with(path, 'w').yields(file)
43
45
  file.expects(:write).with("dumped_data")
44
46
 
45
- expects_send_data("#{[1].pack("N")}1")
47
+ expects_send_data("#{[1].pack("N")}#{BloomFilter::Protocol::TRUE}")
46
48
 
47
49
 
48
50
  @server.receive_data("#{[path.size + 1].pack("N")}#{BloomFilter::Protocol::DUMP}#{path}")
@@ -54,7 +56,7 @@ class BloomFilterServerTest < Test::Unit::TestCase
54
56
  @filter.expects(:replace).with(file)
55
57
  File.expects(:open).with(path, 'r').yields(file)
56
58
 
57
- expects_send_data("#{[1].pack("N")}1")
59
+ expects_send_data("#{[1].pack("N")}#{BloomFilter::Protocol::TRUE}")
58
60
 
59
61
  @server.receive_data("#{[path.size + 1].pack("N")}#{BloomFilter::Protocol::LOAD}#{path}")
60
62
  end
@@ -62,7 +64,7 @@ class BloomFilterServerTest < Test::Unit::TestCase
62
64
 
63
65
  should "properly buffer partial messages" do
64
66
  @filter.expects(:add).with("hello")
65
- expects_send_data("#{[1].pack('N')}1")
67
+ expects_send_data("#{[1].pack('N')}#{BloomFilter::Protocol::TRUE}")
66
68
 
67
69
  @server.receive_data("#{[6].pack("N")}#{BloomFilter::Protocol::ADD}hel")
68
70
  @server.receive_data("lo")
@@ -71,7 +73,7 @@ class BloomFilterServerTest < Test::Unit::TestCase
71
73
 
72
74
  should "handle two messages sent at once" do
73
75
  @filter.expects(:add).with("hello")
74
- expects_send_data("#{[1].pack('N')}1").twice()
76
+ expects_send_data("#{[1].pack('N')}#{BloomFilter::Protocol::TRUE}").twice()
75
77
  @filter.expects(:add).with("bye")
76
78
 
77
79
  @server.receive_data("#{[6].pack("N")}#{BloomFilter::Protocol::ADD}hello#{[4].pack("N")}#{BloomFilter::Protocol::ADD}bye")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bloom_filter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arya Asemanfar
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-26 00:00:00 -08:00
12
+ date: 2010-01-27 00:00:00 -08:00
13
13
  default_executable: bloom_filter_server
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -61,9 +61,11 @@ files:
61
61
  - bin/bloom_filter_server
62
62
  - bloom_filter.gemspec
63
63
  - lib/bloom_filter.rb
64
+ - lib/bloom_filter/bit_vector.rb
64
65
  - lib/bloom_filter/client.rb
65
66
  - lib/bloom_filter/protocol.rb
66
67
  - lib/bloom_filter/server.rb
68
+ - test/bloom_filter_bit_vector_test.rb
67
69
  - test/bloom_filter_client_test.rb
68
70
  - test/bloom_filter_server_test.rb
69
71
  - test/bloom_filter_test.rb
@@ -97,6 +99,7 @@ signing_key:
97
99
  specification_version: 3
98
100
  summary: A simple BloomFilter implementation, usable in-process or as an EventMachine daemon.
99
101
  test_files:
102
+ - test/bloom_filter_bit_vector_test.rb
100
103
  - test/bloom_filter_client_test.rb
101
104
  - test/bloom_filter_server_test.rb
102
105
  - test/bloom_filter_test.rb