fraggle 2.0.0 → 3.0.0
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 +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
|