archipelago 0.1.1 → 0.2.0
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.
- data/README +3 -3
- data/lib/archipelago/current.rb +69 -0
- data/lib/archipelago/disco.rb +102 -29
- data/lib/archipelago/hashish.rb +72 -9
- data/lib/archipelago/pirate.rb +54 -16
- data/lib/archipelago/treasure.rb +72 -48
- data/{scripts → script}/chest.rb +6 -5
- data/{scripts → script}/console +0 -0
- data/script/overloads.rb +61 -0
- data/script/pirate.rb +7 -0
- data/script/services.rb +24 -0
- data/{scripts → script}/tranny.rb +6 -5
- data/tests/current_benchmark.rb +28 -0
- data/tests/current_test.rb +29 -0
- data/tests/disco_benchmark.rb +21 -0
- data/tests/evaltest +3 -0
- data/tests/evaltestmore +3 -0
- data/tests/pirate_test.rb +17 -3
- data/tests/test_helper.rb +12 -12
- data/tests/treasure_benchmark.rb +85 -0
- data/tests/treasure_test.rb +31 -1
- metadata +19 -11
- data/profiles/1000xChest#join!-prepare!-commit!.rb +0 -19
- data/profiles/1000xDubloon#[]=(t).rb +0 -19
- data/profiles/1000xDubloon#method_missing(t).rb +0 -21
- data/profiles/README +0 -3
- data/profiles/profile_helper.rb +0 -25
- data/scripts/pirate.rb +0 -19
data/lib/archipelago/treasure.rb
CHANGED
@@ -39,7 +39,7 @@ module Archipelago
|
|
39
39
|
# The known chests by service id to speed up
|
40
40
|
# recovery by Dubloons having lost their Chest.
|
41
41
|
#
|
42
|
-
|
42
|
+
CHEST_BY_SERVICE_ID = {}
|
43
43
|
|
44
44
|
#
|
45
45
|
# Raised whenever the optimistic locking of the serializable transaction isolation level
|
@@ -55,8 +55,12 @@ module Archipelago
|
|
55
55
|
# Raised whenever a method is called on an object that we dont know about.
|
56
56
|
#
|
57
57
|
class UnknownObjectException < RuntimeError
|
58
|
-
def initialize(chest, key, transaction)
|
59
|
-
|
58
|
+
def initialize(chest, key, transaction = nil)
|
59
|
+
if transaction
|
60
|
+
super("#{chest} does not contain #{key} under #{transaction}")
|
61
|
+
else
|
62
|
+
super("#{chest} does not contain #{key}")
|
63
|
+
end
|
60
64
|
end
|
61
65
|
end
|
62
66
|
|
@@ -95,19 +99,42 @@ module Archipelago
|
|
95
99
|
# Remove all methods so that we look like our target.
|
96
100
|
#
|
97
101
|
instance_methods.each do |method|
|
98
|
-
undef_method method unless method =~ /^__/
|
102
|
+
undef_method method unless (method =~ /^__/ || method == "respond_to?")
|
103
|
+
end
|
104
|
+
#
|
105
|
+
# This Dubloon will always have the same hash, based on
|
106
|
+
# <b>object_id</b>.
|
107
|
+
#
|
108
|
+
def hash
|
109
|
+
self.object_id.hash
|
110
|
+
end
|
111
|
+
#
|
112
|
+
# Defers to Dubloon#==.
|
113
|
+
#
|
114
|
+
def eql?(o)
|
115
|
+
self.==(o)
|
116
|
+
end
|
117
|
+
#
|
118
|
+
# If o is a Dubloon, will return true if it has the same Dubloon#object_id.
|
119
|
+
#
|
120
|
+
# Otherwise will defer to Dubloon#method_missing.
|
121
|
+
#
|
122
|
+
def ==(o)
|
123
|
+
if Dubloon === o
|
124
|
+
return true if self.object_id == o.object_id
|
125
|
+
end
|
126
|
+
return self.method_missing(:==, o)
|
99
127
|
end
|
100
128
|
#
|
101
129
|
# Initialize us with knowledge of our +chest+, the +key+ to our
|
102
130
|
# target in the +chest+, the known +public_methods+ of our target
|
103
131
|
# and any +transaction+ we are associated with.
|
104
132
|
#
|
105
|
-
def initialize(key, chest, transaction, chest_id
|
133
|
+
def initialize(key, chest, transaction, chest_id)
|
106
134
|
@key = key
|
107
135
|
@chest = chest
|
108
136
|
@transaction = transaction
|
109
137
|
@chest_id = chest_id
|
110
|
-
@public_methods = public_methods
|
111
138
|
end
|
112
139
|
#
|
113
140
|
# A more or less normal dump of all our instance variables.
|
@@ -117,8 +144,7 @@ module Archipelago
|
|
117
144
|
@key,
|
118
145
|
@chest,
|
119
146
|
@transaction,
|
120
|
-
@chest_id
|
121
|
-
@public_methods
|
147
|
+
@chest_id
|
122
148
|
])
|
123
149
|
end
|
124
150
|
#
|
@@ -126,24 +152,12 @@ module Archipelago
|
|
126
152
|
# it actually is not correct.
|
127
153
|
#
|
128
154
|
def self._load(s)
|
129
|
-
key, chest, transaction, chest_id
|
130
|
-
instance = self.allocate
|
131
|
-
instance.instance_variable_set(:@key, key)
|
132
|
-
instance.instance_variable_set(:@transaction, transaction)
|
133
|
-
instance.instance_variable_set(:@chest_id, chest_id)
|
134
|
-
instance.instance_variable_set(:@public_methods, public_methods)
|
155
|
+
key, chest, transaction, chest_id = Marshal.load(s)
|
135
156
|
if CHEST_BY_SERVICE_ID.include?(chest_id)
|
136
|
-
|
137
|
-
else
|
138
|
-
instance.instance_variable_set(:@chest, chest)
|
157
|
+
chest = CHEST_BY_SERVICE_ID[chest_id]
|
139
158
|
end
|
140
|
-
|
141
|
-
|
142
|
-
#
|
143
|
-
# The public_methods of our target.
|
144
|
-
#
|
145
|
-
def public_methods
|
146
|
-
return @public_methods.clone
|
159
|
+
|
160
|
+
return self.new(key, chest, transaction, chest_id)
|
147
161
|
end
|
148
162
|
#
|
149
163
|
# Return a clone of myself that is joined to
|
@@ -151,7 +165,7 @@ module Archipelago
|
|
151
165
|
#
|
152
166
|
def join(transaction)
|
153
167
|
@chest.join!(transaction) if transaction
|
154
|
-
return Dubloon.new(@key, @chest, transaction, @chest_id
|
168
|
+
return Dubloon.new(@key, @chest, transaction, @chest_id)
|
155
169
|
end
|
156
170
|
#
|
157
171
|
# Raises exception if the given +transaction+
|
@@ -161,7 +175,8 @@ module Archipelago
|
|
161
175
|
raise UnknownTransactionException.new(self, transaction) unless transaction == @transaction
|
162
176
|
end
|
163
177
|
#
|
164
|
-
#
|
178
|
+
# This Dubloon will always have the same object_id, based on
|
179
|
+
# @chest_id and @key and possibly @transaction.
|
165
180
|
#
|
166
181
|
def object_id
|
167
182
|
id = "#{@chest_id}:#{@key}"
|
@@ -172,31 +187,29 @@ module Archipelago
|
|
172
187
|
# Does our target respond to +meth+?
|
173
188
|
#
|
174
189
|
def respond_to?(meth)
|
175
|
-
|
190
|
+
# This one will be called far too often, and it seems safe to ignore it.
|
191
|
+
return false if meth == :marshal_dump
|
192
|
+
return super(meth) || self.method_missing(:respond_to?, meth)
|
176
193
|
end
|
177
194
|
#
|
178
195
|
# Call +meth+ with +args+ and +block+ on our target if it responds to
|
179
196
|
# it.
|
180
197
|
#
|
181
198
|
def method_missing(meth, *args, &block)
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
raise e
|
196
|
-
end
|
199
|
+
begin
|
200
|
+
return @chest.call_instance_method(@key, meth, @transaction, *args, &block)
|
201
|
+
rescue DRb::DRbConnError => e
|
202
|
+
if defined?(Archipelago::Disco::MC)
|
203
|
+
possible_replacements = Archipelago::Disco::MC.lookup(Archipelago::Disco::Query.new({:service_id => @chest_id}))
|
204
|
+
raise e if possible_replacements.empty?
|
205
|
+
|
206
|
+
@chest = possible_replacements[@chest_id][:service]
|
207
|
+
CHEST_BY_SERVICE_ID[@chest_id] = @chest
|
208
|
+
|
209
|
+
retry
|
210
|
+
else
|
211
|
+
raise e
|
197
212
|
end
|
198
|
-
else
|
199
|
-
return super(meth, *args)
|
200
213
|
end
|
201
214
|
end
|
202
215
|
|
@@ -268,7 +281,7 @@ module Archipelago
|
|
268
281
|
|
269
282
|
initialize_prepared(options[:transaction_recovery_interval] || TRANSACTION_RECOVERY_INTERVAL)
|
270
283
|
|
271
|
-
|
284
|
+
CHEST_BY_SERVICE_ID[self.service_id] = self
|
272
285
|
end
|
273
286
|
|
274
287
|
#
|
@@ -278,6 +291,17 @@ module Archipelago
|
|
278
291
|
@snapshot_by_transaction.keys.clone
|
279
292
|
end
|
280
293
|
|
294
|
+
#
|
295
|
+
# Will do +callable+.call(key, value)
|
296
|
+
# for each key-and-value pair in this Chest.
|
297
|
+
#
|
298
|
+
# NB: This is totaly thread-unsafe, only do this
|
299
|
+
# for management or rescue!
|
300
|
+
#
|
301
|
+
def each(callable)
|
302
|
+
@db.each(callable)
|
303
|
+
end
|
304
|
+
|
281
305
|
#
|
282
306
|
# Evaluate +data+ if we have not already seen +label+ or if we have an earlier +timestamp+ than the one given.
|
283
307
|
#
|
@@ -316,7 +340,7 @@ module Archipelago
|
|
316
340
|
if Dubloon === instance
|
317
341
|
return instance.join(transaction)
|
318
342
|
else
|
319
|
-
return Dubloon.new(key, self, transaction, self.service_id
|
343
|
+
return Dubloon.new(key, self, transaction, self.service_id)
|
320
344
|
end
|
321
345
|
end
|
322
346
|
|
@@ -623,7 +647,7 @@ module Archipelago
|
|
623
647
|
def call_without_transaction(key, method, *arguments, &block)
|
624
648
|
instance = @db[key]
|
625
649
|
|
626
|
-
raise UnknownObjectException(self, key
|
650
|
+
raise UnknownObjectException(self, key) unless instance
|
627
651
|
|
628
652
|
begin
|
629
653
|
return execute(instance, method, *arguments, &block)
|
@@ -721,7 +745,7 @@ module Archipelago
|
|
721
745
|
|
722
746
|
return value if Dubloon === value
|
723
747
|
|
724
|
-
return Dubloon.new(key, self, transaction, service_id
|
748
|
+
return Dubloon.new(key, self, transaction, service_id)
|
725
749
|
end
|
726
750
|
|
727
751
|
#
|
data/{scripts → script}/chest.rb
RENAMED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
if ARGV.size < 1
|
4
|
-
puts "Usage: #{$0} DB-PATH [
|
4
|
+
puts "Usage: #{$0} DB-PATH [EXTRA-LIBS]"
|
5
5
|
exit 1
|
6
6
|
end
|
7
7
|
|
@@ -9,11 +9,12 @@ $: << File.join(File.dirname(__FILE__), "..", "lib")
|
|
9
9
|
|
10
10
|
require 'archipelago/treasure'
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
else
|
15
|
-
DRb.start_service
|
12
|
+
ARGV[1..-1].each do |lib|
|
13
|
+
load lib
|
16
14
|
end
|
15
|
+
|
16
|
+
DRb.start_service
|
17
|
+
|
17
18
|
c = Archipelago::Treasure::Chest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(ARGV[0])))
|
18
19
|
c.publish!
|
19
20
|
|
data/{scripts → script}/console
RENAMED
File without changes
|
data/script/overloads.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# An overload of Archipelago::Hashish::BerkeleyHashish
|
4
|
+
# just to get a few nice debugging methods.
|
5
|
+
#
|
6
|
+
class Archipelago::Hashish::BerkeleyHashish
|
7
|
+
attr_reader :content
|
8
|
+
#
|
9
|
+
# Get the serialized value for +key+.
|
10
|
+
#
|
11
|
+
def get_serialized_value(key)
|
12
|
+
@content_db[Marshal.dump(key)]
|
13
|
+
end
|
14
|
+
#
|
15
|
+
# Yield to +block+ once for every key/value inside this BerkeleyHashish.
|
16
|
+
#
|
17
|
+
def each(&block)
|
18
|
+
@content_db.each do |serialized_key, serialized_value|
|
19
|
+
key = Marshal.load(serialized_key)
|
20
|
+
yield(key, self[key])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
#
|
24
|
+
# Empties the BerkeleyHashish.
|
25
|
+
#
|
26
|
+
def clear
|
27
|
+
@content_db.clear
|
28
|
+
@content.clear
|
29
|
+
@timestamps_db.clear
|
30
|
+
@timestamps.clear
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# An overload of Archipelago::Treasure::Chest just to
|
36
|
+
# get a few nice debugging methods.
|
37
|
+
#
|
38
|
+
class Archipelago::Treasure::Chest
|
39
|
+
#
|
40
|
+
# Yield to +block+ once for every key/value inside this Chest.
|
41
|
+
#
|
42
|
+
def each(&block)
|
43
|
+
@db.each do |key, value|
|
44
|
+
yield(key, value)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
#
|
48
|
+
# Returns a Hash containing what we contain.
|
49
|
+
#
|
50
|
+
def all
|
51
|
+
@db.each do |key, value|
|
52
|
+
end
|
53
|
+
@db.content
|
54
|
+
end
|
55
|
+
#
|
56
|
+
# Empties the Chest.
|
57
|
+
#
|
58
|
+
def clear
|
59
|
+
@db.clear
|
60
|
+
end
|
61
|
+
end
|
data/script/pirate.rb
ADDED
data/script/services.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if ARGV.size < 1
|
4
|
+
puts "Usage: #{$0} DB-PATH [EXTRA-LIBS]"
|
5
|
+
exit 1
|
6
|
+
end
|
7
|
+
|
8
|
+
$: << File.join(File.dirname(__FILE__), "..", "lib")
|
9
|
+
|
10
|
+
require 'archipelago/treasure'
|
11
|
+
require 'archipelago/tranny'
|
12
|
+
|
13
|
+
ARGV[1..-1].each do |lib|
|
14
|
+
load lib
|
15
|
+
end
|
16
|
+
|
17
|
+
DRb.start_service
|
18
|
+
|
19
|
+
t = Archipelago::Tranny::Manager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(File.join(ARGV[0], "tranny"))))
|
20
|
+
t.publish!
|
21
|
+
c = Archipelago::Treasure::Chest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(File.join(ARGV[0], "chest"))))
|
22
|
+
c.publish!
|
23
|
+
|
24
|
+
DRb.thread.join
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
if ARGV.size < 1
|
4
|
-
puts "Usage: #{$0} DB-PATH
|
4
|
+
puts "Usage: #{$0} DB-PATH [EXTRA-LIBS]"
|
5
5
|
exit 1
|
6
6
|
end
|
7
7
|
|
@@ -9,11 +9,12 @@ $: << File.join(File.dirname(__FILE__), "..", "lib")
|
|
9
9
|
|
10
10
|
require 'archipelago/treasure'
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
else
|
15
|
-
DRb.start_service
|
12
|
+
ARGV[1..-1].each do |lib|
|
13
|
+
load lib
|
16
14
|
end
|
15
|
+
|
16
|
+
DRb.start_service
|
17
|
+
|
17
18
|
t = Archipelago::Tranny::Manager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(ARGV[0])))
|
18
19
|
t.publish!
|
19
20
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
3
|
+
|
4
|
+
class CurrentBenchmark < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_synchronize
|
7
|
+
s = "hehu"
|
8
|
+
s2 = "oj"
|
9
|
+
s.extend(Archipelago::Current::Synchronized)
|
10
|
+
bm("Synchronized#synchronize", :n => 10000) do
|
11
|
+
s.synchronize do
|
12
|
+
end
|
13
|
+
end
|
14
|
+
bm("Synchronized#synchronize_on", :n => 10000) do
|
15
|
+
s.synchronize_on(s2) do
|
16
|
+
end
|
17
|
+
end
|
18
|
+
bm("Synchronized#lock/unlock", :n => 100000) do
|
19
|
+
s.lock
|
20
|
+
s.unlock
|
21
|
+
end
|
22
|
+
bm("Synchronized#lock_on/unlock_on", :n => 10000) do
|
23
|
+
s.lock_on(s2)
|
24
|
+
s.unlock_on(s2)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/tests/current_test.rb
CHANGED
@@ -24,4 +24,33 @@ class CurrentTest < Test::Unit::TestCase
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
def test_threaded_collection
|
28
|
+
a = Array(10)
|
29
|
+
a.extend(Archipelago::Current::ThreadedCollection)
|
30
|
+
|
31
|
+
assert_equal(a.select do |e| e == nil end,
|
32
|
+
a.t_select do |e| e == nil end)
|
33
|
+
assert_equal(a.reject do |e| e == nil end,
|
34
|
+
a.t_reject do |e| e == nil end)
|
35
|
+
assert_equal(a.collect do |e| e == nil end,
|
36
|
+
a.t_collect do |e| e == nil end)
|
37
|
+
b = []
|
38
|
+
a.t_each do |e| b << e end
|
39
|
+
assert_equal(b, a)
|
40
|
+
|
41
|
+
a = {1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5}
|
42
|
+
a.extend(Archipelago::Current::ThreadedCollection)
|
43
|
+
|
44
|
+
assert_equal(a.select do |k,v| k == nil end,
|
45
|
+
a.t_select do |k,v| k == nil end)
|
46
|
+
assert_equal(a.to_a.reject do |k,v| k == nil end,
|
47
|
+
a.t_reject do |k,v| k == nil end)
|
48
|
+
assert_equal(a.collect do |k,v| k == nil end,
|
49
|
+
a.t_collect do |k,c| k == nil end)
|
50
|
+
|
51
|
+
b = {}
|
52
|
+
a.t_each do |k,v| b[k] = v end
|
53
|
+
assert_equal(b,a)
|
54
|
+
end
|
55
|
+
|
27
56
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
3
|
+
|
4
|
+
class DiscoBenchmark < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_lookup
|
7
|
+
dj1 = TestJockey.new
|
8
|
+
dj2 = TestJockey.new
|
9
|
+
x = 0
|
10
|
+
bm("Jockey#publish/lookup", :n => 10) do
|
11
|
+
dj1.publish(Archipelago::Disco::Record.new({:service_id => x, :validator => Archipelago::Disco::MockValidator.new}))
|
12
|
+
assert(!dj2.lookup(Archipelago::Disco::Query.new({:service_id => x})).empty?)
|
13
|
+
x += 1
|
14
|
+
end
|
15
|
+
dj1.publish(Archipelago::Disco::Record.new({:service_id => "brappa", :validator => Archipelago::Disco::MockValidator.new}))
|
16
|
+
bm("Jockey#lookup", :n => 10) do
|
17
|
+
assert(!dj2.lookup(Archipelago::Disco::Query.new({:service_id => "brappa"})).empty?)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/tests/evaltest
ADDED
data/tests/evaltestmore
ADDED
data/tests/pirate_test.rb
CHANGED
@@ -11,24 +11,38 @@ class PirateTest < Test::Unit::TestCase
|
|
11
11
|
@c.publish!
|
12
12
|
@c2 = TestChest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("chest2.db")))
|
13
13
|
@c2.publish!
|
14
|
-
@tm = TestManager.new
|
14
|
+
@tm = TestManager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("tranny.db")))
|
15
15
|
@tm.publish!
|
16
|
+
@p.update_services!
|
16
17
|
assert_within(10) do
|
17
|
-
|
18
|
+
@p.chests.keys.sort == [@c.service_id, @c2.service_id].sort
|
18
19
|
end
|
19
20
|
assert_within(10) do
|
20
|
-
|
21
|
+
@p.trannies.keys == [@tm.service_id]
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
25
|
def teardown
|
25
26
|
@p.stop!
|
27
|
+
@c.stop!
|
26
28
|
@c.persistence_provider.unlink
|
29
|
+
@c2.stop!
|
27
30
|
@c2.persistence_provider.unlink
|
31
|
+
@tm.stop!
|
28
32
|
@tm.persistence_provider.unlink
|
29
33
|
DRb.stop_service
|
30
34
|
end
|
31
35
|
|
36
|
+
def test_each
|
37
|
+
@p["oj"] = "bla"
|
38
|
+
@p["brunt"] = "ja"
|
39
|
+
h = {}
|
40
|
+
@p.each(Proc.new do |k,v|
|
41
|
+
h[k] = v
|
42
|
+
end)
|
43
|
+
assert_equal({"oj" => "bla", "brunt" => "ja"}, h)
|
44
|
+
end
|
45
|
+
|
32
46
|
def test_evaluate
|
33
47
|
assert_raise(NameError) do
|
34
48
|
e = Evaltest.new
|
data/tests/test_helper.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
home = File.expand_path(File.dirname(__FILE__))
|
3
3
|
$: << File.join(home, "..", "lib")
|
4
4
|
|
5
|
-
MC_DISABLED = true
|
5
|
+
MC_DISABLED = true unless defined?(MC_ENABLED) && MC_ENABLED
|
6
6
|
|
7
7
|
require 'pp'
|
8
8
|
require 'drb'
|
@@ -37,20 +37,20 @@ class TestChest < Archipelago::Treasure::Chest
|
|
37
37
|
attr_reader :persistence_provider
|
38
38
|
end
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
n.times do
|
48
|
-
yield
|
49
|
-
end
|
40
|
+
def bm(label = "", options = {})
|
41
|
+
n = options[:n] || 1000
|
42
|
+
width = options[:width] || 50
|
43
|
+
Benchmark.benchmark(" " * width + Benchmark::Tms::CAPTION, width, Benchmark::Tms::FMTSTR, "ms/call") do |b|
|
44
|
+
times = b.report("#{n}x#{label}") do
|
45
|
+
n.times do
|
46
|
+
yield
|
50
47
|
end
|
51
|
-
[times * 1000 / n.to_f]
|
52
48
|
end
|
49
|
+
[times * 1000 / n.to_f]
|
53
50
|
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class Test::Unit::TestCase
|
54
54
|
|
55
55
|
def assert_within(timeout, &block)
|
56
56
|
t = Time.new
|
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
3
|
+
|
4
|
+
class TreasureBenchmark < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
DRb.start_service
|
8
|
+
@c = TestChest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("chest.db")))
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@c.persistence_provider.unlink
|
13
|
+
DRb.stop_service
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_outside_transaction
|
17
|
+
k = "hehu"
|
18
|
+
v = "ojoj"
|
19
|
+
bm("Chest#[]=", :n => 1000) do
|
20
|
+
@c[k] = v
|
21
|
+
k = k.next
|
22
|
+
end
|
23
|
+
k = "hehu"
|
24
|
+
bm("Chest#[]", :n => 1000) do
|
25
|
+
t = @c[k]
|
26
|
+
k = k.next
|
27
|
+
end
|
28
|
+
k = "hehu"
|
29
|
+
bm("Chest#delete", :n => 1000) do
|
30
|
+
t = @c.delete(k)
|
31
|
+
k = k.next
|
32
|
+
end
|
33
|
+
@c[k] = v
|
34
|
+
v = @c[k]
|
35
|
+
bm("Dubloon#method_missing") do
|
36
|
+
t = v.size
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_inside_transaction
|
41
|
+
k = "hehu"
|
42
|
+
v = "ojoj"
|
43
|
+
tr = TestTransaction.new
|
44
|
+
bm("Chest#[]= (t)", :n => 1000) do
|
45
|
+
@c[k,tr] = v
|
46
|
+
k = k.next
|
47
|
+
end
|
48
|
+
k = "hehu"
|
49
|
+
bm("Chest#[] (t)", :n => 1000) do
|
50
|
+
t = @c[k,tr]
|
51
|
+
k = k.next
|
52
|
+
end
|
53
|
+
k = "hehu"
|
54
|
+
bm("Chest#delete (t)", :n => 1000) do
|
55
|
+
t = @c.delete(k,tr)
|
56
|
+
k = k.next
|
57
|
+
end
|
58
|
+
@c[k,tr] = v
|
59
|
+
v = @c[k,tr]
|
60
|
+
bm("Dubloon#method_missing (t)") do
|
61
|
+
t = v.upcase
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_transaction_overhead
|
66
|
+
k = "hehu"
|
67
|
+
v = "ojoj"
|
68
|
+
tr = TestTransaction.new
|
69
|
+
bm("Chest#join!/[]=/prepare!/commit!", :n => 1000) do
|
70
|
+
@c[k, tr] = v
|
71
|
+
@c.prepare!(tr)
|
72
|
+
@c.commit!(tr)
|
73
|
+
end
|
74
|
+
bm("Chest#join!/[]=/abort!", :n => 1000) do
|
75
|
+
@c[k, tr] = v
|
76
|
+
@c.abort!(tr)
|
77
|
+
end
|
78
|
+
bm("Chest#join!/[]=/prepare!/abort!", :n => 1000) do
|
79
|
+
@c[k, tr] = v
|
80
|
+
@c.prepare!(tr)
|
81
|
+
@c.abort!(tr)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
data/tests/treasure_test.rb
CHANGED
@@ -1,13 +1,23 @@
|
|
1
1
|
|
2
2
|
require File.join(File.dirname(__FILE__), 'test_helper')
|
3
3
|
|
4
|
+
class A < String
|
5
|
+
def save_hook(old_value, &block)
|
6
|
+
$BURKMAT += 1
|
7
|
+
yield
|
8
|
+
$BURKMAT2 += 1
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
4
12
|
class TreasureTest < Test::Unit::TestCase
|
5
13
|
|
6
14
|
def setup
|
7
15
|
DRb.start_service
|
8
16
|
@c = TestChest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("chest.db")))
|
9
17
|
@c2 = TestChest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("chest2.db")))
|
10
|
-
@tm = TestManager.new
|
18
|
+
@tm = TestManager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("tranny1.db")))
|
19
|
+
$BURKMAT = 0
|
20
|
+
$BURKMAT2 = 0
|
11
21
|
end
|
12
22
|
|
13
23
|
def teardown
|
@@ -17,6 +27,26 @@ class TreasureTest < Test::Unit::TestCase
|
|
17
27
|
DRb.stop_service
|
18
28
|
end
|
19
29
|
|
30
|
+
def test_each
|
31
|
+
@c["oj"] = "bla"
|
32
|
+
@c["brunt"] = "ja"
|
33
|
+
h = {}
|
34
|
+
@c.each(Proc.new do |k,v|
|
35
|
+
h[k] = v
|
36
|
+
end)
|
37
|
+
assert_equal({"oj" => "bla", "brunt" => "ja"}, h)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_around_save
|
41
|
+
s = A.new("hehu")
|
42
|
+
@c["oj"] = s
|
43
|
+
assert_equal(1, $BURKMAT)
|
44
|
+
assert_equal(1, $BURKMAT2)
|
45
|
+
@c["oj"].upcase!
|
46
|
+
assert_equal(2, $BURKMAT)
|
47
|
+
assert_equal(2, $BURKMAT2)
|
48
|
+
end
|
49
|
+
|
20
50
|
def test_eval
|
21
51
|
t = Time.now
|
22
52
|
@c.evaluate!("burk", t, "class Burk; end")
|