tupelo 0.1

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.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +22 -0
  3. data/README.md +422 -0
  4. data/Rakefile +77 -0
  5. data/bench/pipeline.rb +25 -0
  6. data/bugs/take-write.rb +19 -0
  7. data/bugs/write-read.rb +15 -0
  8. data/example/add.rb +19 -0
  9. data/example/app-and-tup.rb +30 -0
  10. data/example/async-transaction.rb +16 -0
  11. data/example/balance-xfer-locking.rb +50 -0
  12. data/example/balance-xfer-retry.rb +55 -0
  13. data/example/balance-xfer.rb +33 -0
  14. data/example/boolean-match.rb +32 -0
  15. data/example/bounded-retry.rb +35 -0
  16. data/example/broker-locking.rb +43 -0
  17. data/example/broker-optimistic-async.rb +33 -0
  18. data/example/broker-optimistic.rb +41 -0
  19. data/example/broker-queue.rb +2 -0
  20. data/example/cancel.rb +17 -0
  21. data/example/concurrent-transactions.rb +39 -0
  22. data/example/custom-class.rb +29 -0
  23. data/example/custom-search.rb +27 -0
  24. data/example/fail-and-retry.rb +29 -0
  25. data/example/hash-tuples.rb +53 -0
  26. data/example/increment.rb +21 -0
  27. data/example/lock-mgr-with-queue.rb +75 -0
  28. data/example/lock-mgr.rb +62 -0
  29. data/example/map-reduce-v2.rb +96 -0
  30. data/example/map-reduce.rb +77 -0
  31. data/example/matching.rb +9 -0
  32. data/example/notify.rb +35 -0
  33. data/example/optimist.rb +20 -0
  34. data/example/pulse.rb +24 -0
  35. data/example/read-in-trans.rb +56 -0
  36. data/example/small-simplified.rb +18 -0
  37. data/example/small.rb +76 -0
  38. data/example/tcp.rb +35 -0
  39. data/example/timeout-trans.rb +21 -0
  40. data/example/timeout.rb +27 -0
  41. data/example/tiny-client.rb +14 -0
  42. data/example/tiny-server.rb +12 -0
  43. data/example/transaction-logic.rb +40 -0
  44. data/example/write-wait.rb +17 -0
  45. data/lib/tupelo/app.rb +121 -0
  46. data/lib/tupelo/archiver/tuplespace.rb +68 -0
  47. data/lib/tupelo/archiver/worker.rb +87 -0
  48. data/lib/tupelo/archiver.rb +86 -0
  49. data/lib/tupelo/client/common.rb +10 -0
  50. data/lib/tupelo/client/reader.rb +124 -0
  51. data/lib/tupelo/client/transaction.rb +455 -0
  52. data/lib/tupelo/client/tuplespace.rb +50 -0
  53. data/lib/tupelo/client/worker.rb +493 -0
  54. data/lib/tupelo/client.rb +44 -0
  55. data/lib/tupelo/version.rb +3 -0
  56. data/test/lib/mock-client.rb +38 -0
  57. data/test/lib/mock-msg.rb +47 -0
  58. data/test/lib/mock-queue.rb +42 -0
  59. data/test/lib/mock-seq.rb +50 -0
  60. data/test/lib/testable-worker.rb +24 -0
  61. data/test/stress/concurrent-transactions.rb +42 -0
  62. data/test/system/test-archiver.rb +35 -0
  63. data/test/unit/test-mock-queue.rb +93 -0
  64. data/test/unit/test-mock-seq.rb +39 -0
  65. data/test/unit/test-ops.rb +222 -0
  66. metadata +134 -0
@@ -0,0 +1,24 @@
1
+ require 'tupelo/client/worker'
2
+ require 'tupelo/client/tuplespace'
3
+
4
+ class TestableWorker < Tupelo::Client::Worker
5
+ def initialize client
6
+ super
7
+
8
+ @cmd_queue = MockQueue.new
9
+
10
+ observe_started_client
11
+ update_to_tick 0
12
+ end
13
+
14
+ def in_thread?
15
+ true
16
+ end
17
+
18
+ def update
19
+ begin
20
+ handle_one_request unless cmd_queue.empty?
21
+ read_messages_from_seq # doesn't block; reads from seq to queue
22
+ end until cmd_queue.empty?
23
+ end
24
+ end
@@ -0,0 +1,42 @@
1
+ require 'tupelo/app'
2
+
3
+ N = 100
4
+
5
+ Tupelo.application do |app|
6
+ app.child do |client|
7
+ N.times do
8
+ client.transaction do |t|
9
+ x, y = t.take [nil, nil]
10
+ sleep rand/100
11
+ t.write [x+1, y]
12
+ end
13
+ end
14
+ client.write ["done"]
15
+ end
16
+
17
+ app.child do |client|
18
+ N.times do
19
+ client.transaction do |t|
20
+ x, y = t.take [nil, nil]
21
+ sleep rand/100
22
+ t.write [x, y+1]
23
+ end
24
+ end
25
+ client.write ["done"]
26
+ end
27
+
28
+ app.local do |client|
29
+ client.write [0, 0]
30
+
31
+ 2.times do
32
+ client.take ["done"]
33
+ end
34
+
35
+ x, y = client.read [nil, nil]
36
+ if x == N and y == N
37
+ puts "OK"
38
+ else
39
+ abort "FAIL: x=#{x}, y=#{y}"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,35 @@
1
+ require 'tupelo/app'
2
+
3
+ Tupelo.application do |app|
4
+ expected = [[1], [2], [3]]
5
+
6
+ app.local do |client|
7
+ client.write *expected
8
+ end
9
+
10
+ child_pid = app.child do |client|
11
+ # Test that tuples written before this client started are readable.
12
+ a = client.read_all [Integer]
13
+ client.write result: a
14
+ sleep 0.1
15
+ end
16
+
17
+ # Normally we would wait using tuples, but in this case we want more
18
+ # isolation in the test case, so we wait in terms of the PID.
19
+ Process.waitpid child_pid
20
+
21
+ app.local do |client|
22
+ h = client.read_all result: Array
23
+ begin
24
+ a = h.first["result"]
25
+ rescue => ex
26
+ abort "FAIL: #{ex}, h=#{h.inspect}"
27
+ end
28
+
29
+ if a == expected
30
+ puts "OK"
31
+ else
32
+ abort "FAIL: a=#{a.inspect}, expected=#{expected.inspect}"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,93 @@
1
+ require 'minitest/autorun'
2
+
3
+ require 'mock-queue.rb'
4
+
5
+ class TestMockQueueWithPushPopYields < Minitest::Test
6
+ def setup
7
+ @q = MockQueue.new yield_on_push: true, yield_on_pop: true
8
+ end
9
+
10
+ def test_push
11
+ f = Fiber.new do |val|
12
+ loop do
13
+ val = @q.push val
14
+ end
15
+ end
16
+
17
+ a = []
18
+ assert_equal a, @q.entries
19
+
20
+ 3.times do |i|
21
+ op, val = f.resume i
22
+ assert_equal :push, op
23
+ assert_equal i, val
24
+ a << i
25
+ assert_equal a, @q.entries
26
+ end
27
+ end
28
+
29
+ def test_pop
30
+ a = []
31
+ f = Fiber.new do
32
+ loop do
33
+ a << @q.pop
34
+ end
35
+ end
36
+
37
+ 3.times do
38
+ op = f.resume
39
+ assert_equal :block, op
40
+ assert_equal [], a
41
+ end
42
+
43
+ @q.entries.concat (0...10).to_a
44
+
45
+ 10.times do |i|
46
+ op, val = f.resume
47
+ assert_equal :pop, op
48
+ assert_equal i, val
49
+ end
50
+
51
+ op = f.resume
52
+ assert_equal :block, op
53
+ assert_equal a, (0...10).to_a
54
+ end
55
+ end
56
+
57
+ class TestMockQueueSimpler < Minitest::Test
58
+ def setup
59
+ @q = MockQueue.new
60
+ end
61
+
62
+ def test_push
63
+ a = []
64
+ assert_equal a, @q.entries
65
+
66
+ 3.times do |i|
67
+ @q.push i
68
+ a << i
69
+ assert_equal a, @q.entries
70
+ end
71
+ end
72
+
73
+ def test_pop
74
+ a = []
75
+ f = Fiber.new do
76
+ loop do
77
+ a << @q.pop
78
+ end
79
+ end
80
+
81
+ 3.times do
82
+ op = f.resume
83
+ assert_equal :block, op
84
+ assert_equal [], a
85
+ end
86
+
87
+ @q.entries.concat (0...10).to_a
88
+
89
+ op = f.resume
90
+ assert_equal :block, op
91
+ assert_equal a, (0...10).to_a
92
+ end
93
+ end
@@ -0,0 +1,39 @@
1
+ require 'minitest/autorun'
2
+
3
+ require 'mock-seq.rb'
4
+ require 'mock-msg.rb'
5
+
6
+ class TestMockSeq < Minitest::Test
7
+ def setup
8
+ @seq = MockSequencer.new
9
+ end
10
+
11
+ def test_multiple_streams
12
+ clients = (0..1).map {|i| @seq.stream}
13
+
14
+ count = 0
15
+ expected = []
16
+ clients.each_with_index do |c, i|
17
+ (0..2).each do |j|
18
+ c.write MockMessage[blob: [i,j]]
19
+ count += 1
20
+ expected << [count, i,j]
21
+ end
22
+ end
23
+
24
+ clients.each_with_index do |c, i|
25
+ assert_equal expected, c.map {|m| [m.global_tick, *m.blob]}
26
+ end
27
+ end
28
+
29
+ def test_alternations_of_reads_and_writes
30
+ client = @seq.stream
31
+ client.write MockMessage[blob: 1]
32
+ client.write MockMessage[blob: 2]
33
+ assert_equal [1,2], client.map(&:blob)
34
+
35
+ client.write MockMessage[blob: "a"]
36
+ client.write MockMessage[blob: "b"]
37
+ assert_equal ["a","b"], client.map(&:blob)
38
+ end
39
+ end
@@ -0,0 +1,222 @@
1
+ require 'minitest/autorun'
2
+ require 'logger'
3
+
4
+ require 'mock-seq.rb'
5
+ require 'mock-msg.rb'
6
+ require 'mock-client.rb'
7
+ require 'testable-worker.rb'
8
+
9
+ class TestOps < Minitest::Test
10
+ attr_reader :seq, :sio, :log
11
+
12
+ class MiniFormatter < Logger::Formatter # Based on EasyServe::EasyFormatter
13
+ Format = "%s: %s: %s\n"
14
+
15
+ def call(severity, time, progname, msg)
16
+ Format % [severity[0..0], progname, msg2str(msg)]
17
+ end
18
+ end
19
+
20
+ def setup
21
+ @seq = MockSequencer.new
22
+ end
23
+
24
+ def make_client cid
25
+ MockClient.new.tap do |c|
26
+ c.client_id = cid
27
+ c.log = Logger.new($stderr).tap do |log|
28
+ log.level = Logger::WARN
29
+ log.progname = cid
30
+ log.formatter = MiniFormatter.new
31
+ end
32
+ c.blobber = Marshal
33
+ c.tuplespace = Tupelo::Client::SimpleTuplespace
34
+ c.message_class = MockMessage
35
+ c.seq = seq.stream
36
+ c.worker = TestableWorker.new(c)
37
+ end
38
+ end
39
+
40
+ def make_clients n
41
+ n.times.map {|i| make_client i}
42
+ end
43
+
44
+ def test_one_client
45
+ client = make_client "one"
46
+
47
+ client.update; writer = client.write_nowait [1]
48
+ client.update; writer.wait
49
+ client.update; assert_equal 1, writer.global_tick
50
+
51
+ reader = Fiber.new do
52
+ client.read [nil]
53
+ end
54
+
55
+ client.update; reader.resume
56
+ client.update; assert_equal [1], reader.resume
57
+ end
58
+
59
+ def test_two_clients
60
+ t = ["c0"]
61
+ cl = make_clients(2)
62
+
63
+ cl[0].write t
64
+
65
+ cl.each do |c|
66
+ reader = Fiber.new { c.read [nil] }; reader.resume
67
+ c.update; assert_equal t, reader.resume
68
+ end
69
+ end
70
+
71
+ def test_read_existing
72
+ t = ["foo"]
73
+ cl = make_clients(2)
74
+
75
+ wr = cl[0].write t
76
+ cl[0].update; assert_equal 1, wr.global_tick
77
+
78
+ cl.each do |c|
79
+ reader = Fiber.new { c.read [nil] }; reader.resume
80
+ c.update; assert_equal t, reader.resume
81
+ end
82
+ end
83
+
84
+ def test_read_waiting
85
+ t = ["bar"]
86
+ cl = make_clients(2)
87
+
88
+ reader = Fiber.new { cl[1].read [nil] }; reader.resume
89
+
90
+ wr = cl[0].write t
91
+ cl[0].update; assert_equal 1, wr.global_tick
92
+ cl[1].update; assert_equal t, reader.resume
93
+
94
+ cl.each do |c|
95
+ reader = Fiber.new { c.read [nil] }; reader.resume
96
+ c.update; assert_equal t, reader.resume
97
+ end
98
+ end
99
+
100
+ def test_take_existing
101
+ t = ["foo"]
102
+ cl = make_clients(2)
103
+
104
+ wr = cl[0].write t
105
+ cl[0].update; assert_equal 1, wr.global_tick
106
+
107
+ taker = Fiber.new { cl[1].take [nil] }; taker.resume
108
+ cl[1].update; taker.resume
109
+ cl[1].update; assert_equal t, taker.resume
110
+ cl[0].update
111
+
112
+ cl.each do |c|
113
+ reader = Fiber.new { c.read_all [nil] }; reader.resume
114
+ c.update; assert_empty reader.resume
115
+ end
116
+ end
117
+
118
+ def test_take_waiting
119
+ t = ["bar"]
120
+ cl = make_clients(2)
121
+
122
+ taker = Fiber.new { cl[1].take [nil] }; taker.resume
123
+ cl[1].update; taker.resume
124
+ cl[1].update; assert_equal :block, taker.resume
125
+
126
+ wr = cl[0].write t
127
+ cl[0].update; assert_equal 1, wr.global_tick
128
+ cl[1].update; taker.resume
129
+ cl[1].update; assert_equal t, taker.resume
130
+ cl[0].update
131
+
132
+ cl.each do |c|
133
+ reader = Fiber.new { c.read_all [nil] }; reader.resume
134
+ c.update; assert_empty reader.resume
135
+ end
136
+ end
137
+
138
+ def test_transaction_existing
139
+ w = [1]; t = [2]
140
+ cl = make_clients(2)
141
+
142
+ wr = cl[0].write t
143
+ cl[0].update; assert_equal 1, wr.global_tick
144
+
145
+ trans = Fiber.new do
146
+ cl[1].transaction do |tr|
147
+ tr.write w
148
+ tr.take t
149
+ end
150
+ end
151
+ trans.resume
152
+
153
+ cl[1].update; trans.resume
154
+ cl[1].update; assert_equal t, trans.resume
155
+ cl[0].update
156
+
157
+ cl.each do |c|
158
+ reader = Fiber.new { c.read_all [nil] }; reader.resume
159
+ c.update; assert_equal [w], reader.resume
160
+ end
161
+ end
162
+
163
+ def test_transaction_waiting
164
+ w = [1]; t = [2]
165
+ cl = make_clients(2)
166
+
167
+ trans = Fiber.new do
168
+ cl[1].transaction do |tr|
169
+ tr.write w
170
+ tr.take t
171
+ end
172
+ end
173
+ trans.resume
174
+
175
+ wr = cl[0].write t
176
+ cl[0].update; assert_equal 1, wr.global_tick
177
+
178
+ cl[1].update; trans.resume
179
+ cl[1].update; assert_equal t, trans.resume
180
+ cl[0].update
181
+
182
+ cl.each do |c|
183
+ reader = Fiber.new { c.read_all [nil] }; reader.resume
184
+ c.update; assert_equal [w], reader.resume
185
+ end
186
+ end
187
+
188
+ def test_transaction_cancel
189
+ w = [1]; t = [2]
190
+ cl = make_clients(2)
191
+
192
+ tr = nil
193
+ trans = Fiber.new do
194
+ tr = cl[1].transaction
195
+ tr.write w
196
+ begin
197
+ tr.take t
198
+ tr.commit.wait
199
+ rescue Tupelo::Client::TransactionAbort
200
+ Fiber.yield :abort
201
+ end
202
+ end
203
+ cl[1].update; assert_equal :block, trans.resume
204
+
205
+ tr.cancel
206
+ cl[1].update; assert_equal :abort, trans.resume
207
+
208
+ wr = cl[0].write t
209
+ cl[0].update; assert_equal 1, wr.global_tick
210
+ cl[1].update
211
+
212
+ cl.each do |c|
213
+ reader = Fiber.new { c.read_all [nil] }; reader.resume
214
+ c.update; assert_equal [t], reader.resume
215
+ end
216
+ end
217
+
218
+ ## test Transaction#read
219
+ ## test failure
220
+ ## test pulse
221
+ ## test optimistic
222
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tupelo
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Joel VanderWerf
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: object-stream
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Distributed tuplespace.
28
+ email: vjoel@users.sourceforge.net
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files:
32
+ - README.md
33
+ - COPYING
34
+ files:
35
+ - README.md
36
+ - COPYING
37
+ - Rakefile
38
+ - lib/tupelo/client.rb
39
+ - lib/tupelo/app.rb
40
+ - lib/tupelo/archiver.rb
41
+ - lib/tupelo/client/worker.rb
42
+ - lib/tupelo/client/common.rb
43
+ - lib/tupelo/client/tuplespace.rb
44
+ - lib/tupelo/client/transaction.rb
45
+ - lib/tupelo/client/reader.rb
46
+ - lib/tupelo/archiver/worker.rb
47
+ - lib/tupelo/archiver/tuplespace.rb
48
+ - lib/tupelo/version.rb
49
+ - bench/pipeline.rb
50
+ - bugs/write-read.rb
51
+ - bugs/take-write.rb
52
+ - example/timeout-trans.rb
53
+ - example/tiny-client.rb
54
+ - example/add.rb
55
+ - example/app-and-tup.rb
56
+ - example/small.rb
57
+ - example/bounded-retry.rb
58
+ - example/map-reduce-v2.rb
59
+ - example/concurrent-transactions.rb
60
+ - example/cancel.rb
61
+ - example/tiny-server.rb
62
+ - example/write-wait.rb
63
+ - example/tcp.rb
64
+ - example/timeout.rb
65
+ - example/read-in-trans.rb
66
+ - example/balance-xfer-retry.rb
67
+ - example/lock-mgr-with-queue.rb
68
+ - example/hash-tuples.rb
69
+ - example/pulse.rb
70
+ - example/transaction-logic.rb
71
+ - example/map-reduce.rb
72
+ - example/balance-xfer.rb
73
+ - example/broker-optimistic-async.rb
74
+ - example/lock-mgr.rb
75
+ - example/broker-locking.rb
76
+ - example/fail-and-retry.rb
77
+ - example/optimist.rb
78
+ - example/balance-xfer-locking.rb
79
+ - example/increment.rb
80
+ - example/custom-class.rb
81
+ - example/matching.rb
82
+ - example/custom-search.rb
83
+ - example/broker-optimistic.rb
84
+ - example/notify.rb
85
+ - example/small-simplified.rb
86
+ - example/broker-queue.rb
87
+ - example/async-transaction.rb
88
+ - example/boolean-match.rb
89
+ - test/lib/testable-worker.rb
90
+ - test/lib/mock-seq.rb
91
+ - test/lib/mock-msg.rb
92
+ - test/lib/mock-queue.rb
93
+ - test/lib/mock-client.rb
94
+ - test/system/test-archiver.rb
95
+ - test/unit/test-ops.rb
96
+ - test/unit/test-mock-seq.rb
97
+ - test/unit/test-mock-queue.rb
98
+ - test/stress/concurrent-transactions.rb
99
+ homepage: https://github.com/vjoel/tupelo
100
+ licenses:
101
+ - BSD
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options:
105
+ - --quiet
106
+ - --line-numbers
107
+ - --inline-source
108
+ - --title
109
+ - tupelo
110
+ - --main
111
+ - README.md
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.0.4
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Distributed tuplespace
130
+ test_files:
131
+ - test/unit/test-ops.rb
132
+ - test/unit/test-mock-seq.rb
133
+ - test/unit/test-mock-queue.rb
134
+ has_rdoc: