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 +1 -1
- data/bloom_filter.gemspec +4 -2
- data/lib/bloom_filter/client.rb +52 -36
- data/test/bloom_filter_client_test.rb +18 -8
- data/test/bloom_filter_integration_test.rb +42 -0
- metadata +4 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.6.
|
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.
|
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-
|
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"
|
data/lib/bloom_filter/client.rb
CHANGED
@@ -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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
67
|
-
|
68
|
-
|
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
|
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
|
96
|
+
def read_response(timeout = nil, &block)
|
98
97
|
ready = IO.select([@socket], nil, nil, timeout || @timeout)
|
99
98
|
if ready
|
100
|
-
|
101
|
-
|
102
|
-
|
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.
|
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
|
+
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-
|
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
|