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 +4 -4
- data/README.md +6 -1
- data/bin/tup +2 -0
- data/example/map-reduce/mr.rb +61 -0
- data/example/map-reduce/prime-factor-balanced.rb +55 -0
- data/example/map-reduce/remote-map-reduce.rb +7 -4
- data/lib/tupelo/app/builder.rb +26 -1
- data/lib/tupelo/app/remote.rb +8 -0
- data/lib/tupelo/app.rb +4 -1
- data/lib/tupelo/version.rb +1 -1
- metadata +92 -96
- data/example/broker-queue.rb +0 -35
- data/example/child-of-child.rb +0 -34
- data/example/fish01.rb +0 -48
- data/example/pregel/dist-opt.rb +0 -15
- data/example/subspaces/addr-book-v1.rb +0 -106
- data/example/subspaces/sorted-set-space-OLD.rb +0 -130
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e5af7d65abd86881773acbdf6957c756d6788bf4
|
4
|
+
data.tar.gz: f8d9c3bb4b8cb83a3d18714a508eeb374e457ba3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
#
|
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,
|
15
|
+
remote host: host, passive: true, eval: %{
|
13
16
|
loop do
|
14
17
|
len = take([String])[0].size
|
15
18
|
write [len]
|
data/lib/tupelo/app/builder.rb
CHANGED
@@ -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,
|
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
|
data/lib/tupelo/app/remote.rb
CHANGED
@@ -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,
|
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'
|
data/lib/tupelo/version.rb
CHANGED
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.
|
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-
|
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/
|
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/
|
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/
|
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/
|
158
|
-
- example/
|
159
|
-
- example/
|
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/
|
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/
|
173
|
-
- example/
|
174
|
-
- example/
|
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/
|
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/
|
183
|
-
- example/
|
184
|
-
- example/
|
185
|
-
- example/
|
186
|
-
- example/
|
187
|
-
- example/
|
188
|
-
- example/
|
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/
|
192
|
-
-
|
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/
|
204
|
-
- test/
|
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:
|
data/example/broker-queue.rb
DELETED
@@ -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
|
data/example/child-of-child.rb
DELETED
@@ -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
|
data/example/pregel/dist-opt.rb
DELETED
@@ -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
|