bloom_filter 0.6.4 → 0.6.5

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.4
1
+ 0.6.5
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.4"
8
+ s.version = "0.6.5"
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-02-01}
12
+ s.date = %q{2010-02-04}
13
13
  s.default_executable = %q{bloom_filter_server}
14
14
  s.description = %q{}
15
15
  s.email = %q{misterfunnyarsal@gmail.com}
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
34
34
  "lib/bloom_filter/server.rb",
35
35
  "test/bloom_filter_bit_vector_test.rb",
36
36
  "test/bloom_filter_client_test.rb",
37
+ "test/bloom_filter_integration_test.rb",
37
38
  "test/bloom_filter_server_test.rb",
38
39
  "test/bloom_filter_test.rb",
39
40
  "test/test_helper.rb"
@@ -46,6 +47,7 @@ Gem::Specification.new do |s|
46
47
  s.test_files = [
47
48
  "test/bloom_filter_bit_vector_test.rb",
48
49
  "test/bloom_filter_client_test.rb",
50
+ "test/bloom_filter_integration_test.rb",
49
51
  "test/bloom_filter_server_test.rb",
50
52
  "test/bloom_filter_test.rb",
51
53
  "test/test_helper.rb"
@@ -4,6 +4,7 @@ require 'bloom_filter/bit_vector'
4
4
 
5
5
  class BloomFilter
6
6
  class Timeout < StandardError; end
7
+ class ConnectionError < StandardError; end
7
8
 
8
9
  class Client
9
10
  PACK_N = "N"
@@ -12,61 +13,59 @@ class BloomFilter
12
13
  @host, @port = host, port
13
14
  @timeout = options[:timeout]
14
15
  @raise_on_timeout = options[:raise_on_timeout] || false
16
+ @raise_on_error = options[:raise_on_error] || false
15
17
  self.connect
16
18
  end
17
19
 
18
20
  def add(el)
19
- self.connect
20
- el = el.to_s
21
- @socket.write("#{[el.size + 1].pack(PACK_N)}#{Protocol::ADD}#{el}")
22
- timeout_or_default(false) do
23
- @socket.read(@socket.read(4).unpack(PACK_N).first) == Protocol::TRUE
21
+ with_socket_or_default(false) do
22
+ el = el.to_s
23
+ @socket.write("#{[el.size + 1].pack(PACK_N)}#{Protocol::ADD}#{el}")
24
+ read_response == Protocol::TRUE
24
25
  end
25
26
  end
26
27
  alias_method :<<, :add
27
28
 
28
29
  def include?(el)
29
- self.connect
30
- el = el.to_s
31
- @socket.write("#{[el.size + 1].pack(PACK_N)}#{Protocol::INCLUDE}#{el}")
32
- timeout_or_default(true) do
33
- @socket.read(@socket.read(4).unpack(PACK_N).first) == Protocol::TRUE
30
+ with_socket_or_default(true) do
31
+ el = el.to_s
32
+ @socket.write("#{[el.size + 1].pack(PACK_N)}#{Protocol::INCLUDE}#{el}")
33
+ read_response == Protocol::TRUE
34
34
  end
35
35
  end
36
36
 
37
37
  def &(els)
38
- self.connect
39
38
  if els.size == 1
40
39
  el = els.first
41
40
  self.include?(el) ? [el] : []
42
41
  else
43
- elements = els.collect { |el| el.to_s }.join(Protocol::DEFAULT_SEPARATOR)
44
- @socket.write("#{[elements.size + 1].pack(PACK_N)}#{Protocol::INCLUDE_MANY}#{elements}")
45
-
46
- timeout_or_default(els) do
47
- response = BitVector.new(els.size, @socket.read(@socket.read(4).unpack(PACK_N).first))
48
- result = []
49
- els.size.times do |i|
50
- result << els[i] if response[i] == 1
51
- end
52
- result
53
- end
42
+ with_socket_or_default(els) do
43
+ elements = els.collect { |el| el.to_s }.join(Protocol::DEFAULT_SEPARATOR)
44
+ @socket.write("#{[elements.size + 1].pack(PACK_N)}#{Protocol::INCLUDE_MANY}#{elements}")
45
+
46
+ read_response do |response|
47
+ response = BitVector.new(els.size, response)
48
+ result = []
49
+ els.size.times do |i|
50
+ result << els[i] if response[i] == 1
51
+ end
52
+ result
53
+ end # read_response
54
+ end # with_socket_or_default
54
55
  end
55
56
  end
56
57
 
57
58
  def dump(path, timeout = nil)
58
- self.connect
59
- @socket.write("#{[path.size + 1].pack(PACK_N)}#{Protocol::DUMP}#{path}")
60
- timeout_or_default(false, timeout) do
61
- @socket.read(@socket.read(4).unpack(PACK_N).first) == Protocol::TRUE
59
+ with_socket_or_default(false) do
60
+ @socket.write("#{[path.size + 1].pack(PACK_N)}#{Protocol::DUMP}#{path}")
61
+ read_response(timeout) == Protocol::TRUE
62
62
  end
63
63
  end
64
64
 
65
65
  def load(path, timeout = nil)
66
- self.connect
67
- @socket.write("#{[path.size + 1].pack(PACK_N)}#{Protocol::LOAD}#{path}")
68
- timeout_or_default(false, timeout) do
69
- @socket.read(@socket.read(4).unpack(PACK_N).first) == Protocol::TRUE
66
+ with_socket_or_default(false) do
67
+ @socket.write("#{[path.size + 1].pack(PACK_N)}#{Protocol::LOAD}#{path}")
68
+ read_response(timeout) == Protocol::TRUE
70
69
  end
71
70
  end
72
71
 
@@ -74,7 +73,7 @@ class BloomFilter
74
73
  unless self.connected?
75
74
  @socket = begin
76
75
  TCPSocket.new(@host, @port)
77
- rescue Exception => e
76
+ rescue Errno::ECONNREFUSED
78
77
  nil
79
78
  end
80
79
  end
@@ -94,15 +93,32 @@ class BloomFilter
94
93
  end
95
94
 
96
95
  private
97
- def timeout_or_default(default, timeout = nil, &block)
96
+ def read_response(timeout = nil, &block)
98
97
  ready = IO.select([@socket], nil, nil, timeout || @timeout)
99
98
  if ready
100
- block.call
101
- elsif @raise_on_timeout
102
- self.disconnect
99
+ size = @socket.read(4)
100
+ raise BloomFilter::ConnectionError if size.nil? || size.length < 4
101
+ size = size.unpack(PACK_N).first
102
+ response = @socket.read(size)
103
+ raise BloomFilter::ConnectionError if response.nil? || response.length < size
104
+ block ? block.call(response) : response
105
+ else
103
106
  raise BloomFilter::Timeout
107
+ end
108
+ end
109
+
110
+ def with_socket_or_default(default, &block)
111
+ self.connect
112
+ if self.connected?
113
+ begin
114
+ yield
115
+ rescue BloomFilter::Timeout
116
+ self.disconnect
117
+ @raise_on_timeout ? raise : default
118
+ rescue BloomFilter::ConnectionError, Errno::EPIPE
119
+ @raise_on_error ? raise : default
120
+ end
104
121
  else
105
- self.disconnect
106
122
  default
107
123
  end
108
124
  end
@@ -110,17 +110,27 @@ class BloomFilterClientTest < Test::Unit::TestCase
110
110
  should "reconnect if not connected before making a call" do
111
111
  socket = mock()
112
112
 
113
- socket.expects(:closed?).returns(true).once
113
+ socket.stubs(:closed?).returns(true, true, false)
114
114
  TCPSocket.expects(:new).with("localhost", 4111).returns(socket).twice
115
115
  IO.stubs(:select).returns(socket)
116
+ socket.stubs(:write, :read)
117
+
116
118
  client = BloomFilter::Client.new("localhost", 4111, :timeout => 1, :raise_on_timeout => true)
117
-
118
- socket.expects(:write).with("#{[6].pack("N")}#{BloomFilter::Protocol::ADD}hello")
119
- socket.expects(:read).with(4).returns([1].pack("N"))
120
- socket.expects(:read).with(1).returns(BloomFilter::Protocol::TRUE)
121
-
122
-
123
- IO.expects(:select).with([socket], nil, nil, 1).returns(socket)
124
119
  client.add("hello")
125
120
  end
121
+
122
+ should "raise exception if set to on conn failure" do
123
+ socket = mock()
124
+
125
+ socket.stubs(:closed?).returns(false)
126
+ TCPSocket.stubs(:new).with("localhost", 4111).returns(socket)
127
+ IO.stubs(:select).returns(socket)
128
+ socket.stubs(:write)
129
+ socket.expects(:read).returns(nil)
130
+
131
+ client = BloomFilter::Client.new("localhost", 4111, :timeout => 1, :raise_on_error => true)
132
+ assert_raises(BloomFilter::ConnectionError) do
133
+ client.add("hello")
134
+ end
135
+ end
126
136
  end
@@ -0,0 +1,42 @@
1
+ require 'test_helper'
2
+ require 'bloom_filter/server'
3
+ require 'bloom_filter/client'
4
+
5
+ class BloomFilterIntegrationTest < Test::Unit::TestCase
6
+ context "with a server listening on port 4111" do
7
+ setup do
8
+ Thread.new do
9
+ EM.run do
10
+ EM.start_server("localhost", 4111, BloomFilter.new_server(1000, 0.05))
11
+ end
12
+ end
13
+ @client = BloomFilter::Client.new("localhost", 4111)
14
+ end
15
+
16
+ should "add an element and return true" do
17
+ assert @client.add("foo")
18
+ end
19
+
20
+ should "add an element and return true after checking for inclusion" do
21
+ @client.add("foo")
22
+ assert @client.include?("foo")
23
+ end
24
+
25
+ should "return false if we haven't added anything" do
26
+ assert !@client.include?("foo")
27
+ end
28
+
29
+ should "intersect with an array and return only the ones that have been added" do
30
+ @client.add 1
31
+ @client.add 2
32
+ @client.add 3
33
+ assert_equal [1,2,3], @client & [1,2,3,4,5]
34
+ end
35
+
36
+ teardown do
37
+ EM.schedule do
38
+ EM.stop
39
+ end
40
+ end
41
+ end
42
+ end
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.4
4
+ version: 0.6.5
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-02-01 00:00:00 -08:00
12
+ date: 2010-02-04 00:00:00 -08:00
13
13
  default_executable: bloom_filter_server
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -67,6 +67,7 @@ files:
67
67
  - lib/bloom_filter/server.rb
68
68
  - test/bloom_filter_bit_vector_test.rb
69
69
  - test/bloom_filter_client_test.rb
70
+ - test/bloom_filter_integration_test.rb
70
71
  - test/bloom_filter_server_test.rb
71
72
  - test/bloom_filter_test.rb
72
73
  - test/test_helper.rb
@@ -101,6 +102,7 @@ summary: A simple BloomFilter implementation, usable in-process or as an EventMa
101
102
  test_files:
102
103
  - test/bloom_filter_bit_vector_test.rb
103
104
  - test/bloom_filter_client_test.rb
105
+ - test/bloom_filter_integration_test.rb
104
106
  - test/bloom_filter_server_test.rb
105
107
  - test/bloom_filter_test.rb
106
108
  - test/test_helper.rb