bloom_filter 0.6.4 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
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