archipelago 0.2.7 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/archipelago.rb +2 -0
- data/lib/archipelago/client.rb +9 -3
- data/lib/archipelago/current.rb +0 -35
- data/lib/archipelago/disco.rb +39 -17
- data/lib/archipelago/dump.rb +1 -0
- data/lib/archipelago/hashish.rb +1 -0
- data/lib/archipelago/pirate.rb +1 -2
- data/lib/archipelago/sanitation.rb +5 -2
- data/lib/archipelago/treasure.rb +28 -7
- data/script/pirate.rb +1 -1
- data/tests/current_test.rb +0 -35
- data/tests/disco_benchmark.rb +2 -2
- data/tests/disco_test.rb +39 -6
- data/tests/pirate_test.rb +8 -4
- data/tests/sanitation_test.rb +24 -4
- metadata +38 -29
data/lib/archipelago.rb
CHANGED
data/lib/archipelago/client.rb
CHANGED
@@ -35,11 +35,13 @@ module Archipelago
|
|
35
35
|
# The timeout that will be used in the first lookup to ensure that we actually
|
36
36
|
# have any services.
|
37
37
|
#
|
38
|
-
INITIAL_LOOKUP_TIMEOUT =
|
38
|
+
INITIAL_LOOKUP_TIMEOUT = 0
|
39
39
|
|
40
40
|
class Base
|
41
41
|
include Archipelago::Disco::Camel
|
42
|
+
|
42
43
|
attr_reader :jockey, :services, :service_descriptions
|
44
|
+
attr_accessor :debug_callable
|
43
45
|
|
44
46
|
#
|
45
47
|
# Initialize a Client using Archipelago::Disco::MC or <i>:jockey</i> if given,
|
@@ -55,6 +57,7 @@ module Archipelago
|
|
55
57
|
@maximum_service_update_interval = options[:maximum_service_update_interval] || MAXIMUM_SERVICE_UPDATE_INTERVAL
|
56
58
|
@service_descriptions = options[:service_descriptions]
|
57
59
|
@initial_lookup_timeout = options[:initial_lookup_timeout] || INITIAL_LOOKUP_TIMEOUT
|
60
|
+
@debug_callable = options[:debug_callable]
|
58
61
|
@services = {}
|
59
62
|
@service_descriptions.each do |name, description|
|
60
63
|
@services[name] = Archipelago::Disco::ServiceLocker.new
|
@@ -101,6 +104,8 @@ module Archipelago
|
|
101
104
|
#
|
102
105
|
def update_services!(options = {})
|
103
106
|
timeout = options[:timeout] || 0
|
107
|
+
silent = options[:silent] || false
|
108
|
+
|
104
109
|
validate = options[:validate] || false
|
105
110
|
around_update_services do
|
106
111
|
@service_descriptions.each do |name, description|
|
@@ -117,10 +122,11 @@ module Archipelago
|
|
117
122
|
# more than on average once every MAXIMUM_SERVICE_UPDATE_INTERVAL, so that MAY make it worthwhile to do
|
118
123
|
# the RBTree song and dance in here. Hopefully.
|
119
124
|
#
|
120
|
-
new_services = @jockey.lookup(Archipelago::Disco::Query.new(description), timeout)
|
125
|
+
new_services = @jockey.lookup(Archipelago::Disco::Query.new(description), :timeout => timeout, :silent => silent)
|
121
126
|
new_services.convert_to_tree!
|
122
127
|
new_services.validate! if validate
|
123
128
|
@services[name] = new_services
|
129
|
+
@debug_callable.call("#{self}.service[#{name.inspect}]: #{PP.pp(@services[name].keys, "")}") if @debug_callable
|
124
130
|
end
|
125
131
|
end
|
126
132
|
end
|
@@ -214,7 +220,7 @@ module Archipelago
|
|
214
220
|
def start_service_updater
|
215
221
|
update_services!(:timeout => @initial_lookup_timeout, :validate => true)
|
216
222
|
@service_update_thread.kill if defined?(@service_update_thread)
|
217
|
-
@service_update_thread = Thread.
|
223
|
+
@service_update_thread = Thread.new do
|
218
224
|
standoff = @initial_service_update_interval
|
219
225
|
loop do
|
220
226
|
begin
|
data/lib/archipelago/current.rb
CHANGED
@@ -33,41 +33,6 @@ module Archipelago
|
|
33
33
|
|
34
34
|
module Current
|
35
35
|
|
36
|
-
class Queue
|
37
|
-
def initialize
|
38
|
-
@lock = Monitor.new
|
39
|
-
@flag = MonitorMixin::ConditionVariable.new(@lock)
|
40
|
-
@ary = []
|
41
|
-
end
|
42
|
-
def <<(e)
|
43
|
-
@lock.synchronize do
|
44
|
-
@ary << e
|
45
|
-
@flag.broadcast
|
46
|
-
end
|
47
|
-
end
|
48
|
-
def empty?(wait = false)
|
49
|
-
@lock.synchronize do
|
50
|
-
if wait
|
51
|
-
@flag.wait_until do
|
52
|
-
@ary.empty?
|
53
|
-
end unless @ary.empty?
|
54
|
-
return @ary.empty?
|
55
|
-
else
|
56
|
-
return @ary.empty?
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
def shift
|
61
|
-
@lock.synchronize do
|
62
|
-
@flag.wait_while do
|
63
|
-
@ary.empty?
|
64
|
-
end if @ary.empty?
|
65
|
-
@flag.broadcast
|
66
|
-
return @ary.shift
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
36
|
#
|
72
37
|
# Adds a few threaded methods to the normal ruby collections.
|
73
38
|
#
|
data/lib/archipelago/disco.rb
CHANGED
@@ -46,7 +46,7 @@ module Archipelago
|
|
46
46
|
#
|
47
47
|
# Default lookup timeout.
|
48
48
|
#
|
49
|
-
LOOKUP_TIMEOUT =
|
49
|
+
LOOKUP_TIMEOUT = 0
|
50
50
|
#
|
51
51
|
# Default initial pause between resending lookup queries.
|
52
52
|
# Will be doubled for each resend.
|
@@ -80,6 +80,7 @@ module Archipelago
|
|
80
80
|
# can include this for simplicity.
|
81
81
|
#
|
82
82
|
module Camel
|
83
|
+
attr_reader :jockey
|
83
84
|
private
|
84
85
|
#
|
85
86
|
# Setup our @jockey as a Archipelago::Disco::Jockey with given options.
|
@@ -311,11 +312,20 @@ module Archipelago
|
|
311
312
|
@attributes = hash
|
312
313
|
end
|
313
314
|
#
|
315
|
+
# To make it Hash and Set friendly.
|
316
|
+
#
|
317
|
+
def hash
|
318
|
+
@attributes.inject(0) do |sum, pair|
|
319
|
+
sum + pair.first.hash + pair.last.hash
|
320
|
+
end
|
321
|
+
end
|
322
|
+
#
|
314
323
|
# Returns whether our @attributes are equal to that of +o+.
|
315
324
|
#
|
316
325
|
def eql?(o)
|
317
326
|
ServiceDescription === o && @attributes == o.attributes
|
318
327
|
end
|
328
|
+
alias :== :eql?
|
319
329
|
#
|
320
330
|
# Returns whether this ServiceDescription matches the given +match+.
|
321
331
|
#
|
@@ -433,7 +443,7 @@ module Archipelago
|
|
433
443
|
#
|
434
444
|
def get_services(match)
|
435
445
|
rval = ServiceLocker.new
|
436
|
-
self.
|
446
|
+
self.each do |service_id, service_data|
|
437
447
|
if service_data.matches?(match)
|
438
448
|
rval[service_id] = service_data
|
439
449
|
end
|
@@ -486,8 +496,8 @@ module Archipelago
|
|
486
496
|
@local_services = ServiceLocker.new(:jockey => self)
|
487
497
|
@subscribed_services = Set.new
|
488
498
|
|
489
|
-
@incoming =
|
490
|
-
@outgoing =
|
499
|
+
@incoming = Queue.new
|
500
|
+
@outgoing = Queue.new
|
491
501
|
|
492
502
|
@new_service_semaphore = MonitorMixin::ConditionVariable.new(Archipelago::Current::Lock.new)
|
493
503
|
@service_change_subscribers_by_event_type = {:found => {}, :lost => {}}
|
@@ -503,6 +513,9 @@ module Archipelago
|
|
503
513
|
# Will listen for +event_type+s matching the Query +match+
|
504
514
|
# and do +block+.call with the matching Record.
|
505
515
|
#
|
516
|
+
# +identity+ is used to determine what subscription to remove
|
517
|
+
# when doing unsubscribe.
|
518
|
+
#
|
506
519
|
# Recognized +event_types+: :found, :lost
|
507
520
|
#
|
508
521
|
def subscribe(event_type, match, identity, &block)
|
@@ -510,7 +523,7 @@ module Archipelago
|
|
510
523
|
end
|
511
524
|
|
512
525
|
#
|
513
|
-
# Will stop listening for +event_type+ and +match+.
|
526
|
+
# Will stop listening for +event_type+ and +match+ with +identity+.
|
514
527
|
#
|
515
528
|
def unsubscribe(event_type, match, identity)
|
516
529
|
@service_change_subscribers_by_event_type[event_type].delete([match, identity])
|
@@ -588,12 +601,16 @@ module Archipelago
|
|
588
601
|
@listener_thread.kill
|
589
602
|
@unilistener_thread.kill
|
590
603
|
|
591
|
-
@incoming.empty?(true)
|
592
|
-
@picker_thread.kill
|
593
604
|
@listener.close
|
594
605
|
@unilistener.close
|
595
|
-
|
596
|
-
|
606
|
+
while !@incoming.empty?
|
607
|
+
sleep 0.1
|
608
|
+
end
|
609
|
+
@picker_thread.kill
|
610
|
+
|
611
|
+
while !@outgoing.empty?
|
612
|
+
sleep 0.1
|
613
|
+
end
|
597
614
|
@shouter_thread.kill
|
598
615
|
@sender.close
|
599
616
|
@unisender.close
|
@@ -603,36 +620,41 @@ module Archipelago
|
|
603
620
|
end
|
604
621
|
|
605
622
|
#
|
606
|
-
# Lookup any services matching +match+, optionally
|
623
|
+
# Lookup any services matching +match+, optionally
|
624
|
+
# with a +:timeout+ and optionally +:silent+.
|
607
625
|
#
|
608
626
|
# Will immediately return if we know of matching and valid services,
|
609
627
|
# will otherwise send out regular Queries and return as soon as
|
610
628
|
# matching services are found, or when the +timeout+ runs out.
|
611
629
|
#
|
612
|
-
def lookup(match,
|
630
|
+
def lookup(match, options = {})
|
631
|
+
timeout = options[:timeout] || @lookup_timeout
|
632
|
+
silent = options[:silent] || false
|
633
|
+
|
613
634
|
match[:unicast_reply] = @unicast_address
|
614
635
|
@subscribed_services << match if @thrifty_caching
|
615
636
|
standoff = @initial_lookup_standoff
|
616
637
|
|
617
|
-
@outgoing << [nil, match]
|
638
|
+
@outgoing << [nil, match] unless silent
|
618
639
|
known_services = @remote_services.get_services(match).merge(@local_services.get_services(match))
|
619
640
|
return known_services if timeout == 0 || !known_services.empty?
|
620
641
|
|
621
642
|
t = Time.new
|
622
643
|
@new_service_semaphore.wait([standoff, timeout].min)
|
623
644
|
standoff *= 2
|
624
|
-
|
645
|
+
|
625
646
|
while Time.new < t + timeout
|
626
647
|
known_services = @remote_services.get_services(match).merge(@local_services.get_services(match))
|
627
648
|
return known_services unless known_services.empty?
|
628
649
|
|
629
|
-
|
650
|
+
wait_time = [standoff, (t + timeout) - Time.new].min
|
651
|
+
@new_service_semaphore.wait(wait_time)
|
630
652
|
standoff *= 2
|
631
653
|
|
632
|
-
@outgoing << [nil, match]
|
654
|
+
@outgoing << [nil, match] unless silent
|
633
655
|
end
|
634
656
|
|
635
|
-
ServiceLocker.new
|
657
|
+
return ServiceLocker.new
|
636
658
|
end
|
637
659
|
|
638
660
|
#
|
@@ -786,7 +808,7 @@ module Archipelago
|
|
786
808
|
@picker_thread = Thread.new do
|
787
809
|
loop do
|
788
810
|
begin
|
789
|
-
data = @incoming.
|
811
|
+
data = @incoming.pop
|
790
812
|
if Archipelago::Disco::Query === data
|
791
813
|
@local_services.get_services(data).each do |service_id, service_data|
|
792
814
|
if @thrifty_replying
|
data/lib/archipelago/dump.rb
CHANGED
@@ -85,6 +85,7 @@ module Archipelago
|
|
85
85
|
# Any values with a different timestamp will be deleted.
|
86
86
|
#
|
87
87
|
def insert!(key, values, timestamp = "\000\000\000\000")
|
88
|
+
@debug_callable.call("#{self.service_id}.insert!(#{key}, #{values.inspect}, #{timestamp.inspect}) called") if @debug_callable
|
88
89
|
if (duplicates = @db.duplicates(key)).empty?
|
89
90
|
values.each do |value|
|
90
91
|
@db[key] = timestamp + value
|
data/lib/archipelago/hashish.rb
CHANGED
data/lib/archipelago/pirate.rb
CHANGED
@@ -21,7 +21,6 @@ require 'archipelago/treasure'
|
|
21
21
|
require 'archipelago/client'
|
22
22
|
require 'pp'
|
23
23
|
require 'drb'
|
24
|
-
require 'digest/sha1'
|
25
24
|
|
26
25
|
module Archipelago
|
27
26
|
|
@@ -251,7 +250,7 @@ module Archipelago
|
|
251
250
|
def responsible_chest(key)
|
252
251
|
raise NoRemoteDatabaseAvailableException.new(self) if self.chests.empty?
|
253
252
|
|
254
|
-
return get_least_greater_than(:chests,
|
253
|
+
return get_least_greater_than(:chests, key, 1).first
|
255
254
|
end
|
256
255
|
|
257
256
|
#
|
@@ -17,6 +17,8 @@
|
|
17
17
|
|
18
18
|
require 'archipelago/client'
|
19
19
|
require 'archipelago/dump'
|
20
|
+
require 'rubygems'
|
21
|
+
require 'oneliner'
|
20
22
|
require 'monitor'
|
21
23
|
require 'drb'
|
22
24
|
|
@@ -93,7 +95,7 @@ module Archipelago
|
|
93
95
|
|
94
96
|
options.merge!({
|
95
97
|
:service_descriptions => {
|
96
|
-
:sites =>
|
98
|
+
:sites => SITE_DESCRIPTION.merge(options[:site_description] || {})
|
97
99
|
}
|
98
100
|
})
|
99
101
|
setup_client(options)
|
@@ -115,6 +117,7 @@ module Archipelago
|
|
115
117
|
dump_hash = responsible_sites(key)
|
116
118
|
super_string.encode(8)
|
117
119
|
dump_hash.t_each do |dump_id, nr_of_chunks_needed|
|
120
|
+
@debug_callable.call("calling #{dump_id}.insert!(#{key}, ..., #{t})") if @debug_callable
|
118
121
|
self.sites[dump_id][:service].insert!(key,
|
119
122
|
(0...nr_of_chunks_needed).collect do |nr_of_chunks_needed|
|
120
123
|
super_string.encode(chunk_size)
|
@@ -243,7 +246,7 @@ module Archipelago
|
|
243
246
|
end
|
244
247
|
end
|
245
248
|
|
246
|
-
if rval.
|
249
|
+
if rval.done?
|
247
250
|
return [rval.to_s, newest_timestamp]
|
248
251
|
else
|
249
252
|
raise NotEnoughDataException.new(self, key) if newest_timestamp != "\000\000\000\000"
|
data/lib/archipelago/treasure.rb
CHANGED
@@ -57,7 +57,7 @@ module Archipelago
|
|
57
57
|
#
|
58
58
|
class WrongChestException < RuntimeError
|
59
59
|
def initialize(chest_id, predecessor_id, key)
|
60
|
-
super("#{key.inspect} is not between #{predecessor_id} and #{chest_id}, and should not be here")
|
60
|
+
super("#{key.inspect} is not between my predecessor (#{predecessor_id}) and me (#{chest_id}), and should not be here")
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
@@ -118,6 +118,17 @@ module Archipelago
|
|
118
118
|
# method call itself within the home Chest of the proxied object.
|
119
119
|
#
|
120
120
|
class Dubloon
|
121
|
+
@@debug_callable = nil
|
122
|
+
def self.debug_callable=(c)
|
123
|
+
@@debug_callable = c
|
124
|
+
end
|
125
|
+
#
|
126
|
+
# Will return whether +o+ is an instance of Dubloon or one
|
127
|
+
# of its subclasses.
|
128
|
+
#
|
129
|
+
def self.dubloon?(o)
|
130
|
+
return o.respond_to?(:dubloon?) && o.dubloon?
|
131
|
+
end
|
121
132
|
#
|
122
133
|
# Remove all methods so that we look like our target.
|
123
134
|
#
|
@@ -138,12 +149,18 @@ module Archipelago
|
|
138
149
|
self.==(o)
|
139
150
|
end
|
140
151
|
#
|
141
|
-
#
|
152
|
+
# Will return that this is a Dubloon.
|
153
|
+
#
|
154
|
+
def dubloon?
|
155
|
+
true
|
156
|
+
end
|
157
|
+
#
|
158
|
+
# If +o+ is a Dubloon, will return true if it has the same Dubloon#object_id.
|
142
159
|
#
|
143
160
|
# Otherwise will defer to Dubloon#method_missing.
|
144
161
|
#
|
145
162
|
def ==(o)
|
146
|
-
if Dubloon
|
163
|
+
if Dubloon.dubloon?(o)
|
147
164
|
return true if self.object_id == o.object_id
|
148
165
|
end
|
149
166
|
return self.method_missing(:==, o)
|
@@ -202,7 +219,7 @@ module Archipelago
|
|
202
219
|
# @chest_id, @key and possibly @transaction.
|
203
220
|
#
|
204
221
|
def object_id
|
205
|
-
id = "
|
222
|
+
id = "Archipelago::Treasure::Dubloon:#{@key}@#{@chest_id}"
|
206
223
|
id << ":#{@transaction.transaction_id}" if @transaction
|
207
224
|
return id
|
208
225
|
end
|
@@ -222,6 +239,7 @@ module Archipelago
|
|
222
239
|
begin
|
223
240
|
return @chest.call_instance_method(@key, meth, @transaction, *args, &block)
|
224
241
|
rescue WrongChestException => e
|
242
|
+
@@debug_callable.call("#{self.object_id} got #{e} when trying to call #{meth}.#{args}") if @@debug_callable
|
225
243
|
#
|
226
244
|
# We just have to find the new chest we belong at now...
|
227
245
|
#
|
@@ -237,6 +255,7 @@ module Archipelago
|
|
237
255
|
|
238
256
|
retry
|
239
257
|
rescue DRb::DRbConnError => e
|
258
|
+
@@debug_callable.call("#{self.object_id} got #{e} when trying to call #{meth}.#{args}") if @@debug_callable
|
240
259
|
#
|
241
260
|
# Here is some fancy rescuing being done.
|
242
261
|
#
|
@@ -289,6 +308,8 @@ module Archipelago
|
|
289
308
|
#
|
290
309
|
include Archipelago::Disco::Publishable
|
291
310
|
|
311
|
+
attr_reader :captain
|
312
|
+
|
292
313
|
#
|
293
314
|
# Initialize a Chest
|
294
315
|
#
|
@@ -438,7 +459,7 @@ module Archipelago
|
|
438
459
|
instance = ensure_instance_with_transaction(key, transaction)
|
439
460
|
return nil unless instance
|
440
461
|
|
441
|
-
if Dubloon
|
462
|
+
if Dubloon.dubloon?(instance)
|
442
463
|
return instance.join(transaction)
|
443
464
|
else
|
444
465
|
return Dubloon.new(key, self, transaction, self.service_id)
|
@@ -890,7 +911,7 @@ module Archipelago
|
|
890
911
|
#
|
891
912
|
def set(key, value, transaction)
|
892
913
|
join!(transaction)
|
893
|
-
if Dubloon
|
914
|
+
if Dubloon.dubloon?(value)
|
894
915
|
value.assert_transaction(transaction)
|
895
916
|
#
|
896
917
|
# Return the value if the value is in fact a proxy to what we are trying overwrite.
|
@@ -920,7 +941,7 @@ module Archipelago
|
|
920
941
|
@db[key] = value
|
921
942
|
end
|
922
943
|
|
923
|
-
return value if Dubloon
|
944
|
+
return value if Dubloon.dubloon?(value)
|
924
945
|
|
925
946
|
return Dubloon.new(key, self, transaction, service_id)
|
926
947
|
end
|
data/script/pirate.rb
CHANGED
data/tests/current_test.rb
CHANGED
@@ -19,41 +19,6 @@ end
|
|
19
19
|
|
20
20
|
class CurrentTest < Test::Unit::TestCase
|
21
21
|
|
22
|
-
def test_queue
|
23
|
-
q = Archipelago::Current::Queue.new
|
24
|
-
assert(q.empty?)
|
25
|
-
t = true
|
26
|
-
Thread.new do
|
27
|
-
e = q.shift
|
28
|
-
t = false
|
29
|
-
end
|
30
|
-
Thread.pass
|
31
|
-
assert(t)
|
32
|
-
q << "blar"
|
33
|
-
Thread.pass
|
34
|
-
sleep(0.1)
|
35
|
-
assert(!t)
|
36
|
-
|
37
|
-
q << "bunke"
|
38
|
-
assert(!q.empty?)
|
39
|
-
q.shift
|
40
|
-
assert(q.empty?)
|
41
|
-
|
42
|
-
assert(q.empty?)
|
43
|
-
q << "hehu"
|
44
|
-
assert(!q.empty?)
|
45
|
-
Thread.new do
|
46
|
-
q.empty?(true)
|
47
|
-
t = true
|
48
|
-
end
|
49
|
-
Thread.pass
|
50
|
-
assert(!t)
|
51
|
-
q.shift
|
52
|
-
Thread.pass
|
53
|
-
assert(t)
|
54
|
-
assert(q.empty?)
|
55
|
-
end
|
56
|
-
|
57
22
|
def test_synchronized
|
58
23
|
t = true
|
59
24
|
|
data/tests/disco_benchmark.rb
CHANGED
@@ -9,12 +9,12 @@ class DiscoBenchmark < Test::Unit::TestCase
|
|
9
9
|
x = 0
|
10
10
|
bm("Jockey#publish/lookup", :n => 10) do
|
11
11
|
dj1.publish(Archipelago::Disco::Record.new({:service_id => x.to_s, :validator => Archipelago::Disco::MockValidator.new}))
|
12
|
-
assert(!dj2.lookup(Archipelago::Disco::Query.new({:service_id => x.to_s})).empty?)
|
12
|
+
assert(!dj2.lookup(Archipelago::Disco::Query.new({:service_id => x.to_s}), :timeout => 2).empty?)
|
13
13
|
x += 1
|
14
14
|
end
|
15
15
|
dj1.publish(Archipelago::Disco::Record.new({:service_id => "brappa", :validator => Archipelago::Disco::MockValidator.new}))
|
16
16
|
bm("Jockey#lookup", :n => 10) do
|
17
|
-
assert(!dj2.lookup(Archipelago::Disco::Query.new({:service_id => "brappa"})).empty?)
|
17
|
+
assert(!dj2.lookup(Archipelago::Disco::Query.new({:service_id => "brappa"}), :timeout => 2).empty?)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
data/tests/disco_test.rb
CHANGED
@@ -24,7 +24,7 @@ class DiscoTest < Test::Unit::TestCase
|
|
24
24
|
:validator => DRbObject.new(@v1),
|
25
25
|
:epa => "blar")
|
26
26
|
@d1.publish(@p1)
|
27
|
-
assert(!@d2.lookup(Archipelago::Disco::Query.new(:epa => "blar")).empty?)
|
27
|
+
assert(!@d2.lookup(Archipelago::Disco::Query.new(:epa => "blar"), :timeout => 2).empty?)
|
28
28
|
|
29
29
|
@listener = UDPSocket.new
|
30
30
|
@listener.setsockopt(Socket::IPPROTO_IP,
|
@@ -76,7 +76,7 @@ class DiscoTest < Test::Unit::TestCase
|
|
76
76
|
|
77
77
|
empty = true
|
78
78
|
Thread.new do
|
79
|
-
empty = @d2.lookup(Archipelago::Disco::Query.new(:epa => "blar2")).empty?
|
79
|
+
empty = @d2.lookup(Archipelago::Disco::Query.new(:epa => "blar2"), :timeout => 2).empty?
|
80
80
|
end
|
81
81
|
|
82
82
|
assert(empty)
|
@@ -93,6 +93,39 @@ class DiscoTest < Test::Unit::TestCase
|
|
93
93
|
assert(!found_wrong)
|
94
94
|
end
|
95
95
|
|
96
|
+
def test_unsubscribe
|
97
|
+
@v1.valid = false
|
98
|
+
|
99
|
+
lost_it = false
|
100
|
+
|
101
|
+
@d2.subscribe(:lost, Archipelago::Disco::Query.new(:epa => "blar"), 1) do
|
102
|
+
lost_it = true
|
103
|
+
end
|
104
|
+
@d2.unsubscribe(:lost, Archipelago::Disco::Query.new(:epa => "blar"), 1)
|
105
|
+
|
106
|
+
assert(@d2.lookup(Archipelago::Disco::Query.new(:epa => "blar"), :timeout => 0).validate!.empty?)
|
107
|
+
|
108
|
+
@d2.validate!
|
109
|
+
|
110
|
+
assert(!lost_it)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_subscribe
|
114
|
+
@v1.valid = false
|
115
|
+
|
116
|
+
lost_it = false
|
117
|
+
|
118
|
+
@d2.subscribe(:lost, Archipelago::Disco::Query.new(:epa => "blar"), 1) do
|
119
|
+
lost_it = true
|
120
|
+
end
|
121
|
+
|
122
|
+
assert(@d2.lookup(Archipelago::Disco::Query.new(:epa => "blar"), :timeout => 0).validate!.empty?)
|
123
|
+
|
124
|
+
@d2.validate!
|
125
|
+
|
126
|
+
assert(lost_it)
|
127
|
+
end
|
128
|
+
|
96
129
|
def test_publish_invalidate
|
97
130
|
@v1.valid = false
|
98
131
|
|
@@ -110,7 +143,7 @@ class DiscoTest < Test::Unit::TestCase
|
|
110
143
|
end
|
111
144
|
@d2.unsubscribe(:lost, Archipelago::Disco::Query.new(:epa => "blarx"), 2)
|
112
145
|
|
113
|
-
assert(@d2.lookup(Archipelago::Disco::Query.new(:epa => "blar"), 0).validate!.empty?)
|
146
|
+
assert(@d2.lookup(Archipelago::Disco::Query.new(:epa => "blar"), :timeout => 0).validate!.empty?)
|
114
147
|
|
115
148
|
@d2.validate!
|
116
149
|
|
@@ -147,7 +180,7 @@ class DiscoTest < Test::Unit::TestCase
|
|
147
180
|
assert(@ltq.empty?, "we got messages while we shouldnt: #{@ltq.inspect}")
|
148
181
|
|
149
182
|
c1 = Archipelago::Disco::Jockey.new(:thrifty_publishing => true)
|
150
|
-
assert(!c1.lookup(Archipelago::Disco::Query.new(:glad => "ja")).empty?)
|
183
|
+
assert(!c1.lookup(Archipelago::Disco::Query.new(:glad => "ja"), :timeout => 2).empty?)
|
151
184
|
|
152
185
|
c1.stop!
|
153
186
|
c3.stop!
|
@@ -159,7 +192,7 @@ class DiscoTest < Test::Unit::TestCase
|
|
159
192
|
:service_id => 3444))
|
160
193
|
|
161
194
|
@ltq.clear
|
162
|
-
assert(!@d2.lookup(Archipelago::Disco::Query.new(:gladaa => "jaaa")).empty?)
|
195
|
+
assert(!@d2.lookup(Archipelago::Disco::Query.new(:gladaa => "jaaa"), :timeout => 2).empty?)
|
163
196
|
assert(@ltq.any? do |d|
|
164
197
|
o = Marshal.load(d)
|
165
198
|
case o
|
@@ -181,7 +214,7 @@ class DiscoTest < Test::Unit::TestCase
|
|
181
214
|
@ltq.clear
|
182
215
|
|
183
216
|
c1 = Archipelago::Disco::Jockey.new
|
184
|
-
assert(!c1.lookup(Archipelago::Disco::Query.new(:glad2 => "ja2"), 2).empty?)
|
217
|
+
assert(!c1.lookup(Archipelago::Disco::Query.new(:glad2 => "ja2"), :timeout => 2).empty?)
|
185
218
|
|
186
219
|
assert(!@ltq.any? do |data|
|
187
220
|
o = Marshal.load(data)
|
data/tests/pirate_test.rb
CHANGED
@@ -111,6 +111,7 @@ class PirateTest < Test::Unit::TestCase
|
|
111
111
|
|
112
112
|
p2 = Archipelago::Pirate::Captain.new(:chest_description => {:class => "TestChest"},
|
113
113
|
:tranny_description => {:class => "TestManager"},
|
114
|
+
:initial_lookup_timeout => 5,
|
114
115
|
:chest_eval_files => [File.join(File.dirname(__FILE__), 'evaltest')])
|
115
116
|
|
116
117
|
assert_within(10) do
|
@@ -185,13 +186,16 @@ class PirateTest < Test::Unit::TestCase
|
|
185
186
|
end
|
186
187
|
|
187
188
|
def test_wrong_chest_exception
|
188
|
-
|
189
|
-
|
190
|
-
|
189
|
+
k = Digest::SHA1.hexdigest("hehu")
|
190
|
+
resp_ch = @p.responsible_chest(k)[:service]
|
191
|
+
irresp_ch = resp_ch == @c2 ? @c : @c2
|
191
192
|
begin
|
192
193
|
$DO_ASSERT_MINE = true
|
193
194
|
assert_raise(Archipelago::Treasure::WrongChestException) do
|
194
|
-
|
195
|
+
irresp_ch.call_instance_method(k, :bruhuf, nil)
|
196
|
+
end
|
197
|
+
assert_raise(Archipelago::Treasure::UnknownObjectException) do
|
198
|
+
resp_ch.call_instance_method(k, :bruff, nil)
|
195
199
|
end
|
196
200
|
ensure
|
197
201
|
$DO_ASSERT_MINE = false
|
data/tests/sanitation_test.rb
CHANGED
@@ -74,6 +74,8 @@ class SanitationTest < Test::Unit::TestCase
|
|
74
74
|
dumps = []
|
75
75
|
cleaner2 = Archipelago::Sanitation::Officer.new(:minimum_nr_of_chunks => 3,
|
76
76
|
:initial_lookup_timeout => 0)
|
77
|
+
print "(setup cleaner)"
|
78
|
+
STDOUT.flush
|
77
79
|
begin
|
78
80
|
10.times do |n|
|
79
81
|
dumps[n] = Archipelago::Dump::Site.new(:officer => cleaner2,
|
@@ -81,6 +83,8 @@ class SanitationTest < Test::Unit::TestCase
|
|
81
83
|
:persistence_directory => Pathname.new(__FILE__).parent.join("master_test_#{n}.db"))
|
82
84
|
dumps[n].publish!
|
83
85
|
end
|
86
|
+
print "(created dumps)"
|
87
|
+
STDOUT.flush
|
84
88
|
#
|
85
89
|
# Wait until it is alive
|
86
90
|
#
|
@@ -88,6 +92,8 @@ class SanitationTest < Test::Unit::TestCase
|
|
88
92
|
cleaner2.update_services!
|
89
93
|
dumps.collect do |d| d.service_id end.sort == cleaner2.sites.keys.sort
|
90
94
|
end
|
95
|
+
print "(updated services)"
|
96
|
+
STDOUT.flush
|
91
97
|
#
|
92
98
|
# Perform checks on all dumps
|
93
99
|
#
|
@@ -109,6 +115,8 @@ class SanitationTest < Test::Unit::TestCase
|
|
109
115
|
assert_equal(dumps[9].service_id, cleaner2.predecessor(dumps[0].service_id))
|
110
116
|
end
|
111
117
|
end
|
118
|
+
print "(tested relations)"
|
119
|
+
STDOUT.flush
|
112
120
|
#
|
113
121
|
# Check that only fresh data is returned
|
114
122
|
#
|
@@ -121,6 +129,8 @@ class SanitationTest < Test::Unit::TestCase
|
|
121
129
|
assert(cleaner2.responsible_sites("a").include?(dumps[0].service_id))
|
122
130
|
assert(cleaner2.responsible_sites("a").include?(dumps[1].service_id))
|
123
131
|
assert_equal(s2.to_s, cleaner2["a"])
|
132
|
+
print "(tested timestamps)"
|
133
|
+
STDOUT.flush
|
124
134
|
#
|
125
135
|
# Check the utility methods of sanitation
|
126
136
|
#
|
@@ -136,6 +146,8 @@ class SanitationTest < Test::Unit::TestCase
|
|
136
146
|
cleaner2.second_master_to(dumps[4].service_id))
|
137
147
|
assert_equal(dumps[9].service_id,
|
138
148
|
cleaner2.second_master_to(dumps[0].service_id))
|
149
|
+
print "(tested recovery relations)"
|
150
|
+
STDOUT.flush
|
139
151
|
#
|
140
152
|
# Check the recovery methods
|
141
153
|
#
|
@@ -167,41 +179,49 @@ class SanitationTest < Test::Unit::TestCase
|
|
167
179
|
}
|
168
180
|
assert_equal(healthy_chunks,
|
169
181
|
chunks_by_id(cleaner2, "a"))
|
182
|
+
print "(tested basic recovery)"
|
183
|
+
STDOUT.flush
|
170
184
|
dumps[1].close!
|
171
185
|
cleaner2.update_services!(:validate => true)
|
172
186
|
dumps[0].instance_eval do lost_peer({:service_id => dumps[1].service_id}) end
|
173
187
|
dumps[2].instance_eval do lost_peer({:service_id => dumps[1].service_id}) end
|
174
188
|
assert_equal({"6"=>0, "7"=>0, "8"=>0, "9"=>0, "0"=>1, "2"=>1, "3"=>1, "4"=>0, "5"=>0},
|
175
189
|
chunks_by_id(cleaner2, "a"))
|
176
|
-
|
190
|
+
print "(tore down service)"
|
177
191
|
dumps[1] = Archipelago::Dump::Site.new(:officer => cleaner2,
|
178
192
|
:service_description => {:service_id => "1"},
|
179
193
|
:persistence_directory => Pathname.new(__FILE__).parent.join("master_test_1.db"))
|
180
194
|
dumps[1].publish!
|
181
195
|
begin
|
182
196
|
assert_within(20) do
|
183
|
-
cleaner2.update_services!
|
197
|
+
cleaner2.update_services!(:validate => true)
|
184
198
|
["0","1","2","3","4","5","6","7","8","9"].sort == cleaner2.sites.keys.sort
|
185
199
|
end
|
186
200
|
rescue Test::Unit::AssertionFailedError => e
|
187
201
|
pp chunks_by_id(cleaner2, "a")
|
188
202
|
raise e
|
189
203
|
end
|
204
|
+
print "(restarted service)"
|
205
|
+
STDOUT.flush
|
190
206
|
assert_equal({"0"=>1, "1"=>1, "2"=>1},
|
191
207
|
cleaner2.responsible_sites("a"))
|
208
|
+
|
192
209
|
dumps[3].instance_eval do @edge_check_thread.wakeup end
|
193
|
-
|
210
|
+
|
194
211
|
begin
|
195
212
|
assert_within(20) do
|
213
|
+
cleaner2.update_services!(:validate => true)
|
196
214
|
chunks_by_id(cleaner2, "a") == healthy_chunks
|
197
215
|
end
|
198
216
|
rescue Test::Unit::AssertionFailedError => e
|
199
217
|
pp chunks_by_id(cleaner2, "a")
|
200
218
|
raise e
|
201
219
|
end
|
220
|
+
print "(asserted auto recovery)"
|
221
|
+
STDOUT.flush
|
202
222
|
ensure
|
203
223
|
dumps.extend(Archipelago::Current::ThreadedCollection)
|
204
|
-
dumps.
|
224
|
+
dumps.each do |dump|
|
205
225
|
dump.close!
|
206
226
|
dump.instance_eval do @persistence_provider.unlink! end
|
207
227
|
end
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.
|
2
|
+
rubygems_version: 0.9.0
|
3
3
|
specification_version: 1
|
4
4
|
name: archipelago
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.3.0
|
7
|
+
date: 2007-06-07 00:00:00 +02:00
|
8
8
|
summary: A set of tools for distributed computing in ruby.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -29,46 +29,46 @@ post_install_message:
|
|
29
29
|
authors:
|
30
30
|
- Martin Kihlgren
|
31
31
|
files:
|
32
|
-
- lib/archipelago/
|
33
|
-
- lib/archipelago/current.rb
|
34
|
-
- lib/archipelago/disco.rb
|
35
|
-
- lib/archipelago/dump.rb
|
32
|
+
- lib/archipelago/tranny.rb
|
36
33
|
- lib/archipelago/hashish.rb
|
34
|
+
- lib/archipelago/dump.rb
|
35
|
+
- lib/archipelago/current.rb
|
36
|
+
- lib/archipelago/treasure.rb
|
37
|
+
- lib/archipelago/client.rb
|
37
38
|
- lib/archipelago/pirate.rb
|
39
|
+
- lib/archipelago/disco.rb
|
38
40
|
- lib/archipelago/sanitation.rb
|
39
|
-
- lib/archipelago/tranny.rb
|
40
|
-
- lib/archipelago/treasure.rb
|
41
41
|
- lib/archipelago.rb
|
42
|
-
- tests/
|
43
|
-
- tests/
|
44
|
-
- tests/disco_benchmark.rb
|
45
|
-
- tests/disco_test.rb
|
46
|
-
- tests/dump_test.rb
|
42
|
+
- tests/test_helper.rb
|
43
|
+
- tests/treasure_benchmark.rb
|
47
44
|
- tests/evaltest
|
48
45
|
- tests/evaltestmore
|
49
|
-
- tests/
|
46
|
+
- tests/treasure_test.rb
|
47
|
+
- tests/tranny_test.rb
|
48
|
+
- tests/current_benchmark.rb
|
50
49
|
- tests/sanitation_benchmark.rb
|
50
|
+
- tests/dump_test.rb
|
51
51
|
- tests/sanitation_test.rb
|
52
|
-
- tests/
|
53
|
-
- tests/
|
54
|
-
- tests/
|
55
|
-
- tests/
|
56
|
-
- script/console.rb
|
57
|
-
- script/officer.rb
|
52
|
+
- tests/current_test.rb
|
53
|
+
- tests/pirate_test.rb
|
54
|
+
- tests/disco_test.rb
|
55
|
+
- tests/disco_benchmark.rb
|
58
56
|
- script/overloads.rb
|
59
|
-
- script/pirate.rb
|
60
57
|
- script/services.rb
|
58
|
+
- script/officer.rb
|
59
|
+
- script/console.rb
|
60
|
+
- script/pirate.rb
|
61
61
|
- GPL-2
|
62
62
|
- TODO
|
63
63
|
- README
|
64
64
|
test_files:
|
65
|
-
- tests/
|
66
|
-
- tests/
|
65
|
+
- tests/treasure_test.rb
|
66
|
+
- tests/tranny_test.rb
|
67
67
|
- tests/dump_test.rb
|
68
|
-
- tests/pirate_test.rb
|
69
68
|
- tests/sanitation_test.rb
|
70
|
-
- tests/
|
71
|
-
- tests/
|
69
|
+
- tests/current_test.rb
|
70
|
+
- tests/pirate_test.rb
|
71
|
+
- tests/disco_test.rb
|
72
72
|
- tests/test_helper.rb
|
73
73
|
rdoc_options:
|
74
74
|
- --line-numbers
|
@@ -89,7 +89,16 @@ dependencies:
|
|
89
89
|
requirements:
|
90
90
|
- - ">="
|
91
91
|
- !ruby/object:Gem::Version
|
92
|
-
version: 0.
|
92
|
+
version: 0.3.0
|
93
|
+
version:
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: fastthread
|
96
|
+
version_requirement:
|
97
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.0.0
|
93
102
|
version:
|
94
103
|
- !ruby/object:Gem::Dependency
|
95
104
|
name: archipelago_rbtree
|
@@ -98,5 +107,5 @@ dependencies:
|
|
98
107
|
requirements:
|
99
108
|
- - ">="
|
100
109
|
- !ruby/object:Gem::Version
|
101
|
-
version: 0.
|
110
|
+
version: 0.3.0
|
102
111
|
version:
|