archipelago 0.2.7 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: