tupelo 0.12 → 0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -1
- data/example/broker-queue.rb +35 -0
- data/example/chat/chat-nohistory.rb +33 -0
- data/example/chat/chat.rb +4 -9
- data/example/child-of-child.rb +34 -0
- data/example/fish01.rb +48 -0
- data/example/pregel/dist-opt.rb +15 -0
- data/example/subspaces/addr-book-v1.rb +106 -0
- data/example/subspaces/addr-book-v2.rb +18 -0
- data/example/subspaces/sorted-set-space.rb +130 -0
- data/lib/tupelo/client/reader.rb +13 -6
- data/lib/tupelo/client/worker.rb +6 -4
- data/lib/tupelo/version.rb +1 -1
- data/test/unit/test-ops.rb +24 -0
- metadata +91 -83
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a657d2c56962432faa339d693f6856f409249f6
|
4
|
+
data.tar.gz: 64a58b3ab627151aeb2fc8965de21a39c1ebf3f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ea7042705c178a855d4d9ad621c2b65433d0adb4ff7dd75ee855f75d4b53d2bc4301ea91f3491bfaf2847294076a9edffa176290192d004488bdf87caa0b016
|
7
|
+
data.tar.gz: 7e371d515db7f86bd95c353fcd5153efd5d1f34ba6edb0c75b7602994309509615f602ba7463729326f3c8d3aa55ba290e67c0e24fac07e917d61e72d668b886
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
**NEWS**: Come hear a talk on Tupelo on December 11 in San Francisco at the [SF Distributed Computing meetup](http://www.meetup.com/San-Francisco-Distributed-Computing).
|
1
|
+
**NEWS**: Come hear a talk on Tupelo on December 11 in San Francisco at the [SF Distributed Computing meetup](http://www.meetup.com/San-Francisco-Distributed-Computing/events/153886592/). Abstract: [doc/sfdc.txt](doc/sfdc.md).
|
2
2
|
|
3
3
|
tupelo
|
4
4
|
==
|
@@ -93,6 +93,11 @@ Getting started
|
|
93
93
|
|
94
94
|
reads all 2-tuples.
|
95
95
|
|
96
|
+
Read tuples in a stream, both existing and as they arrive:
|
97
|
+
|
98
|
+
read <template> do |tuple| ... end
|
99
|
+
read do |tuple| ... end # match any tuple
|
100
|
+
|
96
101
|
Take a tuple matching a template:
|
97
102
|
|
98
103
|
t <template>
|
@@ -0,0 +1,35 @@
|
|
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
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Same as chat.rb, but no messages are stored.
|
2
|
+
|
3
|
+
require 'tupelo/app'
|
4
|
+
|
5
|
+
svr = "chat-nohistory.yaml"
|
6
|
+
|
7
|
+
Thread.abort_on_exception = true
|
8
|
+
|
9
|
+
def display_message msg
|
10
|
+
from, time, line = msg.values_at(*%w{from time line})
|
11
|
+
time_str = Time.at(time).strftime("%I:%M:%S")
|
12
|
+
print "\r\033[2K" # Esc[2K is "Clear entire line"
|
13
|
+
puts "#{from}@#{time_str}> #{line}"
|
14
|
+
end
|
15
|
+
|
16
|
+
Tupelo.tcp_application servers_file: svr do
|
17
|
+
me = argv.shift
|
18
|
+
|
19
|
+
local do
|
20
|
+
require 'readline'
|
21
|
+
|
22
|
+
Thread.new do
|
23
|
+
read from: nil, line: nil, time: nil do |msg|
|
24
|
+
display_message msg
|
25
|
+
Readline.refresh_line
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
while line = Readline.readline("#{me}> ", true)
|
30
|
+
pulse from: me, line: line, time: Time.now.to_f
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/example/chat/chat.rb
CHANGED
@@ -22,7 +22,8 @@ Thread.abort_on_exception = true
|
|
22
22
|
|
23
23
|
def display_message msg
|
24
24
|
from, time, line = msg.values_at(*%w{from time line})
|
25
|
-
time_str = Time.at(time).strftime("%I:%M
|
25
|
+
time_str = Time.at(time).strftime("%I:%M:%S")
|
26
|
+
print "\r\033[2K" # Esc[2K is "Clear entire line"
|
26
27
|
puts "#{from}@#{time_str}> #{line}"
|
27
28
|
end
|
28
29
|
|
@@ -33,15 +34,9 @@ Tupelo.tcp_application servers_file: svr do
|
|
33
34
|
require 'readline'
|
34
35
|
|
35
36
|
Thread.new do
|
36
|
-
seen_at_start = {}
|
37
|
-
read_all(from: nil, line: nil, time: nil).
|
38
|
-
sort_by {|msg| msg["time"]}.
|
39
|
-
each {|msg| display_message msg; seen_at_start[msg] = true}
|
40
|
-
|
41
37
|
read from: nil, line: nil, time: nil do |msg|
|
42
|
-
|
43
|
-
|
44
|
-
Readline.redisplay ### why not u work?
|
38
|
+
display_message msg
|
39
|
+
Readline.refresh_line
|
45
40
|
end
|
46
41
|
end
|
47
42
|
|
@@ -0,0 +1,34 @@
|
|
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
ADDED
@@ -0,0 +1,48 @@
|
|
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
|
@@ -0,0 +1,106 @@
|
|
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
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'tupelo/app'
|
2
|
+
|
3
|
+
Tupelo.application do
|
4
|
+
local do
|
5
|
+
use_subspaces!
|
6
|
+
|
7
|
+
define_subspace(
|
8
|
+
tag: "address books",
|
9
|
+
template: {
|
10
|
+
book: {type: "string"},
|
11
|
+
name: {type: "string"},
|
12
|
+
address: nil
|
13
|
+
}
|
14
|
+
)
|
15
|
+
|
16
|
+
define_subspace
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,130 @@
|
|
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
|
data/lib/tupelo/client/reader.rb
CHANGED
@@ -3,10 +3,14 @@ require 'tupelo/client/common'
|
|
3
3
|
class Tupelo::Client
|
4
4
|
# Include into class that defines #worker and #log.
|
5
5
|
module Api
|
6
|
-
# If block given,
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
6
|
+
# If no block given, return one matching tuple, blocking if necessary.
|
7
|
+
# If block given, yield each matching tuple that is found
|
8
|
+
# locally and then yield each new match as it is written to the space.
|
9
|
+
# Guaranteed not to miss tuples, even if they arrive and are immediately
|
10
|
+
# taken. (Note that simply doing read(template) in a loop would not
|
11
|
+
# have this guarantee.)
|
12
|
+
# The template defaults to Object, which matches any tuple.
|
13
|
+
def read_wait template = Object
|
10
14
|
waiter = Waiter.new(worker.make_template(template), self, !block_given?)
|
11
15
|
worker << waiter
|
12
16
|
if block_given?
|
@@ -23,13 +27,16 @@ class Tupelo::Client
|
|
23
27
|
end
|
24
28
|
alias read read_wait
|
25
29
|
|
26
|
-
|
30
|
+
# The template defaults to Object, which matches any tuple.
|
31
|
+
def read_nowait template = Object
|
27
32
|
matcher = Matcher.new(worker.make_template(template), self)
|
28
33
|
worker << matcher
|
29
34
|
matcher.wait
|
30
35
|
end
|
31
36
|
|
32
|
-
#
|
37
|
+
# Returns all matching tuples currently in the space. The template defaults
|
38
|
+
# to Object, which matches any tuple. Does not wait for more tuples to
|
39
|
+
# arrive.
|
33
40
|
def read_all template = Object
|
34
41
|
matcher = Matcher.new(worker.make_template(template), self, :all => true)
|
35
42
|
worker << matcher
|
data/lib/tupelo/client/worker.rb
CHANGED
@@ -507,13 +507,15 @@ class Tupelo::Client
|
|
507
507
|
end
|
508
508
|
|
509
509
|
def handle_waiter waiter
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
510
|
+
if waiter.once
|
511
|
+
tuple = tuplespace.find_match_for waiter.template
|
512
|
+
if tuple
|
513
|
+
waiter.peek tuple
|
514
|
+
else
|
514
515
|
read_waiters << waiter
|
515
516
|
end
|
516
517
|
else
|
518
|
+
tuplespace.each {|tuple| waiter.gloms tuple}
|
517
519
|
read_waiters << waiter
|
518
520
|
end
|
519
521
|
end
|
data/lib/tupelo/version.rb
CHANGED
data/test/unit/test-ops.rb
CHANGED
@@ -86,6 +86,30 @@ class TestOps < Minitest::Test
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
+
def test_read_stream
|
90
|
+
writer, reader = make_clients(2)
|
91
|
+
a = []
|
92
|
+
n = 10; k = 3
|
93
|
+
|
94
|
+
(0...k).each do |i|
|
95
|
+
writer.now {write [i]}
|
96
|
+
end
|
97
|
+
|
98
|
+
reader.will {read([nil]){|t| a << t}}
|
99
|
+
|
100
|
+
(0...k).each do |i|
|
101
|
+
reader.run_until_blocked
|
102
|
+
assert_equal [i], a[i]
|
103
|
+
end
|
104
|
+
|
105
|
+
assert_equal [0], a[0]
|
106
|
+
(k...n).each do |i|
|
107
|
+
writer.now {write [i]}
|
108
|
+
reader.run_until_blocked
|
109
|
+
assert_equal [i], a[i]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
89
113
|
def test_take_existing
|
90
114
|
t = ["foo"]
|
91
115
|
cl = make_clients(2)
|
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.13'
|
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-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: atdo
|
@@ -84,111 +84,119 @@ files:
|
|
84
84
|
- lib/tupelo/app/trace.rb
|
85
85
|
- lib/tupelo/app/builder.rb
|
86
86
|
- lib/tupelo/client.rb
|
87
|
-
- lib/tupelo/tuplets/persistent-archiver.rb
|
88
|
-
- lib/tupelo/tuplets/persistent-archiver/worker.rb
|
89
|
-
- lib/tupelo/tuplets/persistent-archiver/tuplespace.rb
|
90
|
-
- lib/tupelo/util/boolean.rb
|
91
87
|
- lib/tupelo/app.rb
|
92
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
|
95
|
+
- lib/tupelo/tuplets/persistent-archiver/worker.rb
|
96
|
+
- lib/tupelo/tuplets/persistent-archiver/tuplespace.rb
|
97
|
+
- lib/tupelo/tuplets/persistent-archiver.rb
|
93
98
|
- lib/tupelo/archiver/persister.rb
|
94
99
|
- lib/tupelo/archiver/worker.rb
|
95
100
|
- lib/tupelo/archiver/tuplespace.rb
|
96
101
|
- lib/tupelo/archiver/persistent-tuplespace.rb
|
97
|
-
- lib/tupelo/
|
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
|
102
|
+
- lib/tupelo/util/boolean.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/tiny-server.rb
|
131
|
+
- example/write-wait.rb
|
132
|
+
- example/tcp.rb
|
107
133
|
- 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-v2.rb
|
139
|
+
- example/subspaces/shop/shop-v2.rb
|
140
|
+
- example/subspaces/shop/shop-v1.rb
|
141
|
+
- example/subspaces/sorted-set-space.rb
|
142
|
+
- example/balance-xfer-retry.rb
|
143
|
+
- example/take-nowait-caution.rb
|
144
|
+
- example/lock-mgr-with-queue.rb
|
145
|
+
- example/hash-tuples.rb
|
146
|
+
- example/pulse.rb
|
147
|
+
- example/transaction-logic.rb
|
148
|
+
- example/lease.rb
|
149
|
+
- example/chat/chat.rb
|
150
|
+
- example/chat/chat-nohistory.rb
|
151
|
+
- example/balance-xfer.rb
|
108
152
|
- example/add-dsl.rb
|
109
|
-
- example/
|
110
|
-
- example/
|
111
|
-
- example/
|
112
|
-
- example/dphil.rb
|
113
|
-
- example/broker-optimistic.rb
|
153
|
+
- example/lock-mgr.rb
|
154
|
+
- example/broker-locking.rb
|
155
|
+
- example/dphil-optimistic.rb
|
114
156
|
- example/fail-and-retry.rb
|
115
|
-
- example/
|
116
|
-
- example/read-in-trans.rb
|
117
|
-
- example/bounded-retry.rb
|
118
|
-
- example/pregel/remote.rb
|
119
|
-
- example/pregel/pagerank.rb
|
157
|
+
- example/fish0.rb
|
120
158
|
- example/pregel/pregel.rb
|
121
159
|
- example/pregel/distributed.rb
|
160
|
+
- example/pregel/pagerank.rb
|
122
161
|
- example/pregel/update.rb
|
162
|
+
- example/pregel/remote.rb
|
163
|
+
- example/pregel/dist-opt.rb
|
164
|
+
- example/dphil-optimistic-v2.rb
|
165
|
+
- example/broker-optimistic-v2.rb
|
166
|
+
- example/remote.rb
|
123
167
|
- example/take-nowait.rb
|
124
|
-
- example/
|
125
|
-
- example/
|
126
|
-
- example/broker-locking.rb
|
127
|
-
- example/transaction-logic.rb
|
168
|
+
- example/wait-interrupt.rb
|
169
|
+
- example/optimist.rb
|
128
170
|
- 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/hash-tuples.rb
|
139
171
|
- example/balance-xfer-locking.rb
|
140
|
-
- example/
|
172
|
+
- example/increment.rb
|
173
|
+
- example/child-of-child.rb
|
174
|
+
- example/custom-class.rb
|
175
|
+
- example/matching.rb
|
141
176
|
- example/custom-search.rb
|
142
|
-
- example/
|
143
|
-
- example/
|
144
|
-
- example/
|
145
|
-
- example/
|
146
|
-
- example/multi-tier/kvspace.rb
|
147
|
-
- example/multi-tier/memo.rb
|
148
|
-
- example/multi-tier/drb.rb
|
149
|
-
- example/take-many.rb
|
150
|
-
- example/subspaces/simple.rb
|
151
|
-
- example/subspaces/shop/shop-v2.rb
|
152
|
-
- example/subspaces/shop/shop-v1.rb
|
153
|
-
- example/subspaces/pubsub.rb
|
154
|
-
- example/dphil-optimistic.rb
|
177
|
+
- example/broker-optimistic.rb
|
178
|
+
- example/notify.rb
|
179
|
+
- example/small-simplified.rb
|
180
|
+
- example/broker-queue.rb
|
155
181
|
- example/async-transaction.rb
|
156
|
-
- example/
|
157
|
-
- example/
|
158
|
-
- example/
|
182
|
+
- example/boolean-match.rb
|
183
|
+
- example/load-balancer.rb
|
184
|
+
- example/take-many.rb
|
159
185
|
- example/deadlock.rb
|
160
|
-
- example/
|
161
|
-
- example/add.rb
|
162
|
-
- example/dphil-optimistic-v2.rb
|
163
|
-
- example/parallel.rb
|
164
|
-
- example/tiny-client.rb
|
165
|
-
- example/map-reduce/map-reduce.rb
|
166
|
-
- example/map-reduce/remote-map-reduce.rb
|
167
|
-
- example/map-reduce/map-reduce-v2.rb
|
168
|
-
- example/lock-mgr-with-queue.rb
|
169
|
-
- example/balance-xfer.rb
|
170
|
-
- example/cancel.rb
|
171
|
-
- example/socket-broker.rb
|
172
|
-
- example/timeout-trans.rb
|
173
|
-
- example/optimist.rb
|
174
|
-
- example/tiny-server.rb
|
175
|
-
- example/pubsub.rb
|
176
|
-
- example/broker-optimistic-v2.rb
|
177
|
-
- example/write-wait.rb
|
178
|
-
- example/custom-class.rb
|
179
|
-
- test/stress/archiver-load.rb
|
180
|
-
- test/stress/concurrent-transactions.rb
|
181
|
-
- test/system/test-archiver.rb
|
182
|
-
- test/lib/mock-client.rb
|
183
|
-
- test/lib/time-fuzz.rb
|
184
|
-
- test/lib/mock-queue.rb
|
185
|
-
- test/lib/mock-seq.rb
|
186
|
+
- example/dphil.rb
|
186
187
|
- test/lib/testable-worker.rb
|
188
|
+
- test/lib/mock-seq.rb
|
187
189
|
- test/lib/mock-msg.rb
|
188
|
-
- test/
|
189
|
-
- test/
|
190
|
+
- test/lib/mock-queue.rb
|
191
|
+
- test/lib/time-fuzz.rb
|
192
|
+
- test/lib/mock-client.rb
|
193
|
+
- test/system/test-archiver.rb
|
190
194
|
- test/unit/test-ops.rb
|
191
195
|
- test/unit/test-mock-client.rb
|
196
|
+
- test/unit/test-mock-seq.rb
|
197
|
+
- test/unit/test-mock-queue.rb
|
198
|
+
- test/stress/concurrent-transactions.rb
|
199
|
+
- test/stress/archiver-load.rb
|
192
200
|
- bin/tup
|
193
201
|
- bin/tspy
|
194
202
|
homepage: https://github.com/vjoel/tupelo
|
@@ -223,8 +231,8 @@ signing_key:
|
|
223
231
|
specification_version: 4
|
224
232
|
summary: Distributed tuplespace
|
225
233
|
test_files:
|
226
|
-
- test/unit/test-mock-seq.rb
|
227
|
-
- test/unit/test-mock-queue.rb
|
228
234
|
- test/unit/test-ops.rb
|
229
235
|
- test/unit/test-mock-client.rb
|
236
|
+
- test/unit/test-mock-seq.rb
|
237
|
+
- test/unit/test-mock-queue.rb
|
230
238
|
has_rdoc:
|