archipelago 0.2.7 → 0.3.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.
@@ -15,4 +15,6 @@
15
15
  # along with this program; if not, write to the Free Software
16
16
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
 
18
+ require 'rubygems'
19
+ require 'fastthread'
18
20
  $: << File.dirname(File.expand_path(__FILE__))
@@ -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 = 5
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.start do
223
+ @service_update_thread = Thread.new do
218
224
  standoff = @initial_service_update_interval
219
225
  loop do
220
226
  begin
@@ -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
  #
@@ -46,7 +46,7 @@ module Archipelago
46
46
  #
47
47
  # Default lookup timeout.
48
48
  #
49
- LOOKUP_TIMEOUT = 10
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.t_each do |service_id, service_data|
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 = Archipelago::Current::Queue.new
490
- @outgoing = Archipelago::Current::Queue.new
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
- @outgoing.empty?(true)
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 with a +timeout+.
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, timeout = @lookup_timeout)
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
- @new_service_semaphore.wait(standoff)
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.shift
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
@@ -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
@@ -17,6 +17,7 @@
17
17
 
18
18
  require 'archipelago/current'
19
19
  require 'bdb'
20
+ require 'rubygems'
20
21
  require 'archipelago_rbtree'
21
22
 
22
23
  module Archipelago
@@ -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, Digest::SHA1.hexdigest(Marshal.dump(key)), 1).first
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 => Archipelago::Disco::Query.new(SITE_DESCRIPTION.merge(options[:site_description] || {}))
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.decode_done?
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"
@@ -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
- # If o is a Dubloon, will return true if it has the same Dubloon#object_id.
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 === o
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 = "#{@chest_id}:#{@key}"
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 === instance
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 === value
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 === value
944
+ return value if Dubloon.dubloon?(value)
924
945
 
925
946
  return Dubloon.new(key, self, transaction, service_id)
926
947
  end
@@ -8,4 +8,4 @@ rescue DRb::DRbServerNotFound
8
8
  DRb.start_service(ENV["DRBURI"])
9
9
  end
10
10
  @p = Archipelago::Pirate::Captain.new
11
- @p.evaluate!(File.join(File.dirname(__FILE__), 'overloads.rb'))
11
+ @p.evaluate!(File.join(File.dirname(__FILE__), 'overloads.rb')) unless @p.chests.empty?
@@ -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
 
@@ -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
 
@@ -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)
@@ -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
- chests = [@c, @c2].sort do |a,b|
189
- a.service_id <=> b.service_id
190
- end
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
- chests.last.call_instance_method(chests.last.service_id.next, :bruhuf, nil)
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
@@ -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
- cleaner2.update_services!(:validate => true)
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.t_each do |dump|
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
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.2.7
7
- date: 2007-05-14 00:00:00 +02:00
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/client.rb
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/current_benchmark.rb
43
- - tests/current_test.rb
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/pirate_test.rb
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/test_helper.rb
53
- - tests/tranny_test.rb
54
- - tests/treasure_benchmark.rb
55
- - tests/treasure_test.rb
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/current_test.rb
66
- - tests/disco_test.rb
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/tranny_test.rb
71
- - tests/treasure_test.rb
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.2.7
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.2.7
110
+ version: 0.3.0
102
111
  version: