bloom_filter 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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