tupelo 0.15 → 0.16

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 79bc191b109fc7e11c3200a9e993725299558ead
4
- data.tar.gz: 736b92e95728520e46c0516e857a26a2fd74e766
3
+ metadata.gz: e5af7d65abd86881773acbdf6957c756d6788bf4
4
+ data.tar.gz: f8d9c3bb4b8cb83a3d18714a508eeb374e457ba3
5
5
  SHA512:
6
- metadata.gz: 33db9c43e57b0405190165d965a09099b842dcc7bab9767ee7ec9f3ac11536de37fd8cc56f97709daa1c4c40c69a4f9055634ef318c90211148856c38a38adb9
7
- data.tar.gz: a0b6f65625f735ec0b24bb06a02f07102661bf45b483a3b013ac7cafb4b3fceb27ac10711a7311638d2e305b2a522ea7eea1951739255ce0b31de10ee9bbe338
6
+ metadata.gz: e6af32369c79059957d4513ec90d711a0d0dd514488f126944b7da0dc888fadc07654a32f22387b6e095629f0149c72df4ce6f7ea4ccc24834d52d66e0159a5d
7
+ data.tar.gz: bac6727749123e5b64472b9b983c18fd90f301fa6bb0486b0b6888c4864b818fb1bc6089d4e5f2f7b46bce651927113bffbcff537fa642a4f5446a5965381e73
data/README.md CHANGED
@@ -181,7 +181,12 @@ Getting started
181
181
 
182
182
  (The 'sv' argument names a file that the first instance of tup uses to store information like socket addresses and the second instance uses to connect. The first instance starts the servers as child processes. However, both instances appear in the terminal as interactive shells.)
183
183
 
184
- To do this on two hosts, copy the sv file and, if necessary, edit its connect_host field.
184
+ To do this on two hosts, copy the sv file and, if necessary, edit its connect_host field. You can even do this:
185
+
186
+ host1$ tup sv tcp localhost
187
+
188
+ host2$ tup host1:path/to/sv --tunnel
189
+
185
190
 
186
191
  5. Look at the examples. You may need to dig a bit to find the gem installation. For example:
187
192
 
data/bin/tup CHANGED
@@ -48,6 +48,8 @@ if ARGV.delete("-h") or ARGV.delete("--help")
48
48
  -v verbose mode (include time and pid in log messages)
49
49
 
50
50
  --trace enable trace output
51
+
52
+ --tunnel remote clients use ssh tunnels by default (OpenSSH >= 6.0)
51
53
 
52
54
  --pubsub publish/subscribe mode; does not keep local tuple store:
53
55
 
@@ -0,0 +1,61 @@
1
+ # see also ../parallel.rb and ../remote.rb
2
+
3
+ #require 'tupelo/app'
4
+ #require 'tupelo/app/remote'
5
+ require 'easy-serve/remote'
6
+
7
+ tunnel = !!ARGV.delete("--tunnel")
8
+ host = ARGV.shift
9
+
10
+ #Tupelo.tcp_application do
11
+ ## This is fine:
12
+ ## ez.remote host: host, tunnel: tunnel, eval: %{
13
+ ## }
14
+ #
15
+ ## These break:
16
+ #
17
+ # ez.remote :seqd, :cseqd, host: host, tunnel: tunnel, log: true, eval: %{
18
+ # require 'funl/client'
19
+ #
20
+ # log.progname = "client <starting>"
21
+ #
22
+ # seqd, cseqd = conns
23
+ # client = Funl::Client.new(seq: seqd, cseq: cseqd, log: log)
24
+ # client.cseq_read_client_id
25
+ # }
26
+ #
27
+ ## remote host: host, tunnel: tunnel, eval: %{
28
+ ## }
29
+ #end
30
+
31
+ EasyServe.start do |ez|
32
+ log = ez.log
33
+ log.level = Logger::INFO
34
+ log.progname = File.basename($0)
35
+
36
+ ez.start_servers do
37
+ svhost = tunnel ? "localhost" : nil # no need to expose port if tunnelled
38
+
39
+ ez.server :seqd, :tcp, svhost, 0 do |svr|
40
+ require 'funl/message-sequencer'
41
+ seq = Funl::MessageSequencer.new svr, log: log
42
+ seq.start
43
+ end
44
+
45
+ ez.server :cseqd, :tcp, svhost, 0 do |svr|
46
+ require 'funl/client-sequencer'
47
+ cseq = Funl::ClientSequencer.new svr, log: log
48
+ cseq.start
49
+ end
50
+ end
51
+
52
+ ez.remote :seqd, :cseqd, host: host, tunnel: tunnel, log: true, eval: %{
53
+ require 'funl/client'
54
+
55
+ log.progname = "client <starting>"
56
+
57
+ seqd, cseqd = conns
58
+ client = Funl::Client.new(seq: seqd, cseq: cseqd, log: log)
59
+ client.cseq_read_client_id
60
+ }
61
+ end
@@ -0,0 +1,55 @@
1
+ # Factor numbers using remote hosts. Run with --trace to see contention.
2
+ # This is more "map" than "map-reduce", though you could aggregate the
3
+ # factored numbers, such as by finding the largest prime factor.
4
+
5
+ require 'tupelo/app/remote'
6
+
7
+ hosts = ARGV.shift or abort "usage: #$0 <ssh-hostname>,<ssh-hostname>,..."
8
+ hosts = hosts.split(",")
9
+
10
+ Tupelo.tcp_application do
11
+ hosts.each_with_index do |host, hi|
12
+ remote host: host, passive: true, eval: %{
13
+ require 'prime' # ruby stdlib for prime factorization
14
+ class M
15
+ def initialize nh, hi
16
+ @nh, @hi = nh, hi
17
+ end
18
+ def === x
19
+ Array === x and
20
+ x[0] == "input" and
21
+ x[1] % @nh == @hi
22
+ end
23
+ end
24
+ my_pref = M.new(#{hosts.size}, #{hi})
25
+ loop do
26
+ _, input =
27
+ begin
28
+ take(my_pref, timeout: 1.0) # fewer fails (5.0 -> none at all)
29
+ rescue TimeoutError
30
+ take(["input", Integer])
31
+ end
32
+ write ["output", input, input.prime_division]
33
+ end
34
+ }
35
+ end
36
+
37
+ local do
38
+ t0 = Time.now
39
+ inputs = 1_000_000_000_000 .. 1_000_000_000_050
40
+
41
+ inputs.each do |input|
42
+ write ["input", input]
43
+ end
44
+
45
+ inputs.size.times do
46
+ _, input, outputs = take ["output", Integer, nil]
47
+ output_str = outputs.map {|prime, exp|
48
+ exp == 1 ? prime : "#{prime}**#{exp}"}.join(" * ")
49
+ log "#{input} == #{output_str}"
50
+ end
51
+
52
+ t1 = Time.now
53
+ log "elapsed: %6.2f seconds" % (t1-t0)
54
+ end
55
+ end
@@ -1,15 +1,18 @@
1
- # see also ../parallel.rb and ../remote.rb
1
+ # See also ../parallel.rb and ../remote.rb.
2
+ #
3
+ # To run this example over an ssh tunnel, either pass "--tunnel" on the command
4
+ # line (the switch is parsed by the app framework) or explicitly pass the
5
+ # `tunnel: true` argument to the #remote call below. The --tunnel switch works
6
+ # for all examples and other programs based on 'tupelo/app'.
2
7
 
3
8
  require 'tupelo/app/remote'
4
9
 
5
- tunnel = !!ARGV.delete("--tunnel")
6
-
7
10
  hosts = ARGV.shift or abort "usage: #$0 <ssh-hostname>,<ssh-hostname>,..."
8
11
  hosts = hosts.split(",")
9
12
 
10
13
  Tupelo.tcp_application do
11
14
  hosts.each do |host|
12
- remote host: host, passive: true, tunnel: tunnel, eval: %{
15
+ remote host: host, passive: true, eval: %{
13
16
  loop do
14
17
  len = take([String])[0].size
15
18
  write [len]
@@ -7,14 +7,39 @@ module Tupelo
7
7
  # Does this app own (as child processes) the seq, cseq, and arc services?
8
8
  attr_reader :owns_services
9
9
 
10
+ # Do remote clients default to using ssh tunnels for data? This has
11
+ # slightly different meanings in two cases:
12
+ #
13
+ # 1. When the client is started by the #remote method, as in many simpler
14
+ # examples, the #tunnel_default is the default for the tunnel keyword
15
+ # argument of the #remote method. (Uses ssh -R.)
16
+ #
17
+ # 2. When the client is started as an unrelated process (for example,
18
+ # connecting to a pre-existing tupelo cluster running on a different
19
+ # host), there is no #remote call, and tunneling is automatically set up.
20
+ # (Uses ssh -L.)
21
+ #
22
+ # In both cases, the --tunnel command line switch sets tunnel_default to
23
+ # true.
24
+ #
25
+ attr_reader :tunnel_default
26
+
10
27
  # Arguments available to application after tupelo has parsed out switches
11
28
  # and args that it recognizes.
12
29
  attr_reader :argv
13
30
 
14
- def initialize ez, owns_services: nil, argv: argv
31
+ def initialize ez, argv: argv, owns_services: nil, tunnel_default: false
15
32
  @ez = ez
16
33
  @owns_services = owns_services
34
+ @tunnel_default = tunnel_default
17
35
  @argv = argv
36
+
37
+ # When connecting to remote, non-sibling (not started by the same ancestor
38
+ # process) services, use a tunnel if requested to (see note under
39
+ # #tunnel_default).
40
+ if not owns_services and tunnel_default and not ez.sibling
41
+ ez.tunnel_to_remote_services
42
+ end
18
43
  end
19
44
 
20
45
  def log
@@ -20,12 +20,20 @@ module Tupelo
20
20
  #
21
21
  # Unlike #child, there is no mode that returns a Client instance.
22
22
  #
23
+ # Note that EasyServe options apply, including the `tunnel: true` option.
24
+ # The default for this option is true if the `--tunnel` switch is present
25
+ # on the command line.
26
+ #
23
27
  def remote client_class = Client,
24
28
  client_lib: 'tupelo/client', host: nil, **opts
25
29
  require 'easy-serve/remote'
26
30
  ## detach option so that remote process doesn't keep ssh connection
27
31
  snames = :seqd, :cseqd, :arcd
28
32
 
33
+ if tunnel_default and not opts.key?(:tunnel)
34
+ opts[:tunnel] = true
35
+ end
36
+
29
37
  if opts[:eval]
30
38
  ez.remote *snames, host: host, **opts, eval: %{
31
39
  require #{client_lib.inspect}
data/lib/tupelo/app.rb CHANGED
@@ -33,6 +33,7 @@ module Tupelo
33
33
  end
34
34
 
35
35
  opts[:trace] = argv.delete("--trace")
36
+ opts[:tunnel] = argv.delete("--tunnel")
36
37
 
37
38
  [argv, opts]
38
39
  end
@@ -63,6 +64,7 @@ module Tupelo
63
64
  verbose = opts[:verbose]
64
65
  blob_type = blob_type || "msgpack"
65
66
  enable_trace = opts[:trace]
67
+ tunnel_default = !!opts[:tunnel]
66
68
  persist_dir = opts[:persist_dir]
67
69
 
68
70
  ez_opts = {
@@ -113,7 +115,8 @@ module Tupelo
113
115
  end
114
116
  end
115
117
 
116
- app = AppBuilder.new(ez, owns_services: owns_services, argv: argv.dup)
118
+ app = AppBuilder.new(ez, argv: argv.dup,
119
+ owns_services: owns_services, tunnel_default: tunnel_default)
117
120
 
118
121
  if enable_trace
119
122
  require 'tupelo/app/trace'
@@ -1,3 +1,3 @@
1
1
  module Tupelo
2
- VERSION = "0.15"
2
+ VERSION = "0.16"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tupelo
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.15'
4
+ version: '0.16'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel VanderWerf
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-18 00:00:00.000000000 Z
11
+ date: 2013-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: atdo
@@ -84,124 +84,120 @@ files:
84
84
  - lib/tupelo/app/trace.rb
85
85
  - lib/tupelo/app/builder.rb
86
86
  - lib/tupelo/client.rb
87
- - lib/tupelo/app.rb
88
- - lib/tupelo/archiver.rb
89
- - lib/tupelo/client/worker.rb
90
- - lib/tupelo/client/common.rb
91
- - lib/tupelo/client/tuplespace.rb
92
- - lib/tupelo/client/transaction.rb
93
- - lib/tupelo/client/atdo.rb
94
- - lib/tupelo/client/reader.rb
87
+ - lib/tupelo/tuplets/persistent-archiver.rb
95
88
  - lib/tupelo/tuplets/persistent-archiver/worker.rb
96
89
  - lib/tupelo/tuplets/persistent-archiver/tuplespace.rb
97
- - lib/tupelo/tuplets/persistent-archiver.rb
90
+ - lib/tupelo/util/boolean.rb
91
+ - lib/tupelo/app.rb
92
+ - lib/tupelo/archiver.rb
98
93
  - lib/tupelo/archiver/persister.rb
99
94
  - lib/tupelo/archiver/worker.rb
100
95
  - lib/tupelo/archiver/tuplespace.rb
101
96
  - lib/tupelo/archiver/persistent-tuplespace.rb
102
- - lib/tupelo/util/boolean.rb
97
+ - lib/tupelo/client/transaction.rb
98
+ - lib/tupelo/client/worker.rb
99
+ - lib/tupelo/client/reader.rb
100
+ - lib/tupelo/client/tuplespace.rb
101
+ - lib/tupelo/client/atdo.rb
102
+ - lib/tupelo/client/common.rb
103
103
  - lib/tupelo/version.rb
104
104
  - bench/pipeline.rb
105
105
  - bugs/read-take.rb
106
106
  - bugs/take-write.rb
107
- - example/pubsub.rb
108
- - example/timeout-trans.rb
109
- - example/fish01.rb
110
- - example/tiny-client.rb
111
- - example/add.rb
112
- - example/parallel.rb
113
- - example/socket-broker.rb
114
- - example/multi-tier/memo2.rb
115
- - example/multi-tier/drb.rb
116
- - example/multi-tier/memo.rb
117
- - example/multi-tier/kvspace.rb
118
- - example/multi-tier/http.rb
119
- - example/multi-tier/multi-sinatras.rb
120
- - example/app-and-tup.rb
121
- - example/small.rb
122
- - example/bounded-retry.rb
123
- - example/fish.rb
124
- - example/zk/lock.rb
125
- - example/concurrent-transactions.rb
126
- - example/cancel.rb
127
- - example/map-reduce/map-reduce-v2.rb
128
- - example/map-reduce/remote-map-reduce.rb
129
- - example/map-reduce/map-reduce.rb
130
- - example/map-reduce/prime-factor.rb
131
- - example/write-wait.rb
132
- - example/tcp.rb
133
107
  - example/timeout.rb
134
- - example/read-in-trans.rb
135
- - example/subspaces/simple.rb
136
- - example/subspaces/pubsub.rb
137
- - example/subspaces/addr-book-v1.rb
138
- - example/subspaces/addr-book.rb
139
- - example/subspaces/ramp.rb
140
- - example/subspaces/addr-book-v2.rb
141
- - example/subspaces/sorted-set-space-OLD.rb
142
- - example/subspaces/shop/shop-v2.rb
143
- - example/subspaces/shop/shop-v1.rb
144
- - example/subspaces/sorted-set-space.rb
145
- - example/balance-xfer-retry.rb
146
- - example/take-nowait-caution.rb
147
- - example/lock-mgr-with-queue.rb
148
- - example/hash-tuples.rb
149
- - example/pulse.rb
150
- - example/transaction-logic.rb
151
- - example/lease.rb
152
- - example/chat/chat.rb
153
- - example/chat/chat-nohistory.rb
154
- - example/balance-xfer.rb
155
- - example/uniq-id.rb
156
108
  - example/add-dsl.rb
157
- - example/lock-mgr.rb
158
- - example/broker-locking.rb
159
- - example/dphil-optimistic.rb
109
+ - example/remote.rb
110
+ - example/increment.rb
111
+ - example/matching.rb
112
+ - example/dphil.rb
113
+ - example/broker-optimistic.rb
160
114
  - example/fail-and-retry.rb
161
- - example/fish0.rb
115
+ - example/load-balancer.rb
116
+ - example/read-in-trans.rb
117
+ - example/bounded-retry.rb
118
+ - example/pregel/remote.rb
119
+ - example/pregel/pagerank.rb
162
120
  - example/pregel/pregel.rb
163
121
  - example/pregel/distributed.rb
164
- - example/pregel/pagerank.rb
165
122
  - example/pregel/update.rb
166
- - example/pregel/remote.rb
167
- - example/pregel/dist-opt.rb
168
- - example/dphil-optimistic-v2.rb
169
- - example/broker-optimistic-v2.rb
170
- - example/remote.rb
171
123
  - example/take-nowait.rb
172
- - example/wait-interrupt.rb
173
- - example/tiny-service.rb
174
- - example/optimist.rb
124
+ - example/boolean-match.rb
125
+ - example/lease.rb
126
+ - example/broker-locking.rb
127
+ - example/transaction-logic.rb
175
128
  - example/message-bus.rb
129
+ - example/small-simplified.rb
130
+ - example/small.rb
131
+ - example/lock-mgr.rb
132
+ - example/take-nowait-caution.rb
133
+ - example/concurrent-transactions.rb
134
+ - example/tcp.rb
135
+ - example/notify.rb
136
+ - example/pulse.rb
137
+ - example/chat/chat.rb
138
+ - example/chat/chat-nohistory.rb
139
+ - example/hash-tuples.rb
176
140
  - example/balance-xfer-locking.rb
177
- - example/increment.rb
178
- - example/child-of-child.rb
179
- - example/custom-class.rb
180
- - example/matching.rb
141
+ - example/balance-xfer-retry.rb
181
142
  - example/custom-search.rb
182
- - example/broker-optimistic.rb
183
- - example/notify.rb
184
- - example/small-simplified.rb
185
- - example/broker-queue.rb
186
- - example/async-transaction.rb
187
- - example/boolean-match.rb
188
- - example/load-balancer.rb
143
+ - example/app-and-tup.rb
144
+ - example/multi-tier/memo2.rb
145
+ - example/multi-tier/http.rb
146
+ - example/multi-tier/multi-sinatras.rb
147
+ - example/multi-tier/kvspace.rb
148
+ - example/multi-tier/memo.rb
149
+ - example/multi-tier/drb.rb
189
150
  - example/take-many.rb
151
+ - example/subspaces/ramp.rb
152
+ - example/subspaces/sorted-set-space.rb
153
+ - example/subspaces/addr-book.rb
154
+ - example/subspaces/simple.rb
155
+ - example/subspaces/shop/shop-v2.rb
156
+ - example/subspaces/shop/shop-v1.rb
157
+ - example/subspaces/pubsub.rb
158
+ - example/subspaces/addr-book-v2.rb
159
+ - example/dphil-optimistic.rb
160
+ - example/async-transaction.rb
161
+ - example/wait-interrupt.rb
162
+ - example/fish0.rb
163
+ - example/zk/lock.rb
190
164
  - example/deadlock.rb
191
- - example/dphil.rb
192
- - test/lib/testable-worker.rb
165
+ - example/fish.rb
166
+ - example/add.rb
167
+ - example/dphil-optimistic-v2.rb
168
+ - example/tiny-service.rb
169
+ - example/parallel.rb
170
+ - example/tiny-client.rb
171
+ - example/map-reduce/map-reduce.rb
172
+ - example/map-reduce/remote-map-reduce.rb
173
+ - example/map-reduce/map-reduce-v2.rb
174
+ - example/map-reduce/prime-factor.rb
175
+ - example/map-reduce/mr.rb
176
+ - example/map-reduce/prime-factor-balanced.rb
177
+ - example/lock-mgr-with-queue.rb
178
+ - example/balance-xfer.rb
179
+ - example/cancel.rb
180
+ - example/socket-broker.rb
181
+ - example/timeout-trans.rb
182
+ - example/uniq-id.rb
183
+ - example/optimist.rb
184
+ - example/pubsub.rb
185
+ - example/broker-optimistic-v2.rb
186
+ - example/write-wait.rb
187
+ - example/custom-class.rb
188
+ - test/stress/archiver-load.rb
189
+ - test/stress/concurrent-transactions.rb
190
+ - test/system/test-archiver.rb
191
+ - test/lib/mock-client.rb
192
+ - test/lib/time-fuzz.rb
193
+ - test/lib/mock-queue.rb
193
194
  - test/lib/mock-seq.rb
195
+ - test/lib/testable-worker.rb
194
196
  - test/lib/mock-msg.rb
195
- - test/lib/mock-queue.rb
196
- - test/lib/time-fuzz.rb
197
- - test/lib/mock-client.rb
198
- - test/system/test-archiver.rb
199
- - test/unit/test-ops.rb
200
- - test/unit/test-mock-client.rb
201
197
  - test/unit/test-mock-seq.rb
202
198
  - test/unit/test-mock-queue.rb
203
- - test/stress/concurrent-transactions.rb
204
- - test/stress/archiver-load.rb
199
+ - test/unit/test-ops.rb
200
+ - test/unit/test-mock-client.rb
205
201
  - bin/tup
206
202
  - bin/tspy
207
203
  homepage: https://github.com/vjoel/tupelo
@@ -236,8 +232,8 @@ signing_key:
236
232
  specification_version: 4
237
233
  summary: Distributed tuplespace
238
234
  test_files:
239
- - test/unit/test-ops.rb
240
- - test/unit/test-mock-client.rb
241
235
  - test/unit/test-mock-seq.rb
242
236
  - test/unit/test-mock-queue.rb
237
+ - test/unit/test-ops.rb
238
+ - test/unit/test-mock-client.rb
243
239
  has_rdoc:
@@ -1,35 +0,0 @@
1
- # more like how you would do it in redis, except that the queue is not stored in
2
- # the central server, so operations on it are not a bottleneck, FWIW
3
-
4
- require 'tupelo/app'
5
-
6
- N_PLAYERS = 10
7
-
8
- Tupelo.application do
9
- N_PLAYERS.times do
10
- # sleep rand / 10 # reduce contention -- could also randomize inserts
11
- child do
12
- me = client_id
13
- write name: me
14
-
15
- you = transaction do
16
- game = read_nowait(
17
- player1: nil,
18
- player2: me)
19
- break game["player1"] if game
20
-
21
- unless take_nowait name: me
22
- raise Tupelo::Client::TransactionFailure
23
- end
24
-
25
- you = take(name: nil)["name"]
26
- write(
27
- player1: me,
28
- player2: you)
29
- you
30
- end
31
-
32
- log "now playing with #{you}"
33
- end
34
- end
35
- end
@@ -1,34 +0,0 @@
1
- require 'tupelo/app'
2
-
3
- ### need a programmatic way to start up clients
4
-
5
- Tupelo.application do |app|
6
-
7
- app.child do ## local still hangs
8
- 3.times do |i|
9
- app.child do
10
- write [i]
11
- log "wrote #{i}"
12
- end
13
- end
14
-
15
- 3.times do
16
- log take [nil]
17
- end
18
- end
19
- end
20
-
21
- __END__
22
-
23
- this hangs sometimes but not always:
24
-
25
- tick cid status operation
26
- A: client 3: wrote 0
27
- A: client 4: wrote 1
28
- 1 3 batch write [0]
29
- 2 4 batch write [1]
30
- A: client 2: [0]
31
- 3 2 atomic take [0]
32
- 4 2 atomic take [1]
33
- A: client 2: [1]
34
- A: client 5: wrote 2
data/example/fish01.rb DELETED
@@ -1,48 +0,0 @@
1
- # This works, but requires a fix-up step.
2
-
3
- require 'tupelo/app'
4
-
5
- Tupelo.application do
6
- 2.times do
7
- child passive: true do
8
- loop do
9
- fish = nil
10
-
11
- transaction do
12
- fish, _ = take([String])
13
- n, _ = take_nowait([Integer, fish])
14
- if n
15
- write [n + 1, fish]
16
- else
17
- write [1, fish] # another process might also write this, so ...
18
- end
19
- end
20
- ### what if both processes die here?
21
- transaction do # ... fix up the two tuples.
22
- n1, _ = take_nowait [Integer, fish]; abort unless n1
23
- n2, _ = take_nowait [Integer, fish]; abort unless n2
24
- #log "fixing: #{[n1 + n2, fish]}"
25
- write [n1 + n2, fish]
26
- end
27
- end
28
- end
29
- end
30
-
31
- local do
32
- seed = 3
33
- srand seed
34
- log "seed = #{seed}"
35
-
36
- fishes = %w{ trout marlin char salmon }
37
-
38
- a = fishes * 10
39
- a.shuffle!
40
- a.each do |fish|
41
- write [fish]
42
- end
43
-
44
- fishes.each do |fish|
45
- log take [10, fish]
46
- end
47
- end
48
- end
@@ -1,15 +0,0 @@
1
- #
2
- # Minor optimization:
3
-
4
- class KeyMatcher
5
- def initialize i, n
6
- @i = i
7
- @n = n
8
- end
9
-
10
- def === id
11
- id % @n == @i
12
- end
13
- end
14
-
15
- vertex = take id: v_id_matcher, step: step, rank: nil, active: true
@@ -1,106 +0,0 @@
1
- ## TODO
2
- ##
3
- ## scaling params
4
-
5
- require 'tupelo/app'
6
-
7
- ab_tag = "my address book"
8
- ab_sort_field = 1
9
- ab_val_field = 2
10
- cmd_tag = "#{ab_tag} commands"
11
- resp_tag = "#{ab_tag} responses"
12
-
13
- Tupelo.application do
14
- local do
15
- use_subspaces!
16
-
17
- # Subspace for tuples belonging to the addr book.
18
- define_subspace(
19
- tag: ab_tag,
20
- template: [
21
- {value: ab_tag},
22
- {type: "string"}, # name <-- ab_sort_field references this field
23
- nil # address; can be any object <-- ab_val_field
24
- ]
25
- )
26
-
27
- # Subspace for commands for fetch and delete.
28
- # We can't use #read and #take because then the requesting client
29
- # would have to subscribe to the ab_tag subspace.
30
- define_subspace(
31
- tag: cmd_tag,
32
- template: [
33
- {value: cmd_tag},
34
- {type: "string"}, # cmd name
35
- {type: "list"} # arguments
36
- ]
37
- )
38
-
39
- # Subspace for responses to commands. Identify the command this is in
40
- # response to by copying it (alternately, could use ids).
41
- define_subspace(
42
- tag: resp_tag,
43
- template: [
44
- {value: resp_tag},
45
- {type: "string"}, # cmd name
46
- {type: "list"}, # arguments
47
- nil # result of query -- type depends on command
48
- ]
49
- )
50
- end
51
-
52
- ## Could set N_SORTED_SET_SPACE > 1, but lookups are so fast it would
53
- ## just lead to contention and redundant computation. Redundancy is useful
54
- ## though.
55
-
56
- # Inserts are just writes, which are handled by Worker and SortedSetSpace,
57
- # so this child's app loop only needs to handle special commands: fetch and
58
- # delete, which are delegated to the SortedSetSpace.
59
- child tuplespace: [SortedSetSpace, ab_tag, ab_sort_field, ab_val_field],
60
- subscribe: [ab_tag, cmd_tag], passive: true do
61
- loop do
62
- transaction do
63
- _, cmd, args = take(subspace cmd_tag)
64
-
65
- case cmd
66
- when "delete"
67
- args.each do |name|
68
- take [ab_tag, name, nil]
69
- end
70
-
71
- when "fetch"
72
- name = args[0]
73
- _, _, addr = read [ab_tag, name, nil]
74
- write [resp_tag, name, args, addr]
75
-
76
- when "next", "prev"
77
- name = args[0]
78
- _, name2, addr = read SortedSetTemplate[ab_tag, cmd, name]
79
- write [resp_tag, name, args, name2, addr]
80
-
81
- when "first", "last"
82
- _, name, addr = read SortedSetTemplate[ab_tag, cmd]
83
- write [resp_tag, name, args, name, addr]
84
-
85
- else # maybe write an error message in a tuple
86
- log.error "bad command: #{cmd}"
87
- end
88
- end
89
- end
90
- end
91
-
92
- child subscribe: resp_tag do
93
- # write some ab entries
94
- write [ab_tag, "McFirst, Firsty", "123 W. Crescent Terrace"]
95
- write [ab_tag, "Secondismus, Deuce", "456 S. West Way"]
96
-
97
- # make some queries
98
- write [cmd_tag, "first", []]
99
- *, name, addr = take [resp_tag, "first", [], nil, nil]
100
- log "first entry: #{name} => #{addr}"
101
-
102
- write [cmd_tag, "next", [name]]
103
- *, name, addr = take [resp_tag, "next", [name], nil, nil]
104
- log "next entry: #{name} => #{addr}"
105
- end
106
- end
@@ -1,130 +0,0 @@
1
- require 'rbtree'
2
-
3
- class SortedSetTemplate
4
- class << self
5
- alias [] new
6
- end
7
-
8
- # cmd can be "next", "prev", "first", "last"
9
- # for next/prev, args is ["name"]
10
- # for first/last, args is empty
11
- def initialize tag, cmd, *args
12
- @tag = tag
13
- @cmd = cmd
14
- @args = args
15
- end
16
-
17
- def === other
18
- raise ### should not need this?
19
- end
20
-
21
- def find_in rbtree
22
- case @cmd
23
- when "first"
24
- rbtree.first
25
- ###
26
- end
27
- end
28
-
29
- # A tuple store (in-memory) that is optimized for (key_string, object) pairs.
30
- # The object may be any serializable object (built up from numbers, booleans,
31
- # nil, strings, hashes and arrays).
32
- #
33
- # Unlike in a key-value store, a given key_string may occur more than once.
34
- # It is up to the application to decide whether to enforce key uniqueness or
35
- # not (for example, by taking (k,...) before writing (k,v).
36
- #
37
- # This store should be used only by clients that subscribe to a subspace
38
- # that can be represented as pairs. (See memo2.rb.)
39
- #
40
- # This store also manages meta tuples, which it keeps in an array, just like
41
- # the default Tuplespace class does.
42
- class SortedSetSpace
43
- include Enumerable
44
-
45
- attr_reader :tag, :hash, :metas
46
-
47
- def initialize tag
48
- @tag = tag
49
- clear
50
- end
51
-
52
- def clear
53
- @hash = Hash.new {|h,k| h[k] = []}
54
- # It's up to the application to enforce that these arrays have size <=1.
55
- @metas = []
56
- # We are automatically subscribed to tupelo metadata (subspace defs), so
57
- # we need to keep them somewhere.
58
- end
59
-
60
- def each
61
- hash.each do |k, vs|
62
- vs.each do |v|
63
- yield tag, k, v
64
- end
65
- end
66
- metas.each do |tuple|
67
- yield tuple
68
- end
69
- end
70
-
71
- def insert tuple
72
- if tuple.kind_of? Array
73
- # and tuple.size == 3 and tuple[0] == tag and tuple[1].kind_of? String
74
- # This is redundant, because of subscribe.
75
- t, k, v = tuple
76
- hash[k] << v
77
-
78
- else
79
- metas << tuple
80
- end
81
- end
82
-
83
- def delete_once tuple
84
- if tuple.kind_of? Array
85
- # and tuple.size == 3 and tuple[0] == tag and tuple[1].kind_of? String
86
- # This is redundant, because of subscribe.
87
- t, k, v = tuple
88
- if hash.key?(k) and hash[k].include? v
89
- hash[k].delete v
90
- hash.delete k if hash[k].empty?
91
- true
92
- else
93
- false
94
- end
95
-
96
- else
97
- if i=metas.index(tuple)
98
- delete_at i
99
- end
100
- end
101
- end
102
-
103
- def transaction inserts: [], deletes: [], tick: nil
104
- deletes.each do |tuple|
105
- delete_once tuple or raise "bug"
106
- end
107
-
108
- inserts.each do |tuple|
109
- insert tuple.freeze ## should be deep_freeze
110
- end
111
- end
112
-
113
- def find_distinct_matches_for templates
114
- templates.inject([]) do |tuples, template|
115
- tuples << find_match_for(template, distinct_from: tuples)
116
- end
117
- end
118
-
119
- def find_match_for template, distinct_from: []
120
- case template
121
- when SortedSetTemplate
122
- template.find_in rbtree, distinct_from: distinct_from ###
123
- else
124
- # fall back to linear search
125
- find do |tuple|
126
- template === tuple and not distinct_from.any? {|t| t.equal? tuple}
127
- end
128
- end
129
- end
130
- end