tupelo 0.9 → 0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +31 -1
- data/bugs/read-take.rb +19 -0
- data/bugs/take-write.rb +7 -7
- data/example/app-and-tup.rb +11 -8
- data/example/async-transaction.rb +7 -7
- data/example/balance-xfer-locking.rb +13 -13
- data/example/balance-xfer-retry.rb +16 -16
- data/example/balance-xfer.rb +9 -9
- data/example/boolean-match.rb +5 -5
- data/example/bounded-retry.rb +9 -9
- data/example/broker-locking.rb +14 -14
- data/example/broker-optimistic.rb +7 -7
- data/example/cancel.rb +7 -7
- data/example/concurrent-transactions.rb +17 -17
- data/example/custom-class.rb +9 -9
- data/example/custom-search.rb +8 -8
- data/example/fail-and-retry.rb +11 -11
- data/example/hash-tuples.rb +12 -10
- data/example/increment.rb +8 -8
- data/example/load-balancer.rb +2 -1
- data/example/lock-mgr-with-queue.rb +18 -18
- data/example/lock-mgr.rb +18 -18
- data/example/map-reduce-v2.rb +11 -11
- data/example/map-reduce.rb +11 -11
- data/example/matching.rb +5 -5
- data/example/message-bus.rb +6 -3
- data/example/notify.rb +17 -17
- data/example/optimist.rb +9 -9
- data/example/parallel.rb +16 -8
- data/example/pregel/distributed.rb +129 -0
- data/example/pregel/pagerank.rb +72 -0
- data/example/pregel/pregel.rb +102 -0
- data/example/pregel/remote.rb +165 -0
- data/example/pulse.rb +10 -10
- data/example/read-in-trans.rb +15 -15
- data/example/subspace.rb +34 -0
- data/example/take-nowait.rb +1 -0
- data/example/tcp.rb +3 -3
- data/example/timeout-trans.rb +5 -5
- data/example/timeout.rb +10 -9
- data/example/tiny-client.rb +5 -5
- data/example/tiny-server.rb +2 -2
- data/example/transaction-logic.rb +16 -16
- data/example/wait-interrupt.rb +38 -0
- data/example/write-wait.rb +11 -11
- data/lib/tupelo/archiver/tuplespace.rb +5 -1
- data/lib/tupelo/archiver/worker.rb +25 -18
- data/lib/tupelo/client/reader.rb +2 -2
- data/lib/tupelo/client/transaction.rb +79 -36
- data/lib/tupelo/client/tuplespace.rb +1 -0
- data/lib/tupelo/client/worker.rb +107 -13
- data/lib/tupelo/client.rb +36 -2
- data/lib/tupelo/version.rb +1 -1
- data/test/lib/mock-client.rb +4 -0
- data/test/lib/testable-worker.rb +1 -1
- data/test/stress/concurrent-transactions.rb +15 -15
- data/test/system/test-archiver.rb +8 -8
- data/test/unit/test-ops.rb +56 -0
- metadata +72 -68
- data/bugs/write-read.rb +0 -15
- data/example/broker-queue.rb +0 -35
- data/example/child-of-child.rb +0 -34
data/example/tiny-client.rb
CHANGED
@@ -2,13 +2,13 @@ require 'tupelo/app'
|
|
2
2
|
|
3
3
|
svr = "tiny-server.yaml"
|
4
4
|
|
5
|
-
Tupelo.application servers_file: svr do
|
6
|
-
if
|
5
|
+
Tupelo.application servers_file: svr do
|
6
|
+
if owns_servers
|
7
7
|
abort "server not running"
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
p
|
10
|
+
child do
|
11
|
+
write ["Hello", "world!"]
|
12
|
+
p take [nil, nil]
|
13
13
|
end
|
14
14
|
end
|
data/example/tiny-server.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
require 'tupelo/app'
|
2
2
|
|
3
|
-
Tupelo.application do
|
4
|
-
|
3
|
+
Tupelo.application do
|
4
|
+
child do
|
5
5
|
done = false
|
6
6
|
until done do
|
7
|
-
|
8
|
-
op, x, y =
|
7
|
+
transaction do
|
8
|
+
op, x, y = take [String, Numeric, Numeric]
|
9
9
|
# further operations within this transaction can depend on the above.
|
10
10
|
|
11
11
|
case op
|
12
12
|
when "+"
|
13
|
-
|
13
|
+
write [op, x, y, x + y]
|
14
14
|
when "*"
|
15
|
-
|
15
|
+
write [op, x, y, x * y]
|
16
16
|
when "select"
|
17
|
-
_, _, _, z =
|
18
|
-
|
17
|
+
_, _, _, z = take [nil, nil, nil, x..y]
|
18
|
+
write [op, x, y, z]
|
19
19
|
when "stop"
|
20
20
|
done = true
|
21
21
|
end
|
@@ -23,18 +23,18 @@ Tupelo.application do |app|
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
results =
|
26
|
+
child do
|
27
|
+
write ["+", 1, 2]
|
28
|
+
results = read ["+", 1, 2, nil]
|
29
29
|
p results
|
30
30
|
|
31
|
-
|
32
|
-
results =
|
31
|
+
write ["*", 3, 4]
|
32
|
+
results = read ["*", 3, 4, nil]
|
33
33
|
p results
|
34
34
|
|
35
|
-
|
36
|
-
p
|
35
|
+
write ["select", 10, 20]
|
36
|
+
p read ["select", 10, 20, nil]
|
37
37
|
|
38
|
-
|
38
|
+
write ["stop", 0, 0]
|
39
39
|
end
|
40
40
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# This example shows how a transaction can be used to wait for some event,
|
2
|
+
# but interrupt the wait when some other event happens.
|
3
|
+
|
4
|
+
require 'tupelo/app'
|
5
|
+
|
6
|
+
Tupelo.application do
|
7
|
+
child do
|
8
|
+
log.progname = "host"
|
9
|
+
|
10
|
+
transaction do
|
11
|
+
mode = read(mode: nil)["mode"]
|
12
|
+
log "waiting for visitor to arrive by #{mode}"
|
13
|
+
read ["visitor arrives"]
|
14
|
+
end
|
15
|
+
|
16
|
+
log "welcome!"
|
17
|
+
end
|
18
|
+
|
19
|
+
child do
|
20
|
+
log.progname = "visitor"
|
21
|
+
|
22
|
+
log "I think I am coming by train"
|
23
|
+
write_wait mode: "train"
|
24
|
+
sleep 1
|
25
|
+
|
26
|
+
log "changing my mind, coming by plane"
|
27
|
+
transaction {take mode: nil; write mode: "plane"}
|
28
|
+
sleep 1
|
29
|
+
|
30
|
+
log "changing my mind again, coming by car"
|
31
|
+
transaction {take mode: nil; write mode: "car"}
|
32
|
+
sleep 1
|
33
|
+
|
34
|
+
log "hello!"
|
35
|
+
write_wait ["visitor arrives"]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
data/example/write-wait.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
require 'tupelo/app'
|
2
2
|
|
3
|
-
Tupelo.application do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
w =
|
8
|
-
p
|
3
|
+
Tupelo.application do
|
4
|
+
local do
|
5
|
+
write [1]
|
6
|
+
write [2]
|
7
|
+
w = write [3]
|
8
|
+
p read_all
|
9
9
|
w.wait # wait for the write to come back and be applied to the client
|
10
|
-
p
|
10
|
+
p read_all
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
p
|
12
|
+
write [4]
|
13
|
+
write [5]
|
14
|
+
write_wait [6]
|
15
|
+
p read_all
|
16
16
|
end
|
17
17
|
end
|
@@ -5,9 +5,13 @@ class Tupelo::Archiver
|
|
5
5
|
attr_reader :zero_tolerance
|
6
6
|
|
7
7
|
def initialize(zero_tolerance: Tupelo::Archiver::ZERO_TOLERANCE)
|
8
|
+
@zero_tolerance = zero_tolerance
|
9
|
+
clear
|
10
|
+
end
|
11
|
+
|
12
|
+
def clear
|
8
13
|
@counts = Hash.new(0) # tuple => count
|
9
14
|
@nzero = 0
|
10
|
-
@zero_tolerance = zero_tolerance
|
11
15
|
end
|
12
16
|
|
13
17
|
# note: multiple equal tuples are yielded once
|
@@ -38,7 +38,7 @@ class Tupelo::Archiver
|
|
38
38
|
stream = client.arc_server_stream_for req.io
|
39
39
|
|
40
40
|
begin
|
41
|
-
op,
|
41
|
+
op, sub_delta, tick = stream.read
|
42
42
|
rescue EOFError
|
43
43
|
log.debug {"#{stream.peer_name} disconnected from archiver"}
|
44
44
|
return
|
@@ -48,18 +48,18 @@ class Tupelo::Archiver
|
|
48
48
|
|
49
49
|
log.info {
|
50
50
|
"#{stream.peer_name} requested #{op.inspect} at tick=#{tick}" +
|
51
|
-
(
|
51
|
+
(sub_delta ? " for #{sub_delta}" : "")}
|
52
52
|
|
53
53
|
if tick <= global_tick
|
54
|
-
fork_for_op op,
|
54
|
+
fork_for_op op, sub_delta, tick, stream, req
|
55
55
|
else
|
56
56
|
at_tick tick do
|
57
|
-
fork_for_op op,
|
57
|
+
fork_for_op op, sub_delta, tick, stream, req
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
def fork_for_op op,
|
62
|
+
def fork_for_op op, sub_delta, tick, stream, req
|
63
63
|
fork do
|
64
64
|
begin
|
65
65
|
case op
|
@@ -68,7 +68,7 @@ class Tupelo::Archiver
|
|
68
68
|
when "get range" ### handle this in Funl::HistoryWorker
|
69
69
|
raise "Unimplemented" ###
|
70
70
|
when GET_TUPLESPACE
|
71
|
-
send_tuplespace stream,
|
71
|
+
send_tuplespace stream, sub_delta
|
72
72
|
else
|
73
73
|
raise "Unknown operation: #{op.inspect}"
|
74
74
|
end
|
@@ -94,18 +94,32 @@ class Tupelo::Archiver
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
-
def send_tuplespace stream,
|
97
|
+
def send_tuplespace stream, sub_delta
|
98
98
|
log.info {
|
99
99
|
"send_tuplespace to #{stream.peer_name} " +
|
100
100
|
"at tick #{global_tick.inspect} " +
|
101
|
-
(
|
101
|
+
(sub_delta ? " with sub_delta #{sub_delta.inspect}" : "")}
|
102
102
|
|
103
103
|
stream << [global_tick]
|
104
104
|
|
105
|
-
|
106
|
-
|
105
|
+
## better: make use of sub_delta["subscribed_*"] to reduce what
|
106
|
+
## has to be sent.
|
107
|
+
|
108
|
+
if sub_delta["request_all"]
|
107
109
|
tuplespace.each do |tuple, count|
|
108
|
-
|
110
|
+
count.times do ## just dump and send str * count?
|
111
|
+
stream << tuple ## optimize this, and cache the serial
|
112
|
+
## optimization: use stream.write_to_buffer
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
else
|
117
|
+
tags = sub_delta["request_tags"] ## use set
|
118
|
+
subs = subspaces.select {|sub| tags.include? sub.tag}
|
119
|
+
|
120
|
+
tuplespace.each do |tuple, count|
|
121
|
+
## alternately, store tags with tuples (risk if dynamic spaces)
|
122
|
+
if subs.any? {|sub| sub === tuple}
|
109
123
|
count.times do
|
110
124
|
stream << tuple
|
111
125
|
## optimization: use stream.write_to_buffer
|
@@ -114,13 +128,6 @@ class Tupelo::Archiver
|
|
114
128
|
## optimize this if templates have simple form, such as
|
115
129
|
## [ [str1, nil, ...], [str2, nil, ...], ...]
|
116
130
|
end
|
117
|
-
else
|
118
|
-
tuplespace.each do |tuple, count|
|
119
|
-
count.times do ## just dump and send str * count?
|
120
|
-
stream << tuple ## optimize this, and cache the serial
|
121
|
-
## optimization: use stream.write_to_buffer
|
122
|
-
end
|
123
|
-
end
|
124
131
|
end
|
125
132
|
|
126
133
|
stream << nil # terminator
|
data/lib/tupelo/client/reader.rb
CHANGED
@@ -61,9 +61,9 @@ class Tupelo::Client
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def wait
|
64
|
-
@client.log.debug {"waiting for #{
|
64
|
+
@client.log.debug {"waiting for #{inspect}"}
|
65
65
|
r = queue.pop
|
66
|
-
@client.log.debug {"finished waiting for #{
|
66
|
+
@client.log.debug {"finished waiting for #{inspect}"}
|
67
67
|
r
|
68
68
|
end
|
69
69
|
|
@@ -103,10 +103,13 @@ class Tupelo::Client
|
|
103
103
|
attr_reader :pulses
|
104
104
|
attr_reader :take_templates
|
105
105
|
attr_reader :read_templates
|
106
|
-
attr_reader :
|
107
|
-
attr_reader :
|
106
|
+
attr_reader :take_tuples_for_remote
|
107
|
+
attr_reader :take_tuples_for_local
|
108
|
+
attr_reader :read_tuples_for_remote
|
109
|
+
attr_reader :read_tuples_for_local
|
108
110
|
attr_reader :granted_tuples
|
109
111
|
attr_reader :missing
|
112
|
+
attr_reader :tags
|
110
113
|
|
111
114
|
STATES = [
|
112
115
|
OPEN = :open, # initial state
|
@@ -140,10 +143,13 @@ class Tupelo::Client
|
|
140
143
|
@pulses = []
|
141
144
|
@take_templates = []
|
142
145
|
@read_templates = []
|
143
|
-
@
|
144
|
-
@
|
146
|
+
@take_tuples_for_remote = []
|
147
|
+
@take_tuples_for_local = []
|
148
|
+
@read_tuples_for_remote = []
|
149
|
+
@read_tuples_for_local = []
|
145
150
|
@granted_tuples = nil
|
146
151
|
@missing = nil
|
152
|
+
@tags = nil
|
147
153
|
@_take_nowait = nil
|
148
154
|
@_read_nowait = nil
|
149
155
|
|
@@ -181,6 +187,7 @@ class Tupelo::Client
|
|
181
187
|
|
182
188
|
ops = [ ["write", writes], ["pulse", pulses],
|
183
189
|
["take", take_templates], ["read", read_templates] ]
|
190
|
+
## exclude templates that were satisfied locally by writes
|
184
191
|
ops.map! do |label, tuples|
|
185
192
|
["#{label} #{tuples.map(&:inspect).join(", ")}"] unless tuples.empty?
|
186
193
|
end
|
@@ -209,7 +216,10 @@ class Tupelo::Client
|
|
209
216
|
raise TransactionStateError, "not open: #{inspect}" unless open? or
|
210
217
|
failed?
|
211
218
|
check_tuples tuples
|
212
|
-
|
219
|
+
blobber = worker.blobber
|
220
|
+
@writes.concat tuples.map {|t| blobber.load(blobber.dump(t))}
|
221
|
+
# this is both to de-alias (esp. in case of marshal or yaml) and
|
222
|
+
# to convert symbols to strings (in case of msgpack or json)
|
213
223
|
nil
|
214
224
|
end
|
215
225
|
|
@@ -218,7 +228,8 @@ class Tupelo::Client
|
|
218
228
|
raise TransactionStateError, "not open: #{inspect}" unless open? or
|
219
229
|
failed?
|
220
230
|
check_tuples tuples
|
221
|
-
|
231
|
+
blobber = worker.blobber
|
232
|
+
@pulses.concat tuples.map {|t| blobber.load(blobber.dump(t))}
|
222
233
|
nil
|
223
234
|
end
|
224
235
|
|
@@ -233,7 +244,7 @@ class Tupelo::Client
|
|
233
244
|
log.debug {"asking worker to take #{template_spec.inspect}"}
|
234
245
|
worker_push self
|
235
246
|
wait
|
236
|
-
return
|
247
|
+
return take_tuples_for_local.last
|
237
248
|
end
|
238
249
|
|
239
250
|
def take_nowait template_spec
|
@@ -249,7 +260,7 @@ class Tupelo::Client
|
|
249
260
|
log.debug {"asking worker to take_nowait #{template_spec.inspect}"}
|
250
261
|
worker_push self
|
251
262
|
wait
|
252
|
-
return
|
263
|
+
return take_tuples_for_local[i]
|
253
264
|
end
|
254
265
|
|
255
266
|
# transaction applies only if template has a match
|
@@ -263,7 +274,7 @@ class Tupelo::Client
|
|
263
274
|
log.debug {"asking worker to read #{template_spec.inspect}"}
|
264
275
|
worker_push self
|
265
276
|
wait
|
266
|
-
return
|
277
|
+
return read_tuples_for_local.last
|
267
278
|
end
|
268
279
|
|
269
280
|
def read_nowait template_spec
|
@@ -279,7 +290,7 @@ class Tupelo::Client
|
|
279
290
|
log.debug {"asking worker to read #{template_spec.inspect}"}
|
280
291
|
worker_push self
|
281
292
|
wait
|
282
|
-
return
|
293
|
+
return read_tuples_for_local[i]
|
283
294
|
end
|
284
295
|
|
285
296
|
def abort
|
@@ -299,8 +310,9 @@ class Tupelo::Client
|
|
299
310
|
def commit
|
300
311
|
if open?
|
301
312
|
if @writes.empty? and @pulses.empty? and
|
302
|
-
@
|
303
|
-
|
313
|
+
@take_tuples_for_remote.all? {|t| t.nil?} and
|
314
|
+
@read_tuples_for_remote.all? {|t| t.nil?}
|
315
|
+
@global_tick = worker.global_tick ## ok?
|
304
316
|
done!
|
305
317
|
log.info {"not committing empty transaction"}
|
306
318
|
else
|
@@ -352,11 +364,16 @@ class Tupelo::Client
|
|
352
364
|
end
|
353
365
|
end
|
354
366
|
|
355
|
-
def async
|
356
|
-
raise ArgumentError, "must provide block" unless
|
367
|
+
def async &block
|
368
|
+
raise ArgumentError, "must provide block" unless block
|
357
369
|
TransactionThread.new(self) do ## Fiber?
|
358
370
|
begin
|
359
|
-
val =
|
371
|
+
val =
|
372
|
+
if block.arity == 0
|
373
|
+
instance_eval &block
|
374
|
+
else
|
375
|
+
yield self
|
376
|
+
end
|
360
377
|
commit.wait
|
361
378
|
val
|
362
379
|
rescue TransactionFailure => ex
|
@@ -379,19 +396,21 @@ class Tupelo::Client
|
|
379
396
|
raise unless in_worker_thread?
|
380
397
|
|
381
398
|
if new_tuple
|
382
|
-
return true if
|
399
|
+
return true if take_tuples_for_local.all? and read_tuples_for_local.all?
|
383
400
|
|
384
|
-
|
401
|
+
take_tuples_for_local.each_with_index do |tuple, i|
|
385
402
|
if not tuple and take_templates[i] === new_tuple
|
386
|
-
|
403
|
+
take_tuples_for_local[i] = new_tuple
|
404
|
+
take_tuples_for_remote[i] = new_tuple
|
387
405
|
log.debug {"prepared #{inspect} with #{new_tuple}"}
|
388
406
|
break
|
389
407
|
end
|
390
408
|
end
|
391
409
|
|
392
|
-
|
410
|
+
read_tuples_for_local.each_with_index do |tuple, i|
|
393
411
|
if not tuple and read_templates[i] === new_tuple
|
394
|
-
|
412
|
+
read_tuples_for_local[i] = new_tuple
|
413
|
+
read_tuples_for_remote[i] = new_tuple
|
395
414
|
log.debug {"prepared #{inspect} with #{new_tuple}"}
|
396
415
|
end
|
397
416
|
end
|
@@ -399,11 +418,22 @@ class Tupelo::Client
|
|
399
418
|
else
|
400
419
|
## optimization: use tuple cache
|
401
420
|
skip = nil
|
402
|
-
(
|
403
|
-
|
404
|
-
|
405
|
-
if
|
406
|
-
|
421
|
+
(take_tuples_for_local.size...take_templates.size).each do |i|
|
422
|
+
template = take_templates[i]
|
423
|
+
|
424
|
+
if wt = @writes.find {|tuple| template === tuple}
|
425
|
+
take_tuples_for_remote[i] = nil
|
426
|
+
take_tuples_for_local[i] = wt.dup
|
427
|
+
@writes.delete wt
|
428
|
+
next
|
429
|
+
end
|
430
|
+
|
431
|
+
take_tuples_for_local[i] = take_tuples_for_remote[i] =
|
432
|
+
worker.tuplespace.find_match_for(template,
|
433
|
+
distinct_from: take_tuples_for_local)
|
434
|
+
|
435
|
+
if take_tuples_for_local[i]
|
436
|
+
log.debug {"prepared #{inspect} with #{take_tuples_for_local[i]}"}
|
407
437
|
else
|
408
438
|
if @_take_nowait and @_take_nowait[i]
|
409
439
|
(skip ||= []) << i
|
@@ -412,17 +442,28 @@ class Tupelo::Client
|
|
412
442
|
end
|
413
443
|
|
414
444
|
skip and skip.reverse_each do |i|
|
415
|
-
|
445
|
+
take_tuples_for_local.delete_at i
|
446
|
+
take_tuples_for_remote.delete_at i
|
416
447
|
take_templates.delete_at i
|
417
448
|
@_take_nowait.delete i
|
418
449
|
end
|
419
450
|
|
420
451
|
skip = nil
|
421
|
-
(
|
422
|
-
|
423
|
-
|
424
|
-
if
|
425
|
-
|
452
|
+
(read_tuples_for_local.size...read_templates.size).each do |i|
|
453
|
+
template = read_templates[i]
|
454
|
+
|
455
|
+
if wt = @writes.find {|tuple| template === tuple}
|
456
|
+
read_tuples_for_remote[i] = nil
|
457
|
+
read_tuples_for_local[i] = wt.dup
|
458
|
+
next
|
459
|
+
end
|
460
|
+
|
461
|
+
read_tuples_for_local[i] = read_tuples_for_remote[i] =
|
462
|
+
worker.tuplespace.find_match_for(template,
|
463
|
+
distinct_from: take_tuples_for_local)
|
464
|
+
|
465
|
+
if read_tuples_for_local[i]
|
466
|
+
log.debug {"prepared #{inspect} with #{read_tuples_for_local[i]}"}
|
426
467
|
else
|
427
468
|
if @_read_nowait and @_read_nowait[i]
|
428
469
|
(skip ||= []) << i
|
@@ -431,7 +472,8 @@ class Tupelo::Client
|
|
431
472
|
end
|
432
473
|
|
433
474
|
skip and skip.reverse_each do |i|
|
434
|
-
|
475
|
+
read_tuples_for_local.delete_at i
|
476
|
+
read_tuples_for_remote.delete_at i
|
435
477
|
read_templates.delete_at i
|
436
478
|
@_read_nowait.delete i
|
437
479
|
end
|
@@ -441,11 +483,12 @@ class Tupelo::Client
|
|
441
483
|
## convert cancelling take/write to read
|
442
484
|
## check that remaining take/read tuples do not cross a space boundary
|
443
485
|
|
444
|
-
if
|
486
|
+
if take_tuples_for_local.all? and read_tuples_for_local.all?
|
445
487
|
@queue << true
|
446
488
|
log.debug {
|
447
489
|
"prepared #{inspect}, " +
|
448
|
-
"take tuples: #{
|
490
|
+
"take tuples: #{take_tuples_for_local}, " +
|
491
|
+
"read tuples: #{read_tuples_for_local}"}
|
449
492
|
end
|
450
493
|
|
451
494
|
return true
|
@@ -455,7 +498,7 @@ class Tupelo::Client
|
|
455
498
|
return false if closed? or failed? # might change during this method
|
456
499
|
raise unless in_worker_thread?
|
457
500
|
|
458
|
-
@
|
501
|
+
@take_tuples_for_remote.each do |tuple|
|
459
502
|
if tuple == missing_tuple ## might be false positive, but ok
|
460
503
|
fail [missing_tuple]
|
461
504
|
## optimization: manage tuple cache
|
@@ -463,7 +506,7 @@ class Tupelo::Client
|
|
463
506
|
end
|
464
507
|
end
|
465
508
|
|
466
|
-
@
|
509
|
+
@read_tuples_for_remote.each do |tuple|
|
467
510
|
if tuple == missing_tuple ## might be false positive, but ok
|
468
511
|
fail [missing_tuple]
|
469
512
|
return false
|