fraggle 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +30 -44
- data/bench/gets.rb +32 -0
- data/lib/fraggle/client.rb +33 -68
- data/lib/fraggle/connection.rb +11 -26
- data/lib/fraggle/response.rb +0 -4
- data/lib/fraggle/version.rb +1 -1
- data/test/fraggle_client_test.rb +25 -47
- data/test/fraggle_protocol_test.rb +2 -2
- data/test/fraggle_transaction_test.rb +41 -65
- data/test/helper.rb +19 -13
- metadata +5 -12
- data/example/getdir.rb +0 -58
- data/example/readonly.rb +0 -28
- data/example/resend.rb +0 -26
- data/example/rev.rb +0 -15
- data/example/set.rb +0 -20
- data/example/stat.rb +0 -19
- data/example/walk.rb +0 -29
- data/lib/fraggle/request.rb +0 -36
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Fraggle (
|
1
|
+
# Fraggle (v3.0.0 is compatible with Doozer 0.6)
|
2
2
|
|
3
3
|
Fraggle currently is only a raw interface to Doozer 0.6.
|
4
4
|
Sugar for `WALK`, `GETDIR`, etc are to come in v3.0.0.
|
@@ -7,7 +7,7 @@ Sugar for `WALK`, `GETDIR`, etc are to come in v3.0.0.
|
|
7
7
|
|
8
8
|
## Install
|
9
9
|
|
10
|
-
$ gem install fraggle
|
10
|
+
$ gem install fraggle
|
11
11
|
|
12
12
|
## Use
|
13
13
|
|
@@ -16,65 +16,51 @@ Sugar for `WALK`, `GETDIR`, etc are to come in v3.0.0.
|
|
16
16
|
require 'fraggle'
|
17
17
|
|
18
18
|
EM.start do
|
19
|
-
#
|
20
|
-
# connected. In the event of a lost connection, fraggle will attempt
|
19
|
+
# In the event of a lost connection, fraggle will attempt
|
21
20
|
# other doozers until one accepts or it runs out of options; A NoAddrs
|
22
21
|
# exception will be raised if that later happens.
|
23
22
|
c = Fraggle.connect "doozerd://127.0.0.1:8046"
|
24
23
|
|
25
24
|
req = c.get("/foo") do |e|
|
26
|
-
e.
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
25
|
+
if e.ok?
|
26
|
+
e.value # => nil
|
27
|
+
e.rev # => 0
|
28
|
+
e.missing? # => true
|
29
|
+
else
|
30
|
+
e.err_code # => Fraggle::<CONST>
|
31
|
+
e.err_detail # => "bad path" or something
|
32
|
+
end
|
33
33
|
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
# Phoney check for example
|
49
|
-
if can_stop_watching?(path)
|
50
|
-
watch.cancel
|
35
|
+
c.rev do |v|
|
36
|
+
## Obtain the current revision the store is at and watch from then on for
|
37
|
+
## any SET or DEL to /foo.
|
38
|
+
c.wait("/foo", v.rev) do |e|
|
39
|
+
# The event has:
|
40
|
+
# ------------------------
|
41
|
+
e.err_code # => nil
|
42
|
+
e.err_detail # => nil
|
43
|
+
e.path # => "/foo"
|
44
|
+
e.value # => "zomg!"
|
45
|
+
e.rev # => 123
|
46
|
+
e.set? # => true
|
47
|
+
e.del? # => false
|
51
48
|
end
|
52
49
|
end
|
53
50
|
|
54
51
|
## Setting a key (this will trigger the watch above)
|
55
52
|
req = c.set("/foo", "zomg!", 0) do |e|
|
56
53
|
# Success!
|
57
|
-
|
58
|
-
|
59
|
-
#
|
54
|
+
case e.err_code
|
55
|
+
when Fraggle::REV_MISMATCH
|
56
|
+
# We didn't win
|
57
|
+
when nil
|
58
|
+
# Success!
|
60
59
|
else
|
61
|
-
|
60
|
+
fail "something bad happened"
|
62
61
|
end
|
63
62
|
end
|
64
63
|
|
65
|
-
# Knowning when a command is done is useful in some cases.
|
66
|
-
# Use the `done` callback for those situations.
|
67
|
-
ents = []
|
68
|
-
c.getdir("/test") do |e|
|
69
|
-
ents << e
|
70
|
-
end.done do
|
71
|
-
p ents
|
72
|
-
end
|
73
|
-
|
74
|
-
c.get("/nothere") do |e|
|
75
|
-
e.missing? # => true
|
76
|
-
end
|
77
|
-
|
78
64
|
end
|
79
65
|
|
80
66
|
## Consistency
|
data/bench/gets.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'fraggle'
|
4
|
+
|
5
|
+
reqs = 0
|
6
|
+
|
7
|
+
def rget(c, path, rev, &blk)
|
8
|
+
c.get(path, rev) do |e|
|
9
|
+
blk.call
|
10
|
+
rget(c, path, rev, &blk)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
EM.run do
|
15
|
+
c = Fraggle.connect
|
16
|
+
|
17
|
+
EM.add_timer(1) do
|
18
|
+
# The primer is done. Reset `reqs` and do it for real.
|
19
|
+
reqs = 0
|
20
|
+
EM.add_timer(1) do
|
21
|
+
EM.stop_event_loop
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
c.rev do |v|
|
26
|
+
rget(c, "/ctl/cal/0", v.rev) do
|
27
|
+
reqs += 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
puts "Result (GET): #{reqs}/sec"
|
data/lib/fraggle/client.rb
CHANGED
@@ -28,9 +28,8 @@ module Fraggle
|
|
28
28
|
req.rev = rev
|
29
29
|
req.path = path
|
30
30
|
req.value = value
|
31
|
-
req.valid(&blk)
|
32
31
|
|
33
|
-
idemp(req)
|
32
|
+
idemp(req, &blk)
|
34
33
|
end
|
35
34
|
|
36
35
|
def get(path, rev=nil, &blk)
|
@@ -38,9 +37,8 @@ module Fraggle
|
|
38
37
|
req.verb = GET
|
39
38
|
req.rev = rev
|
40
39
|
req.path = path
|
41
|
-
req.valid(&blk)
|
42
40
|
|
43
|
-
resend(req)
|
41
|
+
resend(req, &blk)
|
44
42
|
end
|
45
43
|
|
46
44
|
def del(path, rev, &blk)
|
@@ -48,9 +46,8 @@ module Fraggle
|
|
48
46
|
req.verb = DEL
|
49
47
|
req.rev = rev
|
50
48
|
req.path = path
|
51
|
-
req.valid(&blk)
|
52
49
|
|
53
|
-
idemp(req)
|
50
|
+
idemp(req, &blk)
|
54
51
|
end
|
55
52
|
|
56
53
|
def getdir(path, rev=nil, offset=nil, &blk)
|
@@ -59,9 +56,8 @@ module Fraggle
|
|
59
56
|
req.rev = rev
|
60
57
|
req.path = path
|
61
58
|
req.offset = offset
|
62
|
-
req.valid(&blk)
|
63
59
|
|
64
|
-
resend(req)
|
60
|
+
resend(req, &blk)
|
65
61
|
end
|
66
62
|
|
67
63
|
def walk(path, rev=nil, offset=nil, &blk)
|
@@ -70,9 +66,8 @@ module Fraggle
|
|
70
66
|
req.rev = rev
|
71
67
|
req.path = path
|
72
68
|
req.offset = offset
|
73
|
-
req.valid(&blk)
|
74
69
|
|
75
|
-
resend(req)
|
70
|
+
resend(req, &blk)
|
76
71
|
end
|
77
72
|
|
78
73
|
def wait(path, rev=nil, &blk)
|
@@ -80,17 +75,15 @@ module Fraggle
|
|
80
75
|
req.verb = WAIT
|
81
76
|
req.rev = rev
|
82
77
|
req.path = path
|
83
|
-
req.valid(&blk)
|
84
78
|
|
85
|
-
resend(req)
|
79
|
+
resend(req, &blk)
|
86
80
|
end
|
87
81
|
|
88
82
|
def rev(&blk)
|
89
83
|
req = Request.new
|
90
84
|
req.verb = REV
|
91
|
-
req.valid(&blk)
|
92
85
|
|
93
|
-
resend(req)
|
86
|
+
resend(req, &blk)
|
94
87
|
end
|
95
88
|
|
96
89
|
def stat(path, rev=nil, &blk)
|
@@ -98,27 +91,16 @@ module Fraggle
|
|
98
91
|
req.rev = rev
|
99
92
|
req.verb = STAT
|
100
93
|
req.path = path
|
101
|
-
req.valid(&blk)
|
102
94
|
|
103
|
-
resend(req)
|
95
|
+
resend(req, &blk)
|
104
96
|
end
|
105
97
|
|
106
98
|
# Sends a request to the server. Returns the request with a new tag
|
107
|
-
# assigned.
|
108
|
-
|
109
|
-
|
110
|
-
wr = Request.new(req.to_hash)
|
111
|
-
|
112
|
-
wr.valid do |e|
|
99
|
+
# assigned.
|
100
|
+
def send(req, &blk)
|
101
|
+
cb = Proc.new do |e|
|
113
102
|
log.debug("response: #{e.inspect} for #{req.inspect}")
|
114
|
-
req.emit(:valid, e)
|
115
|
-
end
|
116
103
|
|
117
|
-
wr.done do
|
118
|
-
req.emit(:done)
|
119
|
-
end
|
120
|
-
|
121
|
-
wr.error do |e|
|
122
104
|
case true
|
123
105
|
when e.disconnected?
|
124
106
|
# If we haven't already reconnected, do so.
|
@@ -126,63 +108,46 @@ module Fraggle
|
|
126
108
|
log.error("conn err: #{req.inspect}")
|
127
109
|
reconnect!
|
128
110
|
end
|
129
|
-
|
130
|
-
if onre
|
131
|
-
# Someone else will handle this
|
132
|
-
onre.call
|
133
|
-
else
|
134
|
-
req.emit(:error, e)
|
135
|
-
end
|
136
|
-
when e.readonly?
|
137
|
-
|
138
|
-
log.error("readonly: #{req.inspect}")
|
139
|
-
|
140
|
-
# Closing the connection triggers a reconnect above.
|
141
|
-
cn.close_connection
|
142
|
-
|
143
|
-
if onre
|
144
|
-
# Someone else will handle this
|
145
|
-
onre.call
|
146
|
-
else
|
147
|
-
req.emit(:error, Connection::Disconnected)
|
148
|
-
end
|
149
|
-
else
|
150
|
-
log.error("error: #{e.inspect} for #{req.inspect}")
|
151
|
-
req.emit(:error, e)
|
152
111
|
end
|
153
112
|
|
113
|
+
blk.call(e)
|
154
114
|
end
|
155
115
|
|
156
|
-
wr = cn.send_request(wr)
|
157
|
-
req.tag = wr.tag
|
158
116
|
log.debug("sending: #{req.inspect}")
|
159
|
-
|
160
|
-
req
|
117
|
+
cn.send_request(req, cb)
|
161
118
|
end
|
162
119
|
|
163
|
-
def resend(req)
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
120
|
+
def resend(req, &blk)
|
121
|
+
cb = Proc.new do |e|
|
122
|
+
if e.disconnected?
|
123
|
+
req.tag = nil
|
124
|
+
log.debug("resending: #{req.inspect}")
|
125
|
+
resend(req, &blk)
|
126
|
+
else
|
127
|
+
blk.call(e)
|
128
|
+
end
|
168
129
|
end
|
130
|
+
|
131
|
+
send(req, &cb)
|
169
132
|
end
|
170
133
|
|
171
|
-
def idemp(req)
|
172
|
-
|
173
|
-
if req.rev > 0
|
134
|
+
def idemp(req, &blk)
|
135
|
+
cb = Proc.new do |e|
|
136
|
+
if e.disconnected? && req.rev > 0
|
174
137
|
# If we're trying to update a value that isn't missing or that we're
|
175
138
|
# not trying to clobber, it's safe to retry. We can't idempotently
|
176
139
|
# update missing values because there may be a race with another
|
177
140
|
# client that sets and/or deletes the key during the time between your
|
178
141
|
# read and write.
|
179
142
|
req.tag = nil
|
180
|
-
idemp(req)
|
181
|
-
|
182
|
-
# We can't safely retry the write. Inform the user.
|
183
|
-
req.emit(:error, Connection::Disconnected)
|
143
|
+
idemp(req, &blk)
|
144
|
+
next
|
184
145
|
end
|
146
|
+
|
147
|
+
blk.call(e)
|
185
148
|
end
|
149
|
+
|
150
|
+
send(req, &cb)
|
186
151
|
end
|
187
152
|
|
188
153
|
def reconnect!
|
data/lib/fraggle/connection.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'fraggle/request'
|
2
1
|
require 'fraggle/response'
|
3
2
|
|
4
3
|
module Fraggle
|
@@ -23,15 +22,13 @@ module Fraggle
|
|
23
22
|
end
|
24
23
|
|
25
24
|
|
26
|
-
attr_reader :
|
25
|
+
attr_reader :addr
|
27
26
|
|
28
27
|
def initialize(addr)
|
29
28
|
@addr, @cb = addr, {}
|
30
29
|
end
|
31
30
|
|
32
31
|
def receive_data(data)
|
33
|
-
@last_received = Time.now
|
34
|
-
|
35
32
|
(@buf ||= "") << data
|
36
33
|
|
37
34
|
while @buf.length > 0
|
@@ -51,30 +48,19 @@ module Fraggle
|
|
51
48
|
|
52
49
|
# The default receive_response
|
53
50
|
def receive_response(res)
|
54
|
-
if err?
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
req = @cb.delete(res.tag)
|
59
|
-
|
60
|
-
if ! req
|
61
|
-
return
|
62
|
-
end
|
63
|
-
|
64
|
-
if res.ok?
|
65
|
-
req.emit(:valid, res)
|
66
|
-
else
|
67
|
-
req.emit(:error, res)
|
68
|
-
end
|
51
|
+
return if err?
|
52
|
+
req, blk = @cb.delete(res.tag)
|
53
|
+
return if ! blk
|
54
|
+
blk.call(res)
|
69
55
|
end
|
70
56
|
|
71
|
-
def send_request(req)
|
57
|
+
def send_request(req, blk)
|
72
58
|
if req.tag
|
73
59
|
raise SendError, "Already sent #{req.inspect}"
|
74
60
|
end
|
75
61
|
|
76
62
|
if err?
|
77
|
-
next_tick {
|
63
|
+
next_tick { blk.call(Disconnected) }
|
78
64
|
return req
|
79
65
|
end
|
80
66
|
|
@@ -85,9 +71,8 @@ module Fraggle
|
|
85
71
|
req.tag %= 2**31
|
86
72
|
end
|
87
73
|
|
88
|
-
|
89
|
-
|
90
|
-
@cb[req.tag] = req
|
74
|
+
# TODO: remove this!
|
75
|
+
@cb[req.tag] = [req, blk]
|
91
76
|
|
92
77
|
data = req.encode
|
93
78
|
head = [data.length].pack("N")
|
@@ -99,8 +84,8 @@ module Fraggle
|
|
99
84
|
|
100
85
|
def unbind
|
101
86
|
@err = true
|
102
|
-
@cb.values.each do |
|
103
|
-
|
87
|
+
@cb.values.each do |_, blk|
|
88
|
+
blk.call(Disconnected)
|
104
89
|
end
|
105
90
|
end
|
106
91
|
|
data/lib/fraggle/response.rb
CHANGED
data/lib/fraggle/version.rb
CHANGED
data/test/fraggle_client_test.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require File.dirname(__FILE__)+"/helper"
|
1
|
+
require File.expand_path(File.dirname(__FILE__)+"/helper")
|
2
2
|
require 'fraggle/client'
|
3
3
|
|
4
4
|
class FraggleClientTest < Test::Unit::TestCase
|
5
5
|
|
6
|
-
attr_reader :c
|
6
|
+
attr_reader :c
|
7
7
|
|
8
8
|
def setup
|
9
9
|
addr = "127.0.0.1:0"
|
@@ -24,14 +24,14 @@ class FraggleClientTest < Test::Unit::TestCase
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def test_send_error
|
27
|
-
req, log = request(V::
|
28
|
-
req = c.send(req)
|
27
|
+
req, log = request(V::REV)
|
29
28
|
|
30
|
-
|
29
|
+
c.send(req, &log)
|
30
|
+
|
31
|
+
res = reply(req.tag, :err_code => E::OTHER)
|
31
32
|
c.cn.receive_response(res)
|
32
33
|
|
33
|
-
assert_equal [], log.
|
34
|
-
assert_equal [res], log.error
|
34
|
+
assert_equal [res], log.valid
|
35
35
|
end
|
36
36
|
|
37
37
|
def test_reconnect_without_pending_requests
|
@@ -41,8 +41,8 @@ class FraggleClientTest < Test::Unit::TestCase
|
|
41
41
|
c.cn.close_connection
|
42
42
|
|
43
43
|
# Send a request to invoke reconnect
|
44
|
-
req, log = request(V::
|
45
|
-
|
44
|
+
req, log = request(V::REV)
|
45
|
+
c.send(req, &log)
|
46
46
|
|
47
47
|
# Fake reactor turn (only available in tests)
|
48
48
|
c.cn.tick!
|
@@ -50,15 +50,15 @@ class FraggleClientTest < Test::Unit::TestCase
|
|
50
50
|
assert exp.include?(c.cn.addr), "#{c.cn.addr.inspect} not in #{exp.inspect}"
|
51
51
|
|
52
52
|
# If the client can handle an error, it should not mention it to the user.
|
53
|
-
assert_equal [Fraggle::Connection::Disconnected], log.
|
53
|
+
assert_equal [Fraggle::Connection::Disconnected], log.valid
|
54
54
|
end
|
55
55
|
|
56
56
|
def test_reconnect_with_pending_request
|
57
57
|
exp = @addrs.dup
|
58
58
|
|
59
59
|
# Send a request to invoke reconnect
|
60
|
-
req, log = request(V::
|
61
|
-
|
60
|
+
req, log = request(V::REV)
|
61
|
+
c.send(req, &log)
|
62
62
|
|
63
63
|
# Disconnect from 127.0.0.1:0
|
64
64
|
c.cn.close_connection
|
@@ -68,18 +68,18 @@ class FraggleClientTest < Test::Unit::TestCase
|
|
68
68
|
|
69
69
|
assert exp.include?(c.cn.addr), "#{c.cn.addr.inspect} not in #{exp.inspect}"
|
70
70
|
|
71
|
-
assert_equal [Fraggle::Connection::Disconnected], log.
|
71
|
+
assert_equal [Fraggle::Connection::Disconnected], log.valid
|
72
72
|
end
|
73
73
|
|
74
74
|
def test_reconnect_with_multiple_pending_requests
|
75
75
|
exp = @addrs.dup
|
76
76
|
|
77
77
|
# Send a request to invoke reconnect
|
78
|
-
req, loga = request(V::
|
79
|
-
|
78
|
+
req, loga = request(V::REV)
|
79
|
+
c.send(req, &loga)
|
80
80
|
|
81
|
-
req, logb = request(V::
|
82
|
-
|
81
|
+
req, logb = request(V::REV)
|
82
|
+
c.send(req, &logb)
|
83
83
|
|
84
84
|
# Disconnect from 127.0.0.1:0
|
85
85
|
c.cn.close_connection
|
@@ -93,13 +93,13 @@ class FraggleClientTest < Test::Unit::TestCase
|
|
93
93
|
assert_equal exp.length - 1, c.addrs.length
|
94
94
|
|
95
95
|
# If the client can handle an error, it should not mention it to the user.
|
96
|
-
assert_equal [Fraggle::Connection::Disconnected], loga.
|
97
|
-
assert_equal [Fraggle::Connection::Disconnected], logb.
|
96
|
+
assert_equal [Fraggle::Connection::Disconnected], loga.valid
|
97
|
+
assert_equal [Fraggle::Connection::Disconnected], logb.valid
|
98
98
|
end
|
99
99
|
|
100
100
|
def test_resend_pending_requests
|
101
101
|
req, log = request(V::GET, :path => "/foo")
|
102
|
-
|
102
|
+
c.resend(req, &log)
|
103
103
|
|
104
104
|
c.cn.close_connection
|
105
105
|
|
@@ -108,42 +108,20 @@ class FraggleClientTest < Test::Unit::TestCase
|
|
108
108
|
|
109
109
|
def test_idemp_pending_requests
|
110
110
|
one, olog = request(V::SET, :rev => 1, :path => "/foo", :value => "bar")
|
111
|
-
|
111
|
+
c.idemp(one, &olog)
|
112
112
|
|
113
113
|
zero, zlog = request(V::SET, :rev => 0, :path => "/foo", :value => "bar")
|
114
|
-
|
114
|
+
c.idemp(zero, &zlog)
|
115
115
|
|
116
116
|
neg, nlog = request(V::SET, :rev => -1, :path => "/foo", :value => "bar")
|
117
|
-
|
117
|
+
c.idemp(neg, &nlog)
|
118
118
|
|
119
119
|
c.cn.close_connection
|
120
120
|
|
121
121
|
assert_equal [one], c.cn.sent
|
122
122
|
|
123
|
-
assert_equal [Fraggle::Connection::Disconnected], zlog.
|
124
|
-
assert_equal [Fraggle::Connection::Disconnected], nlog.
|
125
|
-
end
|
126
|
-
|
127
|
-
def test_readonly_simple
|
128
|
-
a, al = request(V::SET, :rev => 0, :path => "/foo")
|
129
|
-
a = c.send(a)
|
130
|
-
|
131
|
-
b, bl = request(V::SET, :rev => 0, :path => "/foo")
|
132
|
-
b = c.send(b)
|
133
|
-
|
134
|
-
res = Fraggle::Response.new(
|
135
|
-
:tag => a.tag,
|
136
|
-
:err_code => E::READONLY,
|
137
|
-
:err_detail => "9.9.9.9:9"
|
138
|
-
)
|
139
|
-
|
140
|
-
c.cn.receive_response(res)
|
141
|
-
|
142
|
-
assert_equal "1.1.1.1:1", c.cn.addr
|
143
|
-
assert_equal ["2.2.2.2:2", "3.3.3.3:3"], c.addrs
|
144
|
-
|
145
|
-
assert_equal [Fraggle::Connection::Disconnected], al.error
|
146
|
-
assert_equal [Fraggle::Connection::Disconnected], bl.error
|
123
|
+
assert_equal [Fraggle::Connection::Disconnected], zlog.valid
|
124
|
+
assert_equal [Fraggle::Connection::Disconnected], nlog.valid
|
147
125
|
end
|
148
126
|
|
149
127
|
###
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.dirname(__FILE__)+"/helper"
|
1
|
+
require File.expand_path(File.dirname(__FILE__)+"/helper")
|
2
2
|
require 'fraggle/connection'
|
3
3
|
|
4
4
|
class FraggleProtocolTest < Test::Unit::TestCase
|
@@ -80,7 +80,7 @@ class FraggleProtocolTest < Test::Unit::TestCase
|
|
80
80
|
end
|
81
81
|
|
82
82
|
nop = Fraggle::Request.new :verb => V::NOP
|
83
|
-
cn.send_request(nop)
|
83
|
+
cn.send_request(nop, nil)
|
84
84
|
|
85
85
|
assert_equal head+bytes, got
|
86
86
|
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require File.dirname(__FILE__)+"/helper"
|
1
|
+
require File.expand_path(File.dirname(__FILE__)+"/helper")
|
2
2
|
require 'fraggle/connection'
|
3
3
|
|
4
4
|
class FraggleTransactionTest < Test::Unit::TestCase
|
5
5
|
|
6
|
-
attr_reader :cn
|
6
|
+
attr_reader :cn
|
7
7
|
|
8
8
|
def nop(attrs={})
|
9
9
|
request(V::NOP, attrs)
|
@@ -15,45 +15,37 @@ class FraggleTransactionTest < Test::Unit::TestCase
|
|
15
15
|
|
16
16
|
def test_tagging
|
17
17
|
req, _ = nop
|
18
|
-
assert_equal 0, cn.send_request(req).tag
|
18
|
+
assert_equal 0, cn.send_request(req, _).tag
|
19
19
|
req, _ = nop
|
20
|
-
assert_equal 1, cn.send_request(req).tag
|
20
|
+
assert_equal 1, cn.send_request(req, _).tag
|
21
21
|
req, _ = nop
|
22
|
-
assert_equal 2, cn.send_request(req).tag
|
22
|
+
assert_equal 2, cn.send_request(req, _).tag
|
23
23
|
end
|
24
24
|
|
25
25
|
def test_valid
|
26
|
-
req, log =
|
27
|
-
req = cn.send_request(req)
|
26
|
+
req, log = request(V::REV)
|
28
27
|
|
29
|
-
|
28
|
+
cn.send_request(req, log)
|
29
|
+
|
30
|
+
res = reply(req.tag)
|
30
31
|
cn.receive_response(res)
|
31
32
|
|
32
33
|
assert_equal [res], log.valid
|
33
|
-
assert_equal [], log.done
|
34
34
|
end
|
35
35
|
|
36
36
|
def test_error
|
37
|
-
req, log =
|
38
|
-
req = cn.send_request(req)
|
37
|
+
req, log = request(V::REV)
|
39
38
|
|
40
|
-
|
41
|
-
:tag => req.tag,
|
42
|
-
:err_code => E::OTHER
|
43
|
-
)
|
39
|
+
cn.send_request(req, log)
|
44
40
|
|
41
|
+
res = reply(req.tag, :err_code => E::OTHER)
|
45
42
|
cn.receive_response(res)
|
46
43
|
|
47
|
-
assert_equal [], log.valid
|
48
|
-
assert_equal [], log.done
|
49
|
-
assert_equal [res], log.error
|
44
|
+
assert_equal [res], log.valid
|
50
45
|
end
|
51
46
|
|
52
47
|
def test_invalid_tag
|
53
|
-
res =
|
54
|
-
:tag => 0,
|
55
|
-
:err_code => E::OTHER
|
56
|
-
)
|
48
|
+
res = reply(0, :err_code => E::OTHER)
|
57
49
|
|
58
50
|
assert_nothing_raised do
|
59
51
|
cn.receive_response(res)
|
@@ -61,10 +53,11 @@ class FraggleTransactionTest < Test::Unit::TestCase
|
|
61
53
|
end
|
62
54
|
|
63
55
|
def test_deletes_callback
|
64
|
-
req, log =
|
65
|
-
|
56
|
+
req, log = request(V::REV)
|
57
|
+
|
58
|
+
cn.send_request(req, log)
|
66
59
|
|
67
|
-
res =
|
60
|
+
res = reply(req.tag)
|
68
61
|
cn.receive_response(res)
|
69
62
|
|
70
63
|
# This should be ignored
|
@@ -74,70 +67,53 @@ class FraggleTransactionTest < Test::Unit::TestCase
|
|
74
67
|
end
|
75
68
|
|
76
69
|
def test_error_deletes_callback
|
77
|
-
req, log =
|
78
|
-
req = cn.send_request(req)
|
70
|
+
req, log = request(V::REV)
|
79
71
|
|
80
|
-
|
81
|
-
:tag => req.tag,
|
82
|
-
:err_code => E::OTHER
|
83
|
-
)
|
72
|
+
cn.send_request(req, log)
|
84
73
|
|
74
|
+
res = reply(req.tag, :err_code => E::OTHER)
|
85
75
|
cn.receive_response(res)
|
86
76
|
|
87
77
|
# This should be ignored
|
88
78
|
cn.receive_response(res)
|
89
79
|
|
90
|
-
assert_equal [res], log.
|
80
|
+
assert_equal [res], log.valid
|
91
81
|
end
|
92
82
|
|
93
83
|
def test_cannot_reuse_sent_request
|
94
|
-
req, _ =
|
95
|
-
|
84
|
+
req, _ = request(V::REV)
|
85
|
+
cn.send_request(req, _)
|
96
86
|
|
97
87
|
assert_raises Fraggle::Connection::SendError do
|
98
|
-
cn.send_request(req)
|
88
|
+
cn.send_request(req, _)
|
99
89
|
end
|
100
90
|
end
|
101
91
|
|
102
|
-
def
|
103
|
-
a, al =
|
104
|
-
a = cn.send_request(a)
|
105
|
-
b, bl =
|
106
|
-
b = cn.send_request(b)
|
107
|
-
c, cl =
|
108
|
-
c = cn.send_request(c)
|
92
|
+
def test_disconnect_with_pending_requests
|
93
|
+
a, al = request(V::REV)
|
94
|
+
a = cn.send_request(a, al)
|
95
|
+
b, bl = request(V::REV)
|
96
|
+
b = cn.send_request(b, bl)
|
97
|
+
c, cl = request(V::REV)
|
98
|
+
c = cn.send_request(c, cl)
|
109
99
|
|
110
100
|
cn.unbind
|
111
101
|
|
112
|
-
assert_equal
|
113
|
-
assert_equal Fraggle::Connection::Disconnected,
|
114
|
-
|
115
|
-
assert_equal 1, bl.error.length
|
116
|
-
assert_equal Fraggle::Connection::Disconnected, bl.error.first
|
117
|
-
|
118
|
-
assert_equal 1, cl.error.length
|
119
|
-
assert_equal Fraggle::Connection::Disconnected, cl.error.first
|
102
|
+
assert_equal [Fraggle::Connection::Disconnected], al.valid
|
103
|
+
assert_equal [Fraggle::Connection::Disconnected], bl.valid
|
104
|
+
assert_equal [Fraggle::Connection::Disconnected], cl.valid
|
120
105
|
end
|
121
106
|
|
122
|
-
def
|
123
|
-
a, al = nop
|
124
|
-
a = cn.send_request(a)
|
125
|
-
|
107
|
+
def test_send_when_disconnected
|
126
108
|
cn.unbind
|
127
109
|
|
128
|
-
|
129
|
-
cn.
|
130
|
-
|
131
|
-
assert_equal [], al.valid
|
132
|
-
end
|
110
|
+
req, log = request(V::REV)
|
111
|
+
ret = cn.send_request(req, log)
|
133
112
|
|
134
|
-
|
135
|
-
cn.err = true
|
113
|
+
assert_equal req, ret
|
136
114
|
|
137
|
-
|
138
|
-
req = cn.send_request(req)
|
139
|
-
assert_equal nil, req.tag
|
115
|
+
cn.tick!
|
140
116
|
|
141
|
-
assert_equal
|
117
|
+
assert_equal [Fraggle::Connection::Disconnected], log.valid
|
142
118
|
end
|
143
119
|
end
|
data/test/helper.rb
CHANGED
@@ -14,8 +14,8 @@ class TestConn
|
|
14
14
|
@ticks = []
|
15
15
|
end
|
16
16
|
|
17
|
-
def send_request(req)
|
18
|
-
@sent << super(req)
|
17
|
+
def send_request(req, blk)
|
18
|
+
@sent << super(req, blk)
|
19
19
|
req
|
20
20
|
end
|
21
21
|
|
@@ -50,23 +50,29 @@ class Test::Unit::TestCase
|
|
50
50
|
F = Fraggle::Response
|
51
51
|
E = Fraggle::Response::Err
|
52
52
|
|
53
|
-
Log
|
53
|
+
class Log
|
54
|
+
attr_reader :valid
|
55
|
+
|
56
|
+
def initialize
|
57
|
+
@valid = []
|
58
|
+
end
|
59
|
+
|
60
|
+
def call(e)
|
61
|
+
@valid << e
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_proc
|
65
|
+
me = self
|
66
|
+
Proc.new {|e| me.call(e) }
|
67
|
+
end
|
68
|
+
end
|
54
69
|
|
55
70
|
def request(verb, attrs={})
|
56
71
|
logable(Fraggle::Request.new(attrs.merge(:verb => verb)))
|
57
72
|
end
|
58
73
|
|
59
74
|
def logable(req)
|
60
|
-
log = Log.new
|
61
|
-
req.valid do |e|
|
62
|
-
log.valid << e
|
63
|
-
end
|
64
|
-
req.done do
|
65
|
-
log.done << req
|
66
|
-
end
|
67
|
-
req.error do |e|
|
68
|
-
log.error << e
|
69
|
-
end
|
75
|
+
log = Log.new
|
70
76
|
[req, log]
|
71
77
|
end
|
72
78
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fraggle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
|
-
-
|
7
|
+
- 3
|
8
8
|
- 0
|
9
9
|
- 0
|
10
|
-
version:
|
10
|
+
version: 3.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Blake Mizerany
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-04-
|
18
|
+
date: 2011-04-29 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -76,19 +76,12 @@ files:
|
|
76
76
|
- LICENSE
|
77
77
|
- README.md
|
78
78
|
- Rakefile
|
79
|
-
-
|
80
|
-
- example/readonly.rb
|
81
|
-
- example/resend.rb
|
82
|
-
- example/rev.rb
|
83
|
-
- example/set.rb
|
84
|
-
- example/stat.rb
|
85
|
-
- example/walk.rb
|
79
|
+
- bench/gets.rb
|
86
80
|
- fraggle.gemspec
|
87
81
|
- lib/fraggle.rb
|
88
82
|
- lib/fraggle/client.rb
|
89
83
|
- lib/fraggle/connection.rb
|
90
84
|
- lib/fraggle/msg.pb.rb
|
91
|
-
- lib/fraggle/request.rb
|
92
85
|
- lib/fraggle/response.rb
|
93
86
|
- lib/fraggle/version.rb
|
94
87
|
- test/fraggle_client_test.rb
|
data/example/getdir.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'eventmachine'
|
3
|
-
require 'fraggle'
|
4
|
-
|
5
|
-
EM.run do
|
6
|
-
|
7
|
-
## NOTE: This will be easier the very near future.
|
8
|
-
|
9
|
-
## Collects names in a directory
|
10
|
-
|
11
|
-
c = Fraggle.connect
|
12
|
-
c.log.level = Logger::DEBUG
|
13
|
-
|
14
|
-
def c.getdirx(path, rev, offset, &blk)
|
15
|
-
w = Request.new
|
16
|
-
w.valid(&blk)
|
17
|
-
|
18
|
-
err = Proc.new do |e|
|
19
|
-
if e.err_code == Fraggle::Response::Err::AGAIN
|
20
|
-
w.emit(:done)
|
21
|
-
else
|
22
|
-
w.emit(:error, e)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
req = getdir(path, rev, offset) do |e|
|
27
|
-
blk.call(e)
|
28
|
-
req = getdirx(path, rev, offset+1, &blk)
|
29
|
-
req.error(&err)
|
30
|
-
end
|
31
|
-
req.error(&err)
|
32
|
-
|
33
|
-
w
|
34
|
-
end
|
35
|
-
|
36
|
-
ents, n = [], 0
|
37
|
-
|
38
|
-
f = Proc.new do |e|
|
39
|
-
ents << e.path
|
40
|
-
n += 1
|
41
|
-
c.getdir("/ctl", nil, n, &f).error do |e|
|
42
|
-
if e.err_code == Fraggle::Response::Err::RANGE
|
43
|
-
p [:ents, ents]
|
44
|
-
else
|
45
|
-
p [:err, e]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
c.getdir("/ctl", nil, n, &f).error do |e|
|
51
|
-
if e.err_code == Fraggle::Response::Err::RANGE
|
52
|
-
p [:ents, ents]
|
53
|
-
else
|
54
|
-
p [:err, e]
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
data/example/readonly.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'fraggle'
|
3
|
-
|
4
|
-
# This example assumes you have a Doozer with CAL privledges listening on port
|
5
|
-
# 8041 and a Doozer sink listening on 8042. This example will connect to the
|
6
|
-
# sink and attempt a write operation that will be redirected by the sink.
|
7
|
-
# Fraggle will pick the only remaining addr it has which is the CAL Doozer and
|
8
|
-
# retry the write operation.
|
9
|
-
|
10
|
-
EM.run do
|
11
|
-
# Connect to a slave (be sure this is a slave)
|
12
|
-
c = Fraggle.connect("doozer:?ca=127.0.0.1:8042&ca=127.0.0.1:8041")
|
13
|
-
c.log.level = Logger::DEBUG
|
14
|
-
|
15
|
-
a = c.set("/foo", "bar", -1) do |e|
|
16
|
-
# This shouldn't happen
|
17
|
-
p [:valid, a, e]
|
18
|
-
end.error do |e|
|
19
|
-
p [:err, a, e]
|
20
|
-
end
|
21
|
-
|
22
|
-
b = c.set("/foo", "bar", 1) do |e|
|
23
|
-
p [:valid, b, e]
|
24
|
-
end.error do |e|
|
25
|
-
# This shouldn't happen
|
26
|
-
p [:err, b, e]
|
27
|
-
end
|
28
|
-
end
|
data/example/resend.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'fraggle'
|
3
|
-
|
4
|
-
###
|
5
|
-
# To see this example in action, run 1 doozerd and attach 2
|
6
|
-
# more to it before running.
|
7
|
-
#
|
8
|
-
# NOTE: If you have the doozerd source, you can run ./bin/test-cluster
|
9
|
-
#
|
10
|
-
EM.run do
|
11
|
-
c = Fraggle.connect
|
12
|
-
c.log.level = Logger::DEBUG
|
13
|
-
|
14
|
-
puts "# To see this work, kill the doozer this is connected to"
|
15
|
-
puts "# to see it resend the request to the next connection."
|
16
|
-
puts
|
17
|
-
|
18
|
-
# Wait for rev 100,000
|
19
|
-
c.get("/foo", 100_000) do |e|
|
20
|
-
p ["This should not be!", e]
|
21
|
-
end.error do |e|
|
22
|
-
p [:err, e]
|
23
|
-
end.done do
|
24
|
-
p [:done, "This should not be!"]
|
25
|
-
end
|
26
|
-
end
|
data/example/rev.rb
DELETED
data/example/set.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'eventmachine'
|
3
|
-
require 'fraggle'
|
4
|
-
|
5
|
-
MaxInt64 = (1<<62)-1
|
6
|
-
|
7
|
-
EM.run do
|
8
|
-
c = Fraggle.connect
|
9
|
-
c.log.level = Logger::DEBUG
|
10
|
-
|
11
|
-
EM.add_periodic_timer(1) do
|
12
|
-
c.get("/hello") do |e|
|
13
|
-
p [:e, e]
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
c.set('/hello', 'world', MaxInt64) do |e|
|
18
|
-
p [:set, e]
|
19
|
-
end
|
20
|
-
end
|
data/example/stat.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'eventmachine'
|
3
|
-
require 'fraggle'
|
4
|
-
|
5
|
-
EM.run do
|
6
|
-
c = Fraggle.connect
|
7
|
-
|
8
|
-
EM.add_periodic_timer(1) do
|
9
|
-
c.stat("/example") do |e|
|
10
|
-
p e
|
11
|
-
end.error do |e|
|
12
|
-
p [:err, e]
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
EM.add_periodic_timer(0.5) do
|
17
|
-
c.set("/example/#{rand(10)}", "test", -1)
|
18
|
-
end
|
19
|
-
end
|
data/example/walk.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'eventmachine'
|
3
|
-
require 'fraggle'
|
4
|
-
|
5
|
-
EM.run do
|
6
|
-
c = Fraggle.connect
|
7
|
-
|
8
|
-
paths = []
|
9
|
-
|
10
|
-
req = c.walk("/**", 1)
|
11
|
-
|
12
|
-
valid = Proc.new do |e|
|
13
|
-
paths << e.path+"="+e.value
|
14
|
-
end
|
15
|
-
|
16
|
-
done = Proc.new do
|
17
|
-
puts "rev #{req.rev} " + ("-"*25)
|
18
|
-
puts *paths
|
19
|
-
|
20
|
-
paths.clear
|
21
|
-
|
22
|
-
req = c.walk("/**", req.rev+1)
|
23
|
-
req.valid(&valid)
|
24
|
-
req.done(&done)
|
25
|
-
end
|
26
|
-
|
27
|
-
req.valid(&valid)
|
28
|
-
req.done(&done)
|
29
|
-
end
|
data/lib/fraggle/request.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'fraggle/msg.pb'
|
2
|
-
|
3
|
-
module Fraggle
|
4
|
-
class Request
|
5
|
-
|
6
|
-
DEFAULT_PROC = Proc.new {}
|
7
|
-
|
8
|
-
attr_accessor :cn
|
9
|
-
attr_reader :cb
|
10
|
-
|
11
|
-
def initialize(attrs={})
|
12
|
-
super(attrs)
|
13
|
-
@cb = Hash.new
|
14
|
-
end
|
15
|
-
|
16
|
-
def valid(&blk)
|
17
|
-
@cb[:valid] = blk
|
18
|
-
self
|
19
|
-
end
|
20
|
-
|
21
|
-
def done(&blk)
|
22
|
-
@cb[:done] = blk
|
23
|
-
self
|
24
|
-
end
|
25
|
-
|
26
|
-
def error(&blk)
|
27
|
-
@cb[:error] = blk
|
28
|
-
self
|
29
|
-
end
|
30
|
-
|
31
|
-
def emit(name, *args)
|
32
|
-
(@cb[name] || DEFAULT_PROC).call(*args)
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
36
|
-
end
|