tupelo 0.9 → 0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -1
  3. data/bugs/read-take.rb +19 -0
  4. data/bugs/take-write.rb +7 -7
  5. data/example/app-and-tup.rb +11 -8
  6. data/example/async-transaction.rb +7 -7
  7. data/example/balance-xfer-locking.rb +13 -13
  8. data/example/balance-xfer-retry.rb +16 -16
  9. data/example/balance-xfer.rb +9 -9
  10. data/example/boolean-match.rb +5 -5
  11. data/example/bounded-retry.rb +9 -9
  12. data/example/broker-locking.rb +14 -14
  13. data/example/broker-optimistic.rb +7 -7
  14. data/example/cancel.rb +7 -7
  15. data/example/concurrent-transactions.rb +17 -17
  16. data/example/custom-class.rb +9 -9
  17. data/example/custom-search.rb +8 -8
  18. data/example/fail-and-retry.rb +11 -11
  19. data/example/hash-tuples.rb +12 -10
  20. data/example/increment.rb +8 -8
  21. data/example/load-balancer.rb +2 -1
  22. data/example/lock-mgr-with-queue.rb +18 -18
  23. data/example/lock-mgr.rb +18 -18
  24. data/example/map-reduce-v2.rb +11 -11
  25. data/example/map-reduce.rb +11 -11
  26. data/example/matching.rb +5 -5
  27. data/example/message-bus.rb +6 -3
  28. data/example/notify.rb +17 -17
  29. data/example/optimist.rb +9 -9
  30. data/example/parallel.rb +16 -8
  31. data/example/pregel/distributed.rb +129 -0
  32. data/example/pregel/pagerank.rb +72 -0
  33. data/example/pregel/pregel.rb +102 -0
  34. data/example/pregel/remote.rb +165 -0
  35. data/example/pulse.rb +10 -10
  36. data/example/read-in-trans.rb +15 -15
  37. data/example/subspace.rb +34 -0
  38. data/example/take-nowait.rb +1 -0
  39. data/example/tcp.rb +3 -3
  40. data/example/timeout-trans.rb +5 -5
  41. data/example/timeout.rb +10 -9
  42. data/example/tiny-client.rb +5 -5
  43. data/example/tiny-server.rb +2 -2
  44. data/example/transaction-logic.rb +16 -16
  45. data/example/wait-interrupt.rb +38 -0
  46. data/example/write-wait.rb +11 -11
  47. data/lib/tupelo/archiver/tuplespace.rb +5 -1
  48. data/lib/tupelo/archiver/worker.rb +25 -18
  49. data/lib/tupelo/client/reader.rb +2 -2
  50. data/lib/tupelo/client/transaction.rb +79 -36
  51. data/lib/tupelo/client/tuplespace.rb +1 -0
  52. data/lib/tupelo/client/worker.rb +107 -13
  53. data/lib/tupelo/client.rb +36 -2
  54. data/lib/tupelo/version.rb +1 -1
  55. data/test/lib/mock-client.rb +4 -0
  56. data/test/lib/testable-worker.rb +1 -1
  57. data/test/stress/concurrent-transactions.rb +15 -15
  58. data/test/system/test-archiver.rb +8 -8
  59. data/test/unit/test-ops.rb +56 -0
  60. metadata +72 -68
  61. data/bugs/write-read.rb +0 -15
  62. data/example/broker-queue.rb +0 -35
  63. data/example/child-of-child.rb +0 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 241bdc610aa513222cd452c8624bcf69cd9b2686
4
- data.tar.gz: 674756c0a1156745007199a4e476df72df7183ef
3
+ metadata.gz: 892628e201d400fa9592a01b1fd62c4bb8e09ab5
4
+ data.tar.gz: 2ca45f4f124ad6db32e2880557004f5c0553cf9f
5
5
  SHA512:
6
- metadata.gz: c6b2e338a9d11abfe109ed608b8b51807bc69994a75824978c37f0b2ad00327efc080b8e8ee1eb85303b9fee3961045fbae1b2b9bc6fa5c6776a743e7f818f67
7
- data.tar.gz: 026cf80f84292493865f5f644f54ce883defa9351d99c6268c02791d500edd88cbeaa0cc4c25c556d0a96f3cee424f33dea1a4d97d1f421bfd1532803a323d21
6
+ metadata.gz: 0b8bfcdbb7143f543372cd0bdad95feb49305a47e57e0368146e3c224f33e1fddb261f9f019ec4c4a503a4250d91ecc653a93e5792c27e4f47cfd7ca33727a76
7
+ data.tar.gz: 931b57069c7e06452429eb71e083c568be953a1e37de54cd1b9541107c6a79884e7d64645ed8765777c9ede5f18589e3c35d5057e946e82b8daa70c18180b49d
data/README.md CHANGED
@@ -21,6 +21,7 @@ Documentation
21
21
  ============
22
22
 
23
23
  * [FAQ](doc/faq.md)
24
+ * [Subspaces](doc/subspace.md)
24
25
 
25
26
  Getting started
26
27
  ==========
@@ -110,7 +111,7 @@ Getting started
110
111
  ...
111
112
  end
112
113
 
113
- Note that a local match is still not a guarantee of `x_final == x_optimistic`. Another process may take `x_optimistic` first, and the take will be re-executed. (Think of #take_nowait as a way of saying "take a match, but don't bother trying if there is no match known at this time.")
114
+ Note that a local match is still not a guarantee of `x_final == x_optimistic`. Another process may take `x_optimistic` first, and the take will be re-executed. (Think of #take_nowait as a way of saying "take a match, but don't bother trying if there is no match known at this time.") Similarly, #take_nowait returning nil is not a guarantee that a match does not exist: another process could have written a match later than the time of the local search.
114
115
 
115
116
  Perform a general transaction:
116
117
 
@@ -124,7 +125,17 @@ Getting started
124
125
  end
125
126
 
126
127
  Note that the block may execute more than once, if there is competition for the tuples that you are trying to #take or #read. When the block exits, however, the transaction is final and universally accepted by all clients.
128
+
129
+ Tuples written or taken during a transaction affect subsequent operations in the transaction without modifying the tuplespace or affecting other concurrent transactions (until the transaction completes):
127
130
 
131
+ transaction do |t|
132
+ t.write [3]
133
+ p t.read [3] # => 3
134
+ p read_all # => [] # note read_all called on client, not trans.
135
+ t.take [3]
136
+ p t.read_nowait [3] # => nil
137
+ end
138
+
128
139
  You can timeout a transaction:
129
140
 
130
141
  transaction timeout: 1 do
@@ -180,6 +191,8 @@ A tuplespace is a service for coordination, configuration, and control of concur
180
191
 
181
192
  See https://en.wikipedia.org/wiki/Tuple_space for general information and history. This project is strongly influenced by Masatoshi Seki's Rinda implementation, part of the Ruby standard library. See http://pragprog.com/book/sidruby/the-druby-book for a good introduction to rinda and druby.
182
193
 
194
+ See http://dbmsmusings.blogspot.com/2010/08/problems-with-acid-and-how-to-fix-them.html for an explanation of the imporance of determinism in distributed transaction systems.
195
+
183
196
  What is a tuple?
184
197
  ----------------
185
198
 
@@ -210,6 +223,8 @@ In other words, a tuple is a fairly general object, though this depends on the s
210
223
 
211
224
  It's kind of like a "JSON object", except that, when using the json serializer, the hash keys can only be strings. In the msgpack case, keys have no special limitations. In the case of the marshal and yaml modes, tuples can contain many other kinds of objects.
212
225
 
226
+ The empty tuples `[]` and `{}` are allowed, but bare values such as `3.14` or `false` are not tuples by themselves.
227
+
213
228
  One other thing to keep in mind: in the array case, the order of the elements is significant. In the hash case, the order is not significant. So these are both true:
214
229
 
215
230
  [1,2] != [2,1]
@@ -292,6 +307,17 @@ Transactions have a significant disadvantage compared to using take/write to loc
292
307
 
293
308
  Transactions do have an advantage over using take/write to lock/unlock tuples: there is no possibility of deadlock. See [example/deadlock.rb](example/deadlock.rb) and [example/parallel.rb](example/parallel.rb).
294
309
 
310
+ Another advantage of tranactions is that it is possible to guarantee continuous existence of a time-series of tuples. For example, suppose that tuples matching `{step: Numeric}` indicate the progress of some activity. With transactions, you can guarantee that there is exactly one matching tuple at any time. So any client which reads this template will find a match without blocking.
311
+
312
+ Another use of transactions: forcing a retry when something changes:
313
+
314
+ transaction do
315
+ step = read(step: nil)["step"]
316
+ take value: nil, step: step
317
+ end
318
+
319
+ This code waits on the existence of a value, but retries if the step changes while waiting. See example/pregel/distributed.rb for a use of this techinique.
320
+
295
321
  Tupelo transactions are ACID in the following sense. They are Atomic and Isolated -- this is enforced by the transaction processing in each client. Consistency is enforced by the underlying message sequencer: each client's copy of the space is the deterministic result of the same sequence of operations. Durability is optional, but can be provided by the persistent archiver or other clients.
296
322
 
297
323
  On the CAP spectrum, tupelo tends towards consistency: for all clients, write and take operations are applied in the same order, so the state of the entire system up through a given tick of discrete time is universally agreed upon. Of course, because of the difficulties of distributed systems, one client may not yet have seen the same range of ticks as another.
@@ -404,6 +430,8 @@ To compare
404
430
 
405
431
  * doozer, etcd
406
432
 
433
+ * serf -- tupelo has lower latency and is transactional, but at a cost compared to serf; tupelo semantics is closer to databases
434
+
407
435
  * arakoon
408
436
 
409
437
  * hazelcast
@@ -471,6 +499,8 @@ Each inner serialization method ("blobber") has its own advantages and drawbacks
471
499
 
472
500
  For most purposes, msgpack is a good choice, so it is the default.
473
501
 
502
+ The sending client's tupelo library must make sure that there is no aliasing within the list of tuples (this is only an issue for Marshal and YAML, since msgpack and json do not support references).
503
+
474
504
 
475
505
  Development
476
506
  ===========
data/bugs/read-take.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'tupelo/app'
2
+
3
+ Tupelo.application do
4
+ local do
5
+ write_wait [1]
6
+
7
+ note = notifier
8
+
9
+ transaction do
10
+ read [1]
11
+ take [1]
12
+ end
13
+
14
+ note.wait
15
+ status, tick, cid, op = note.wait
16
+ p op # should "take [1]", not "take [1]; read [1]"
17
+ # this is just an optimization, not really a bug
18
+ end
19
+ end
data/bugs/take-write.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  require 'tupelo/app'
2
2
 
3
- Tupelo.application do |app|
4
- app.local do |client|
5
- client.write_wait [1]
3
+ Tupelo.application do
4
+ local do
5
+ write_wait [1]
6
6
 
7
- note = client.notifier
7
+ note = notifier
8
8
 
9
- client.transaction do |t|
10
- x = t.take [1]
11
- t.write x
9
+ transaction do
10
+ x = take [1]
11
+ write x
12
12
  end
13
13
 
14
14
  note.wait
@@ -11,19 +11,22 @@
11
11
  #
12
12
  # w [2]
13
13
  # w [3]
14
- # ra [nil] # => [[5]]
14
+ # ra # => [[5]]
15
15
  # w [7.4]
16
- # ra [nil] # => [[12.4]]
16
+ # ra # => [[12.4]]
17
17
 
18
18
  require 'tupelo/app'
19
19
 
20
- Tupelo.application do |app|
21
- app.child do |client|
20
+ filename = "servers-#$$.yaml"
21
+ puts "run this in another shell: tup #{filename}"
22
+
23
+ Tupelo.application servers_file: filename do
24
+ child do
22
25
  loop do
23
- client.transaction do |t|
24
- x, = t.take [Numeric]
25
- y, = t.take [Numeric]
26
- t.write [x + y]
26
+ transaction do
27
+ x, = take [Numeric]
28
+ y, = take [Numeric]
29
+ write [x + y]
27
30
  end
28
31
  end
29
32
  end
@@ -2,15 +2,15 @@ require 'tupelo/app'
2
2
 
3
3
  # see also cancel.rb
4
4
 
5
- Tupelo.application do |app|
6
- app.child do |client|
7
- t = client.transaction.async do |t|
8
- t.write ["pong"]
9
- t.take ["ping"]
5
+ Tupelo.application do
6
+ child do
7
+ t = transaction.async do
8
+ write ["pong"]
9
+ take ["ping"]
10
10
  end
11
11
 
12
- client.write ["ping"]
13
- puts client.take ["pong"]
12
+ write ["ping"]
13
+ puts take ["pong"]
14
14
  puts t.value
15
15
  end
16
16
  end
@@ -1,28 +1,28 @@
1
1
  require 'tupelo/app'
2
2
 
3
- Tupelo.application do |app|
4
- app.child do |client|
5
- client.write(
3
+ Tupelo.application do
4
+ child do
5
+ write(
6
6
  {name: "alice", balance: 1000},
7
7
  {name: "bob", balance: 200}
8
8
  )
9
9
  10.times do |i|
10
- alice = client.take(name: "alice", balance: Numeric)
11
- client.log alice
10
+ alice = take(name: "alice", balance: Numeric)
11
+ log alice
12
12
  alice = alice.dup
13
13
  alice["balance"] -= 10
14
- client.write_wait alice
14
+ write_wait alice
15
15
  sleep 0.1
16
16
  end
17
17
 
18
- client.log client.read_all(name: /^(?:alice|bob)$/, balance: nil)
18
+ log read_all(name: /^(?:alice|bob)$/, balance: nil)
19
19
  end
20
20
 
21
- app.child do |client|
21
+ child do
22
22
  sleep 0.3
23
23
 
24
- src = client.take(name: "alice", balance: Numeric)
25
- dst = client.take(name: "bob", balance: Numeric)
24
+ src = take(name: "alice", balance: Numeric)
25
+ dst = take(name: "bob", balance: Numeric)
26
26
 
27
27
  if src["balance"] < 500
28
28
  abort "insufficient funds -- not attempting transfer"
@@ -41,10 +41,10 @@ Tupelo.application do |app|
41
41
  src["balance"] -= 500
42
42
  dst["balance"] += 500
43
43
 
44
- w = client.write src, dst
45
- client.log "attempting to set #{[src, dst]}"
44
+ w = write src, dst
45
+ log "attempting to set #{[src, dst]}"
46
46
 
47
47
  w.wait
48
- client.log client.read_all(name: /^(?:alice|bob)$/, balance: nil)
48
+ log read_all(name: /^(?:alice|bob)$/, balance: nil)
49
49
  end
50
50
  end
@@ -1,27 +1,27 @@
1
1
  require 'tupelo/app'
2
2
 
3
- Tupelo.application do |app|
4
- app.child do |client|
5
- client.write(
3
+ Tupelo.application do
4
+ child do
5
+ write(
6
6
  {name: "alice", balance: 1000},
7
7
  {name: "bob", balance: 200}
8
8
  )
9
9
  10.times do |i|
10
- alice = client.take(name: "alice", balance: Numeric)
11
- client.log alice
10
+ alice = take(name: "alice", balance: Numeric)
11
+ log alice
12
12
  alice = alice.dup
13
13
  alice["balance"] -= 10
14
- client.write_wait alice
14
+ write_wait alice
15
15
  sleep 0.1
16
16
  end
17
17
 
18
- client.log client.read_all(name: /^(?:alice|bob)$/, balance: nil)
18
+ log read_all(name: /^(?:alice|bob)$/, balance: nil)
19
19
  end
20
20
 
21
- app.child do |client|
22
- client.transaction do |t|
23
- src = t.take(name: "alice", balance: Numeric)
24
- dst = t.take(name: "bob", balance: Numeric)
21
+ child do
22
+ transaction do
23
+ src = take(name: "alice", balance: Numeric)
24
+ dst = take(name: "bob", balance: Numeric)
25
25
 
26
26
  if src["balance"] < 500
27
27
  abort "insufficient funds -- not attempting transfer"
@@ -37,19 +37,19 @@ Tupelo.application do |app|
37
37
  # force fail -- the tuples this client is trying to take
38
38
  # will be gone when it wakes up
39
39
 
40
- client.log "attempting to set #{[src, dst]}"
41
- t.write src, dst
40
+ log "attempting to set #{[src, dst]}"
41
+ write src, dst
42
42
 
43
43
  if false # enable this to see how failures are retried
44
44
  begin
45
- t.commit.wait
45
+ commit.wait
46
46
  rescue => ex
47
- client.log "retrying after #{ex}"
47
+ log "retrying after #{ex}"
48
48
  raise
49
49
  end
50
50
  end
51
51
  end
52
52
 
53
- client.log client.read_all(name: /^(?:alice|bob)$/, balance: nil)
53
+ log read_all(name: /^(?:alice|bob)$/, balance: nil)
54
54
  end
55
55
  end
@@ -1,17 +1,17 @@
1
1
  require 'tupelo/app'
2
2
 
3
- Tupelo.application do |app|
4
- app.child do |client|
5
- client.write(
3
+ Tupelo.application do
4
+ child do
5
+ write(
6
6
  {name: "alice", balance: 1000},
7
7
  {name: "bob", balance: 200}
8
8
  )
9
9
  end
10
10
 
11
- app.child do |client|
12
- client.transaction do |t|
13
- src = t.take(name: "alice", balance: Numeric)
14
- dst = t.take(name: "bob", balance: Numeric)
11
+ child do
12
+ transaction do
13
+ src = take(name: "alice", balance: Numeric)
14
+ dst = take(name: "bob", balance: Numeric)
15
15
 
16
16
  if src["balance"] < 500
17
17
  abort "insufficient funds -- not attempting transfer"
@@ -23,11 +23,11 @@ Tupelo.application do |app|
23
23
  src["balance"] -= 500
24
24
  dst["balance"] += 500
25
25
 
26
- t.write src, dst
26
+ write src, dst
27
27
  end
28
28
  # transaction will block if balances have changed since the read.
29
29
  # see balance-xfer-retry.rb
30
30
 
31
- client.log client.read_all(name: /^(?:alice|bob)$/, balance: nil)
31
+ log read_all(name: /^(?:alice|bob)$/, balance: nil)
32
32
  end
33
33
  end
@@ -1,15 +1,15 @@
1
1
  require 'tupelo/app'
2
2
  require 'tupelo/util/boolean'
3
3
 
4
- Tupelo.application do |app|
5
- app.local do |client|
6
- tm = client.match_any [0..2, String], [3..5, Hash]
4
+ Tupelo.application do
5
+ local do
6
+ tm = match_any [0..2, String], [3..5, Hash]
7
7
 
8
- client.write(
8
+ write(
9
9
  [0, "a"], [1, {b: 0}], [2, "c"],
10
10
  [3, "a"], [4, {b: 0}], [5, "c"]
11
11
  ).wait
12
12
 
13
- client.log client.read_all tm
13
+ log read_all tm
14
14
  end
15
15
  end
@@ -3,32 +3,32 @@ require 'tupelo/app'
3
3
  N = 2
4
4
  K = 1
5
5
 
6
- Tupelo.application do |app|
6
+ Tupelo.application do
7
7
  (N+K).times do
8
- app.child do |client|
8
+ child do
9
9
  catch :gave_up do
10
10
  tries = 0
11
11
 
12
- r = client.take [Integer] do |val|
12
+ r = take [Integer] do |val|
13
13
  tries += 1
14
14
  if tries >= N
15
- client.log "giving up on #{val}"
15
+ log "giving up on #{val}"
16
16
  throw :gave_up
17
17
  end
18
- client.log "trying to take #{val}"
18
+ log "trying to take #{val}"
19
19
  end
20
20
 
21
- client.log "took #{r.inspect}"
21
+ log "took #{r.inspect}"
22
22
  end
23
23
  end
24
24
  end
25
25
 
26
26
  sleep 0.01
27
27
 
28
- app.child do |client|
28
+ child do
29
29
  N.times do |i|
30
- client.write [i]
31
- client.log "wrote #{[i]}"
30
+ write [i]
31
+ log "wrote #{[i]}"
32
32
  sleep 0.1
33
33
  end
34
34
  end
@@ -7,37 +7,37 @@ N_PLAYERS = 10
7
7
 
8
8
  token = ["token"] # only the holder of the token can arrange games
9
9
 
10
- Tupelo.application do |app|
11
- app.local do |client|
12
- client.write token
10
+ Tupelo.application do
11
+ local do
12
+ write token
13
13
  end
14
14
 
15
15
  N_PLAYERS.times do
16
- app.child do |client|
17
- me = client.client_id
16
+ child do
17
+ me = client_id
18
18
 
19
- client.take token # bottleneck and fragile until 'client.write token'
20
- other_player = client.read_nowait(name: nil)
19
+ take token # bottleneck and fragile until 'write token'
20
+ other_player = read_nowait(name: nil)
21
21
  # sleep 1 # program takes ~N_PLAYERS sec to finish
22
22
 
23
23
  if other_player
24
- client.take other_player
25
- client.write(
24
+ take other_player
25
+ write(
26
26
  player1: me,
27
27
  player2: other_player["name"])
28
- client.write token
28
+ write token
29
29
  you = other_player["name"]
30
30
 
31
31
  else
32
- client.write(name: me)
33
- client.write token
34
- game = client.read(
32
+ write(name: me)
33
+ write token
34
+ game = read(
35
35
  player1: nil,
36
36
  player2: me)
37
37
  you = game["player1"]
38
38
  end
39
39
 
40
- client.log "now playing with #{you}"
40
+ log "now playing with #{you}"
41
41
  end
42
42
  end
43
43
  end
@@ -9,15 +9,15 @@ require 'tupelo/app'
9
9
 
10
10
  N_PLAYERS = 10
11
11
 
12
- Tupelo.application do |app|
12
+ Tupelo.application do
13
13
  N_PLAYERS.times do
14
14
  # sleep rand / 10 # reduce contention -- could also randomize inserts
15
- app.child do |client|
16
- me = client.client_id
17
- client.write name: me
15
+ child do
16
+ me = client_id
17
+ write name: me
18
18
 
19
19
  begin
20
- t = client.transaction
20
+ t = transaction
21
21
  if t.take_nowait name: me
22
22
  you = t.take(name: nil)["name"]
23
23
  t.write(
@@ -28,14 +28,14 @@ Tupelo.application do |app|
28
28
  t.fail!
29
29
  end
30
30
  rescue Tupelo::Client::TransactionFailure => ex
31
- game = client.read_nowait(
31
+ game = read_nowait(
32
32
  player1: nil,
33
33
  player2: me)
34
34
  retry unless game
35
35
  you = game["player1"]
36
36
  end
37
37
 
38
- client.log "now playing with #{you}"
38
+ log "now playing with #{you}"
39
39
  end
40
40
  end
41
41
  end
data/example/cancel.rb CHANGED
@@ -1,17 +1,17 @@
1
1
  require 'tupelo/app'
2
2
 
3
- Tupelo.application do |app|
4
- app.child do |client|
3
+ Tupelo.application do
4
+ child do
5
5
  ats = (0..4).map do |i|
6
- client.transaction.async do |t|
7
- t.take ["start"]
8
- t.write [i]
6
+ transaction.async do
7
+ take ["start"]
8
+ write [i]
9
9
  end
10
10
  end
11
11
 
12
12
  [0,1,2,4].each {|i| ats[i].cancel}
13
13
 
14
- client.write ["start"]
15
- p client.take [Integer]
14
+ write ["start"]
15
+ p take [Integer]
16
16
  end
17
17
  end
@@ -2,37 +2,37 @@ require 'tupelo/app'
2
2
 
3
3
  N = 100
4
4
 
5
- Tupelo.application do |app|
6
- app.child do |client|
7
- client.write [0, 0]
5
+ Tupelo.application do
6
+ child do
7
+ write [0, 0]
8
8
 
9
9
  t1 = Thread.new do
10
10
  N.times do
11
- client.transaction do |t|
12
- t.take ["reader ready"]
13
- x, y = t.take [nil, nil]
14
- t.write [x+1, y]
15
- t.write ["data ready"]
11
+ transaction do
12
+ take ["reader ready"]
13
+ x, y = take [nil, nil]
14
+ write [x+1, y]
15
+ write ["data ready"]
16
16
  end
17
17
  end
18
18
  end
19
19
 
20
20
  t2 = Thread.new do
21
21
  N.times do
22
- client.transaction do |t|
23
- t.take ["reader ready"]
24
- x, y = t.take [nil, nil]
25
- t.write [x, y+1]
26
- t.write ["data ready"]
22
+ transaction do
23
+ take ["reader ready"]
24
+ x, y = take [nil, nil]
25
+ write [x, y+1]
26
+ write ["data ready"]
27
27
  end
28
28
  end
29
29
  end
30
30
 
31
31
  loop do
32
- client.write ["reader ready"]
33
- client.take ["data ready"]
34
- x, y = client.read [nil, nil]
35
- client.log "%3d %3d" % [x, y]
32
+ write ["reader ready"]
33
+ take ["data ready"]
34
+ x, y = read [nil, nil]
35
+ log "%3d %3d" % [x, y]
36
36
  break if x == N and y == N
37
37
  end
38
38
  end
@@ -10,20 +10,20 @@ end
10
10
  require 'tupelo/app'
11
11
 
12
12
  # Must use marshal or yaml -- msgpack and json do not support custom classes.
13
- Tupelo.application blob_type: 'marshal' do |app|
14
- app.child do |client|
13
+ Tupelo.application blob_type: 'marshal' do
14
+ child do
15
15
  f = Foo.new; f.x = 3
16
16
  p f
17
17
 
18
- client.write [f]
18
+ write [f]
19
19
 
20
- p client.read [nil]
21
- p client.read [Foo]
22
- p client.read [f]
20
+ p read [nil]
21
+ p read [Foo]
22
+ p read [f]
23
23
 
24
- p client.take [Foo]
24
+ p take [Foo]
25
25
 
26
- client.write [f]
27
- p client.take [f]
26
+ write [f]
27
+ p take [f]
28
28
  end
29
29
  end
@@ -14,14 +14,14 @@ class MyClient < Tupelo::Client
14
14
  end
15
15
  end
16
16
 
17
- Tupelo.application do |app|
18
- app.local MyClient do |client|
19
- client.write [41, 42, 43]
20
- client.write [42, 42, 42]
21
- client.write [42, 42]
22
- client.write_wait [42] # make sure all writes up to this one have completed
17
+ Tupelo.application do
18
+ local MyClient do
19
+ write [41, 42, 43]
20
+ write [42, 42, 42]
21
+ write [42, 42]
22
+ write_wait [42] # make sure all writes up to this one have completed
23
23
 
24
- client.log client.read_all [nil, nil, nil]
25
- client.log client.read_all_diagonal 42
24
+ log read_all
25
+ log read_all_diagonal 42
26
26
  end
27
27
  end