fraggle 4.0.0.pre.1 → 4.0.0.pre.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ *.prof*
data/README.md CHANGED
@@ -1,11 +1,14 @@
1
- # Fraggle (v4.0.0.pre.1 is compatible with Doozer 0.6)
1
+ # Fraggle
2
+ ## The current gem is v4.0.0.pre.1 is compatible with Doozer 0.6
2
3
 
3
- Fraggle currently is only a raw interface to Doozer 0.6.
4
+ Please see the [4.0.0.pre.1 README](https://github.com/ha/fraggle/tree/v4.0.0.pre.1) for instructions on use.
4
5
 
5
6
  **An EventMachine based Doozer client**
6
7
 
7
8
  ## Install
8
9
 
10
+ (For pre-releases, use `--pre`)
11
+
9
12
  $ gem install fraggle
10
13
 
11
14
  ## Use
@@ -31,48 +34,75 @@ addresses with IP 127.0.0.1 and ports 8046, 8041, 8042, 8043.
31
34
  c = Fraggle.connect
32
35
 
33
36
  c.rev do |v|
34
- c.get(v.rev, "/foo") do |e|
35
- p [:get, e]
36
- if e.ok?
37
+ c.get(v, "/foo") do |e, err|
38
+ if err
39
+ err.code # => nil
40
+ err.detail # => nil
41
+ else
37
42
  e.value # => nil
38
43
  e.rev # => 0
39
44
  e.missing? # => true
40
- else
41
- e.err_code # => nil
42
- e.err_detail # => nil
43
45
  end
46
+
47
+ p [:get, e, err]
44
48
  end
45
49
 
46
50
  ## Obtain the current revision the store is at and watch from then on for
47
51
  ## any SET or DEL to /foo.
48
- c.wait(v.rev, "/foo") do |e|
52
+ c.wait(v, "/foo") do |e, err|
49
53
  # The event has:
50
54
  # ------------------------
51
- e.err_code # => nil
52
- e.err_detail # => nil
53
- e.path # => "/foo"
54
- e.value # => "zomg!"
55
- e.rev # => 123
56
- e.set? # => true
57
- e.del? # => false
58
-
59
- p [:wait, e]
55
+ if err
56
+ err.code # => nil
57
+ err.detail # => nil
58
+ else
59
+ e.path # => "/foo"
60
+ e.value # => "zomg!"
61
+ e.rev # => 123
62
+ e.set? # => true
63
+ e.del? # => false
64
+ end
65
+
66
+ p [:wait, e, err]
60
67
  end
61
68
  end
62
69
 
63
70
  ## Setting a key (this will trigger the watch above)
64
- c.set(Fraggle::Clobber, "/foo", "zomg!") do |e|
71
+ f = Proc.new do |e, err|
72
+ p [:e, e, err]
73
+
74
+ if err && err.disconnected?
75
+ # Fraggle (for now) does not attempt a non-idempotent request. This means
76
+ # Fraggle will hand off the error to the user if there is a SET or DEL
77
+ # with rev 0 (missing) and delete it during the time we may be
78
+ # disconnected.
79
+ #
80
+ # In this scenario, there are no other clients that can exist that will
81
+ # attempt to set this "lock" if it's missing then delete it. It is safe
82
+ # for us to resend the request if we were disconnected from the previous
83
+ # server before a response.
84
+ #
85
+ # See High-Availability in the README for more information about this.
86
+ #
87
+ c.set(0, "/foo", "zomg!", &f)
88
+ next
89
+ end
90
+
65
91
  # Success!
66
- case e.err_code
67
- when Fraggle::REV_MISMATCH
68
- # We didn't win
69
- when nil
70
- # Success!
71
- else
72
- fail "something bad happened: " + e.inspect
92
+ if err
93
+ case err.code
94
+ when Fraggle::REV_MISMATCH
95
+ p :not_it
96
+ when nil
97
+ # Success!
98
+ p [:it, e]
99
+ else
100
+ fail "something bad happened: " + e.inspect
101
+ end
73
102
  end
74
103
  end
75
104
 
105
+ c.set(0, "/foo", "zomg!", &f)
76
106
  end
77
107
 
78
108
  ## Consistency
@@ -82,9 +112,9 @@ the most up-to-date data. If you need to do multiple reads at certain
82
112
  point in time for consistency, use the `rev` command.
83
113
 
84
114
  c.rev do |v|
85
- c.get(v.rev, "/a") { ... }
86
- c.get(v.rev, "/b") { ... }
87
- c.get(v.rev, "/c") { ... }
115
+ c.get(v, "/a") { ... }
116
+ c.get(v, "/b") { ... }
117
+ c.get(v, "/c") { ... }
88
118
  end
89
119
 
90
120
  This also means you can go back in time or into the future!
@@ -117,8 +147,9 @@ stores history as far back as it is configured to hold it. The default is
117
147
 
118
148
  ## Commands
119
149
 
120
- Each command behaves according to the [proto spec][], respectively.
121
- Their `blk`s are called with one parameter, a `Fraggle::Response`, when a response is
150
+ Each command below behaves according to the [proto spec][], respectively.
151
+ Their `blk`s are called with two parameters, a `Fraggle::Response` as the first
152
+ or a `Fraggle::Connection::ResponseError` as the second if a response is
122
153
  returned from the server.
123
154
 
124
155
  `set(rev, path, value, &blk)`
@@ -127,10 +158,6 @@ returned from the server.
127
158
 
128
159
  `get(rev, path, &blk)`
129
160
 
130
- `getdir(rev, path, offset, &blk)`
131
-
132
- `walk(rev, path, offset, &blk)`
133
-
134
161
  `wait(rev, path, &blk)`
135
162
 
136
163
  `rev(&blk)`
@@ -144,19 +171,17 @@ returned from the server.
144
171
  Watches `path` (a glob pattern) for changes, from `rev` in history on. Its
145
172
  `blk` is called with a `Fraggle::Response` for each event.
146
173
 
147
- `getdir_all(rev, path, off=0, lim=MaxInt64, ents=[], &blk)`
174
+ `getdir(rev, path, off=0, lim=MaxInt64, ents=[], &blk)`
148
175
 
149
176
  Behaves like `getdir` but collects `ents`, starting at `off` until all or `lim`
150
- entries are read. When done `blk` is called with the result as the first
151
- parameter or an error as the second. Depending on the response, one or the
152
- other will be set and the other with be `nil`.
177
+ entries are read. When done, `blk` is called with the result (an `Array`) as the
178
+ first parameter or a `Fraggle::Connection::Response` as the second. Depending
179
+ on the response, one or the other will be set and the other with be `nil`.
153
180
 
154
- `walk_all(rev, path, off=0, lim=MaxInt64, ents=[], &blk)`
181
+ `walk(rev, path, off=0, lim=MaxInt64, ents=[], &blk)`
155
182
 
156
- Behaves like `walk` but collects `ents`, starting at `off` until all or `lim`
157
- entries are read. When done `blk` is called with the result as the first
158
- parameter or an error as the second. Depending on the response, one or the
159
- other will be set and the other with be `nil`.
183
+ Like `getdir`, but but path is a glob pattern and each result contains a `path`,
184
+ `value`, and `rev`.
160
185
 
161
186
  ## Dev
162
187
 
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # By Mark McGranaghan
4
+
5
+ require "rubygems"
6
+ require "bundler"
7
+ Bundler.setup
8
+ require "fraggle"
9
+ require "statsample"
10
+
11
+ $stdout.sync = true
12
+
13
+ abort("read <[get|set]> <total> <width> [verbose]") if (ARGV.size < 2)
14
+ op = ARGV.shift.to_sym
15
+ total = ARGV.shift.to_i
16
+ width = ARGV.shift.to_i
17
+ verbose = !!ARGV.shift
18
+ latencies = []
19
+ sent_at = nil
20
+
21
+ EM.run do
22
+ client = Fraggle.connect
23
+ sent = 0
24
+ received = 0
25
+ start = Time.now
26
+
27
+ f = Proc.new do |r|
28
+ received_at = Time.now
29
+ received +=1
30
+ latency = received_at - sent_at
31
+
32
+ latencies << latency
33
+ if verbose
34
+ $stdout.puts("received=#{received} ok=#{r.ok?} rev=#{r.rev} latency=#{latency}")
35
+ elsif (received % 10 == 0)
36
+ $stdout.print(".")
37
+ end
38
+ if (received == total)
39
+ EM.stop
40
+ elapsed = Time.now - start
41
+ vector = latencies.to_scale
42
+ $stdout.puts
43
+ $stdout.puts("total=#{total}")
44
+ $stdout.puts("elapsed=#{elapsed}")
45
+ $stdout.puts("rate=#{total / elapsed}")
46
+ $stdout.puts("mean=#{vector.mean}")
47
+ $stdout.puts("sd=#{vector.sd}")
48
+ $stdout.puts("perc90=#{vector.percentil(90)}")
49
+ $stdout.puts("perc99=#{vector.percentil(99)}")
50
+ $stdout.puts("max=#{vector.max}")
51
+ end
52
+ end
53
+
54
+ tick = Proc.new do
55
+ if (sent == total)
56
+ # done sending
57
+ elsif ((sent - received) < width)
58
+ # pipe open
59
+ sent_at = Time.now
60
+ sent += 1
61
+ if verbose
62
+ $stdout.puts("sent=#{sent}")
63
+ end
64
+
65
+ case op
66
+ when :get
67
+ client.get(nil, "/processes/#{sent}", &f)
68
+ when :set
69
+ client.set(Fraggle::Clobber, "/processes/#{sent}", "1", &f)
70
+ end
71
+ else
72
+ # pipe closed
73
+ end
74
+ EM.next_tick(&tick)
75
+ end
76
+ tick.call
77
+ end
@@ -6,7 +6,7 @@ EM.run do
6
6
 
7
7
  c.rev do |v|
8
8
  # Valid
9
- req = c.getdir_all("/ctl/node", v.rev) do |ents, err|
9
+ req = c.getdir(v, "/ctl/node") do |ents, err|
10
10
  if err
11
11
  p [:err, err]
12
12
  else
@@ -17,12 +17,12 @@ EM.run do
17
17
  end
18
18
 
19
19
  # Limit 0 return nothing
20
- c.getdir_all("/ctl/node", v.rev, 0, 0) do |ents, err|
20
+ c.getdir(v, "/ctl/node", 0, 0) do |ents, err|
21
21
  p [:ret, ents, err]
22
22
  end
23
23
 
24
24
  # Error
25
- c.getdir_all("/nothere", v.rev) do |ents, err|
25
+ c.getdir(v, "/nothere") do |ents, err|
26
26
  p [:ret, ents, err]
27
27
  end
28
28
  end
@@ -10,47 +10,73 @@ EM.run do
10
10
  c = Fraggle.connect
11
11
 
12
12
  c.rev do |v|
13
- c.get(v.rev, "/foo") do |e|
14
- p [:get, e]
15
- if e.ok?
13
+ c.get(v, "/foo") do |e, err|
14
+ if err
15
+ err.code # => nil
16
+ err.detail # => nil
17
+ else
16
18
  e.value # => nil
17
19
  e.rev # => 0
18
20
  e.missing? # => true
19
- else
20
- e.err_code # => nil
21
- e.err_detail # => nil
22
21
  end
22
+
23
+ p [:get, e, err]
23
24
  end
24
25
 
25
26
  ## Obtain the current revision the store is at and watch from then on for
26
27
  ## any SET or DEL to /foo.
27
- c.wait(v.rev, "/foo") do |e|
28
+ c.wait(v, "/foo") do |e, err|
28
29
  # The event has:
29
30
  # ------------------------
30
- e.err_code # => nil
31
- e.err_detail # => nil
32
- e.path # => "/foo"
33
- e.value # => "zomg!"
34
- e.rev # => 123
35
- e.set? # => true
36
- e.del? # => false
37
-
38
- p [:wait, e]
31
+ if err
32
+ err.code # => nil
33
+ err.detail # => nil
34
+ else
35
+ e.path # => "/foo"
36
+ e.value # => "zomg!"
37
+ e.rev # => 123
38
+ e.set? # => true
39
+ e.del? # => false
40
+ end
41
+
42
+ p [:wait, e, err]
39
43
  end
40
44
  end
41
45
 
42
46
  ## Setting a key (this will trigger the watch above)
43
- c.set(0, "/foo", "zomg!") do |e|
47
+ f = Proc.new do |e, err|
48
+ p [:e, e, err]
49
+
50
+ if err && err.disconnected?
51
+ # Fraggle (for now) does not attempt a non-idempotent request. This means
52
+ # Fraggle will hand off the error to the user if there is a SET or DEL
53
+ # with rev 0 (missing) and delete it during the time we may be
54
+ # disconnected.
55
+ #
56
+ # In this scenario, there are no other clients that can exist that will
57
+ # attempt to set this "lock" if it's missing then delete it. It is safe
58
+ # for us to resend the request if we were disconnected from the previous
59
+ # server before a response.
60
+ #
61
+ # See High-Availability in the README for more information about this.
62
+ #
63
+ c.set(0, "/foo", "zomg!", &f)
64
+ next
65
+ end
66
+
44
67
  # Success!
45
- case e.err_code
46
- when Fraggle::REV_MISMATCH
47
- p :not_it
48
- when nil
49
- # Success!
50
- p :it
51
- else
52
- fail "something bad happened: " + e.inspect
68
+ if err
69
+ case err.code
70
+ when Fraggle::REV_MISMATCH
71
+ p :not_it
72
+ when nil
73
+ # Success!
74
+ p [:it, e]
75
+ else
76
+ fail "something bad happened: " + e.inspect
77
+ end
53
78
  end
54
79
  end
55
80
 
81
+ c.set(0, "/foo", "zomg!", &f)
56
82
  end
@@ -6,7 +6,7 @@ EM.run do
6
6
 
7
7
  c.rev do |v|
8
8
  # Valid
9
- req = c.walk_all("/ctl/node/**", v.rev) do |ents, err|
9
+ req = c.walk(v, "/ctl/node/**") do |ents, err|
10
10
  if err
11
11
  p [:err, err]
12
12
  else
@@ -17,13 +17,13 @@ EM.run do
17
17
  end
18
18
 
19
19
  # Limit 0 return nothing
20
- c.walk_all("/ctl/node/**", v.rev, 0, 0) do |ents, err|
21
- p [:ret, ents, err]
20
+ c.walk(v, "/ctl/node/**", 0, 0) do |ents, err|
21
+ p [:nothing, ents, err]
22
22
  end
23
23
 
24
24
  # Error
25
- c.walk_all("/nothere", v.rev) do |ents, err|
26
- p [:ret, ents, err]
25
+ c.walk(v, "/nothere") do |ents, err|
26
+ p [:nothere, ents, err]
27
27
  end
28
28
  end
29
29
  end
@@ -5,8 +5,8 @@ EM.run do
5
5
  c = Fraggle.connect
6
6
 
7
7
  c.rev do |v|
8
- c.watch("/ctl/node/**", v.rev) do |e|
9
- p e
8
+ c.watch(v, "/ctl/node/**") do |e, err|
9
+ p [e, err]
10
10
  end
11
11
  end
12
12
  end
@@ -23,4 +23,5 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency "eventmachine"
24
24
 
25
25
  s.add_development_dependency "turn"
26
+ s.add_development_dependency "statsample"
26
27
  end
@@ -1,6 +1,5 @@
1
1
  require 'eventmachine'
2
2
  require 'fraggle/connection'
3
- require 'logger'
4
3
 
5
4
  module Fraggle
6
5
  class Client
@@ -11,13 +10,10 @@ module Fraggle
11
10
  class NoMoreAddrs < StandardError
12
11
  end
13
12
 
14
- DefaultLog = Logger.new(STDERR)
15
- DefaultLog.level = Logger::UNKNOWN
13
+ attr_reader :cn, :addrs
16
14
 
17
- attr_reader :cn, :log, :addrs
18
-
19
- def initialize(cn, addrs, log=DefaultLog)
20
- @cn, @addrs, @log = cn, addrs, log
15
+ def initialize(cn, addrs)
16
+ @cn, @addrs = cn, addrs
21
17
  end
22
18
 
23
19
  def addr
@@ -52,7 +48,7 @@ module Fraggle
52
48
  idemp(req, &blk)
53
49
  end
54
50
 
55
- def getdir(rev, path, offset, &blk)
51
+ def _getdir(rev, path, offset, &blk)
56
52
  req = Request.new
57
53
  req.verb = GETDIR
58
54
  req.rev = rev
@@ -62,7 +58,7 @@ module Fraggle
62
58
  resend(req, &blk)
63
59
  end
64
60
 
65
- def walk(rev, path, offset, &blk)
61
+ def _walk(rev, path, offset, &blk)
66
62
  req = Request.new
67
63
  req.verb = WALK
68
64
  req.rev = rev
@@ -85,7 +81,9 @@ module Fraggle
85
81
  req = Request.new
86
82
  req.verb = REV
87
83
 
88
- resend(req, &blk)
84
+ resend(req) do |v, _|
85
+ blk.call(v.rev)
86
+ end
89
87
  end
90
88
 
91
89
  def stat(rev, path, &blk)
@@ -97,21 +95,29 @@ module Fraggle
97
95
  resend(req, &blk)
98
96
  end
99
97
 
98
+ def access(secret, &blk)
99
+ req = Request.new
100
+ req.verb = ACCESS
101
+ req.value = secret
102
+
103
+ resend(req, &blk)
104
+ end
105
+
100
106
  def watch(rev, path, &blk)
101
- wait(rev, path, rev) do |e|
102
- blk.call(e)
103
- if e.ok?
104
- watch(rev, path, e.rev+1, &blk)
107
+ wait(rev, path) do |e, err|
108
+ blk.call(e, err)
109
+ if ! err
110
+ watch(e.rev+1, path, &blk)
105
111
  end
106
112
  end
107
113
  end
108
114
 
109
- def getdir_all(rev, path, off=0, lim=MaxInt64, ents=[], &blk)
110
- all(:getdir, rev, path, off, lim, ents, &blk)
115
+ def getdir(rev, path, off=0, lim=MaxInt64, ents=[], &blk)
116
+ all(:_getdir, rev, path, off, lim, ents, &blk)
111
117
  end
112
118
 
113
- def walk_all(rev, path, off=0, lim=MaxInt64, ents=[], &blk)
114
- all(:walk, rev, path, off, lim, ents, &blk)
119
+ def walk(rev, path, off=0, lim=MaxInt64, ents=[], &blk)
120
+ all(:_walk, rev, path, off, lim, ents, &blk)
115
121
  end
116
122
 
117
123
  def all(m, rev, path, off, lim, ents=[], &blk)
@@ -120,11 +126,10 @@ module Fraggle
120
126
  return
121
127
  end
122
128
 
123
- __send__(m, rev, path, off) do |e|
124
- case e.err_code
129
+ __send__(m, rev, path, off) do |e, err|
130
+ case err && err.code
125
131
  when nil
126
- ents << e
127
- all(m, rev, path, off+1, lim-1, ents, &blk)
132
+ all(m, rev, path, off+1, lim-1, ents << e, &blk)
128
133
  when Fraggle::Response::Err::RANGE
129
134
  blk.call(ents, nil)
130
135
  else
@@ -136,56 +141,56 @@ module Fraggle
136
141
  # Sends a request to the server. Returns the request with a new tag
137
142
  # assigned.
138
143
  def send(req, &blk)
139
- cb = Proc.new do |e|
140
- log.debug("response: #{e.inspect} for #{req.inspect}")
141
-
142
- if e.disconnected? && cn.err?
143
- log.error("conn err: #{req.inspect}")
144
- reconnect!
144
+ cb = Proc.new do |e, err|
145
+ case err
146
+ when Connection::DisconnectedError
147
+ if cn.err?
148
+ reconnect!
149
+ end
145
150
  end
146
-
147
- blk.call(e)
151
+ blk.call(e, err)
148
152
  end
149
153
 
150
- log.debug("sending: #{req.inspect}")
151
154
  cn.send_request(req, cb)
152
155
  end
153
156
 
154
157
  def resend(req, &blk)
155
- cb = Proc.new do |e|
156
- if e.disconnected?
158
+ send(req) do |e, err|
159
+ case err
160
+ when nil
161
+ blk.call(e, err)
162
+ when Connection::DisconnectedError
157
163
  req.tag = nil
158
- log.debug("resending: #{req.inspect}")
159
164
  resend(req, &blk)
160
165
  else
161
- blk.call(e)
166
+ blk.call(e, err)
162
167
  end
163
168
  end
164
-
165
- send(req, &cb)
166
169
  end
167
170
 
168
171
  def idemp(req, &blk)
169
- cb = Proc.new do |e|
170
- if e.disconnected? && req.rev > 0
172
+ send(req) do |e, err|
173
+ case err
174
+ when Connection::DisconnectedError
171
175
  # If we're trying to update a value that isn't missing or that we're
172
176
  # not trying to clobber, it's safe to retry. We can't idempotently
173
177
  # update missing values because there may be a race with another
174
178
  # client that sets and/or deletes the key during the time between your
175
179
  # read and write.
176
- req.tag = nil
177
- idemp(req, &blk)
178
- next
180
+ if (req.rev || 0) > 0
181
+ req.tag = nil
182
+ idemp(req, &blk)
183
+ else
184
+ blk.call(e, err)
185
+ end
186
+ when nil
187
+ blk.call(e, err)
179
188
  end
180
-
181
- blk.call(e)
182
189
  end
183
-
184
- send(req, &cb)
185
190
  end
186
191
 
187
192
  def reconnect!
188
- if addr = @addrs.shift
193
+ if addr = @addrs.slice!(rand(@addrs.length))
189
194
  reconnect(addr)
190
195
  else
191
196
  raise NoMoreAddrs
@@ -193,7 +198,6 @@ module Fraggle
193
198
  end
194
199
 
195
200
  def reconnect(addr)
196
- log.warn("reconnecting to #{addr}")
197
201
  host, port = addr.split(":")
198
202
  @cn = EM.connect(host, port, Fraggle::Connection, addr)
199
203
  end
@@ -4,21 +4,35 @@ module Fraggle
4
4
 
5
5
  module Connection
6
6
 
7
- Disconnected = Response.new
8
- Disconnected.disconnected = true
9
-
10
- # Base class for all Connection errors
11
- class Error < StandardError
12
- attr_accessor :req
13
-
7
+ # Raised when a request is invalid
8
+ class SendError < StandardError
14
9
  def initialize(req, msg=nil)
15
10
  @req = req
16
11
  super(msg)
17
12
  end
18
13
  end
19
14
 
20
- # Raised when a request is invalid
21
- class SendError < Error
15
+ class DisconnectedError < StandardError
16
+ def ==(o)
17
+ return false if ! o.kind_of?(self.class)
18
+ message == o.message
19
+ end
20
+ end
21
+
22
+ class ResponseError < StandardError
23
+ attr_reader :code
24
+
25
+ alias :detail :message
26
+
27
+ def initialize(res)
28
+ @code = res.err_code
29
+ super("#{res.name_for(Response::Err, code)}: #{res.err_detail}")
30
+ end
31
+
32
+ def ==(o)
33
+ return false if ! o.kind_of?(self.class)
34
+ code == o.code && message == o.message
35
+ end
22
36
  end
23
37
 
24
38
 
@@ -33,10 +47,10 @@ module Fraggle
33
47
 
34
48
  while @buf.length > 0
35
49
  if @len && @buf.length >= @len
36
- bytes = @buf.slice!(0, @len)
37
- @len = nil
38
- res = Response.decode(bytes)
39
- receive_response(res)
50
+ bytes = @buf.slice!(0, @len)
51
+ @len = nil
52
+ res = Response.decode(bytes)
53
+ receive_response(res)
40
54
  elsif @buf.length >= 4
41
55
  bytes = @buf.slice!(0, 4)
42
56
  @len = bytes.unpack("N")[0]
@@ -51,7 +65,11 @@ module Fraggle
51
65
  return if err?
52
66
  req, blk = @cb.delete(res.tag)
53
67
  return if ! blk
54
- blk.call(res)
68
+ if res.err_code
69
+ blk.call(nil, ResponseError.new(res))
70
+ else
71
+ blk.call(res, nil)
72
+ end
55
73
  end
56
74
 
57
75
  def send_request(req, blk)
@@ -60,7 +78,7 @@ module Fraggle
60
78
  end
61
79
 
62
80
  if err?
63
- next_tick { blk.call(Disconnected) }
81
+ next_tick { blk.call(nil, DisconnectedError.new(self.addr)) }
64
82
  return req
65
83
  end
66
84
 
@@ -85,7 +103,7 @@ module Fraggle
85
103
  def unbind
86
104
  @err = true
87
105
  @cb.values.each do |_, blk|
88
- blk.call(Disconnected)
106
+ blk.call(nil, DisconnectedError.new(self.addr))
89
107
  end
90
108
  end
91
109
 
@@ -16,6 +16,7 @@ module Fraggle
16
16
  WALK = 9
17
17
  GETDIR = 14
18
18
  STAT = 16
19
+ ACCESS = 99
19
20
  end
20
21
 
21
22
  optional :tag, :int32, 1
@@ -6,8 +6,6 @@ module Fraggle
6
6
  SET = 4
7
7
  DEL = 8
8
8
 
9
- attr_accessor :disconnected
10
-
11
9
  def set?
12
10
  return false if !flags
13
11
  (flags & SET) > 0
@@ -26,9 +24,5 @@ module Fraggle
26
24
  err_code.nil?
27
25
  end
28
26
 
29
- def disconnected?
30
- !!@disconnected
31
- end
32
-
33
27
  end
34
28
  end
@@ -1,3 +1,3 @@
1
1
  module Fraggle
2
- VERSION = "4.0.0.pre.1"
2
+ VERSION = "4.0.0.pre.2"
3
3
  end
@@ -23,7 +23,7 @@ class FraggleClientTest < Test::Unit::TestCase
23
23
  @c.__send__(:initialize, cn, @addrs)
24
24
  end
25
25
 
26
- def test_send_error
26
+ def test_response_error
27
27
  req, log = request(V::REV)
28
28
 
29
29
  c.send(req, &log)
@@ -31,7 +31,7 @@ class FraggleClientTest < Test::Unit::TestCase
31
31
  res = reply(req.tag, :err_code => E::OTHER)
32
32
  c.cn.receive_response(res)
33
33
 
34
- assert_equal [res], log.valid
34
+ assert_equal [[nil, C::ResponseError.new(res)]], log.valid
35
35
  end
36
36
 
37
37
  def test_reconnect_without_pending_requests
@@ -50,7 +50,7 @@ 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.valid
53
+ assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], log.valid
54
54
  end
55
55
 
56
56
  def test_reconnect_with_pending_request
@@ -68,7 +68,7 @@ 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.valid
71
+ assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], log.valid
72
72
  end
73
73
 
74
74
  def test_reconnect_with_multiple_pending_requests
@@ -93,8 +93,8 @@ 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.valid
97
- assert_equal [Fraggle::Connection::Disconnected], logb.valid
96
+ assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], loga.valid
97
+ assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], logb.valid
98
98
  end
99
99
 
100
100
  def test_resend_pending_requests
@@ -120,8 +120,8 @@ class FraggleClientTest < Test::Unit::TestCase
120
120
 
121
121
  assert_equal [one], c.cn.sent
122
122
 
123
- assert_equal [Fraggle::Connection::Disconnected], zlog.valid
124
- assert_equal [Fraggle::Connection::Disconnected], nlog.valid
123
+ assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], zlog.valid
124
+ assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], nlog.valid
125
125
  end
126
126
 
127
127
  ###
@@ -181,7 +181,7 @@ class FraggleClientTest < Test::Unit::TestCase
181
181
  :offset => 0
182
182
  }
183
183
 
184
- assert_verb exp, :getdir, 0, "/foo", 0
184
+ assert_verb exp, :_getdir, 0, "/foo", 0
185
185
  end
186
186
 
187
187
  def test_rev
@@ -210,7 +210,7 @@ class FraggleClientTest < Test::Unit::TestCase
210
210
  :offset => 0
211
211
  }
212
212
 
213
- assert_verb exp, :walk, 0, "/foo/*", 0
213
+ assert_verb exp, :_walk, 0, "/foo/*", 0
214
214
  end
215
215
 
216
216
  def test_wait
@@ -223,4 +223,13 @@ class FraggleClientTest < Test::Unit::TestCase
223
223
  assert_verb exp, :wait, 0, "/foo/*"
224
224
  end
225
225
 
226
+ def test_wait
227
+ exp = {
228
+ :verb => V::ACCESS,
229
+ :value => "abc"
230
+ }
231
+
232
+ assert_verb exp, :access, "abc"
233
+ end
234
+
226
235
  end
@@ -5,20 +5,16 @@ class FraggleTransactionTest < Test::Unit::TestCase
5
5
 
6
6
  attr_reader :cn
7
7
 
8
- def nop(attrs={})
9
- request(V::NOP, attrs)
10
- end
11
-
12
8
  def setup
13
9
  @cn = TestConn.new("127.0.0.1:0")
14
10
  end
15
11
 
16
12
  def test_tagging
17
- req, _ = nop
13
+ req, _ = request(V::REV)
18
14
  assert_equal 0, cn.send_request(req, _).tag
19
- req, _ = nop
15
+ req, _ = request(V::REV)
20
16
  assert_equal 1, cn.send_request(req, _).tag
21
- req, _ = nop
17
+ req, _ = request(V::REV)
22
18
  assert_equal 2, cn.send_request(req, _).tag
23
19
  end
24
20
 
@@ -30,7 +26,7 @@ class FraggleTransactionTest < Test::Unit::TestCase
30
26
  res = reply(req.tag)
31
27
  cn.receive_response(res)
32
28
 
33
- assert_equal [res], log.valid
29
+ assert_equal [[res, nil]], log.valid
34
30
  end
35
31
 
36
32
  def test_error
@@ -41,7 +37,8 @@ class FraggleTransactionTest < Test::Unit::TestCase
41
37
  res = reply(req.tag, :err_code => E::OTHER)
42
38
  cn.receive_response(res)
43
39
 
44
- assert_equal [res], log.valid
40
+ err = C::ResponseError.new(res)
41
+ assert_equal [[nil, err]], log.valid
45
42
  end
46
43
 
47
44
  def test_invalid_tag
@@ -63,7 +60,7 @@ class FraggleTransactionTest < Test::Unit::TestCase
63
60
  # This should be ignored
64
61
  cn.receive_response(res)
65
62
 
66
- assert_equal [res], log.valid
63
+ assert_equal [[res, nil]], log.valid
67
64
  end
68
65
 
69
66
  def test_error_deletes_callback
@@ -77,14 +74,14 @@ class FraggleTransactionTest < Test::Unit::TestCase
77
74
  # This should be ignored
78
75
  cn.receive_response(res)
79
76
 
80
- assert_equal [res], log.valid
77
+ assert_equal [[nil, C::ResponseError.new(res)]], log.valid
81
78
  end
82
79
 
83
80
  def test_cannot_reuse_sent_request
84
81
  req, _ = request(V::REV)
85
82
  cn.send_request(req, _)
86
83
 
87
- assert_raises Fraggle::Connection::SendError do
84
+ assert_raises C::SendError do
88
85
  cn.send_request(req, _)
89
86
  end
90
87
  end
@@ -99,9 +96,9 @@ class FraggleTransactionTest < Test::Unit::TestCase
99
96
 
100
97
  cn.unbind
101
98
 
102
- assert_equal [Fraggle::Connection::Disconnected], al.valid
103
- assert_equal [Fraggle::Connection::Disconnected], bl.valid
104
- assert_equal [Fraggle::Connection::Disconnected], cl.valid
99
+ assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], al.valid
100
+ assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], bl.valid
101
+ assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], cl.valid
105
102
  end
106
103
 
107
104
  def test_send_when_disconnected
@@ -114,6 +111,6 @@ class FraggleTransactionTest < Test::Unit::TestCase
114
111
 
115
112
  cn.tick!
116
113
 
117
- assert_equal [Fraggle::Connection::Disconnected], log.valid
114
+ assert_equal [[nil, C::DisconnectedError.new("127.0.0.1:0")]], log.valid
118
115
  end
119
116
  end
@@ -46,6 +46,7 @@ end
46
46
 
47
47
  class Test::Unit::TestCase
48
48
 
49
+ C = Fraggle::Connection
49
50
  V = Fraggle::Request::Verb
50
51
  F = Fraggle::Response
51
52
  E = Fraggle::Response::Err
@@ -57,13 +58,13 @@ class Test::Unit::TestCase
57
58
  @valid = []
58
59
  end
59
60
 
60
- def call(e)
61
- @valid << e
61
+ def call(e, err)
62
+ @valid << [e, err]
62
63
  end
63
64
 
64
65
  def to_proc
65
66
  me = self
66
- Proc.new {|e| me.call(e) }
67
+ Proc.new {|e, err| me.call(e, err) }
67
68
  end
68
69
  end
69
70
 
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fraggle
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1923831851
4
+ hash: 1923831853
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 4
8
8
  - 0
9
9
  - 0
10
10
  - pre
11
- - 1
12
- version: 4.0.0.pre.1
11
+ - 2
12
+ version: 4.0.0.pre.2
13
13
  platform: ruby
14
14
  authors:
15
15
  - Blake Mizerany
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2011-05-02 00:00:00 -07:00
20
+ date: 2011-05-05 00:00:00 -07:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency
@@ -63,6 +63,20 @@ dependencies:
63
63
  version: "0"
64
64
  type: :development
65
65
  version_requirements: *id003
66
+ - !ruby/object:Gem::Dependency
67
+ name: statsample
68
+ prerelease: false
69
+ requirement: &id004 !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ hash: 3
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ type: :development
79
+ version_requirements: *id004
66
80
  description: An EventMachine Client for Doozer
67
81
  email:
68
82
  - blake.mizerany@gmail.com
@@ -78,10 +92,10 @@ files:
78
92
  - LICENSE
79
93
  - README.md
80
94
  - Rakefile
81
- - bench/gets.rb
82
- - example/getdir_all.rb
95
+ - bench/gs.rb
96
+ - example/getdir.rb
83
97
  - example/readme.rb
84
- - example/walk_all.rb
98
+ - example/walk.rb
85
99
  - example/watch.rb
86
100
  - fraggle.gemspec
87
101
  - lib/fraggle.rb
@@ -1,32 +0,0 @@
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"