archipelago 0.2.5 → 0.2.6
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 +1 -1
- data/TODO +8 -17
- data/lib/archipelago.rb +0 -12
- data/lib/archipelago/client.rb +154 -17
- data/lib/archipelago/current.rb +1 -1
- data/lib/archipelago/disco.rb +269 -74
- data/lib/archipelago/dump.rb +279 -0
- data/lib/archipelago/hashish.rb +264 -108
- data/lib/archipelago/pirate.rb +52 -43
- data/lib/archipelago/sanitation.rb +268 -0
- data/lib/archipelago/tranny.rb +2 -4
- data/lib/archipelago/treasure.rb +173 -27
- data/script/{console → console.rb} +1 -1
- data/script/officer.rb +10 -0
- data/script/pirate.rb +5 -1
- data/script/services.rb +12 -5
- data/tests/disco_benchmark.rb +2 -2
- data/tests/disco_test.rb +39 -7
- data/tests/dump_test.rb +71 -0
- data/tests/pirate_test.rb +74 -21
- data/tests/sanitation_benchmark.rb +50 -0
- data/tests/sanitation_test.rb +219 -0
- data/tests/test_helper.rb +15 -3
- data/tests/tranny_test.rb +0 -2
- data/tests/treasure_benchmark.rb +6 -3
- data/tests/treasure_test.rb +43 -7
- metadata +13 -7
- data/lib/archipelago/cove.rb +0 -68
- data/lib/archipelago/exxon.rb +0 -138
- data/lib/archipelago/oneline.rb +0 -641
data/tests/dump_test.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
3
|
+
|
4
|
+
class DumpTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@c = Archipelago::Sanitation::Officer.new(:initial_lookup_timeout => 0)
|
8
|
+
@d = Archipelago::Dump::Site.new(:officer => @c,
|
9
|
+
:persistence_directory => Pathname.new(__FILE__).parent.join("site.db"))
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
@d.instance_eval do @persistence_provider.unlink! end
|
14
|
+
@c.stop!
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_insert_fetch
|
18
|
+
@d.insert!("key", ["value", "value1"])
|
19
|
+
|
20
|
+
assert_equal(["value", "value1"].sort,
|
21
|
+
@d.fetch("key").collect do |e| e.last end.sort)
|
22
|
+
|
23
|
+
@d.insert!("key2", ["value2"])
|
24
|
+
@d.insert!("key2", ["value3"])
|
25
|
+
assert_equal(["value2"],
|
26
|
+
@d.fetch("key2").collect do |e| e.last end.sort)
|
27
|
+
|
28
|
+
@d.insert!("key2", ["value3"], "hehu")
|
29
|
+
assert_equal(["value3"],
|
30
|
+
@d.fetch("key2").collect do |e| e.last end.sort)
|
31
|
+
|
32
|
+
@d.insert!("key", ["value2", "value3"], "apap")
|
33
|
+
assert_equal(["value2", "value3"].sort,
|
34
|
+
@d.fetch("key").collect do |e| e.last end.sort)
|
35
|
+
|
36
|
+
@d.delete!("key")
|
37
|
+
@d.delete!("key2")
|
38
|
+
assert_equal([],
|
39
|
+
@d.fetch("key").collect do |e| e.last end)
|
40
|
+
assert_equal([],
|
41
|
+
@d.fetch("key2").collect do |e| e.last end)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_too_few
|
45
|
+
@d.insert!("a", ["b","c"])
|
46
|
+
assert_equal(["b","c"].sort,
|
47
|
+
@d.fetch("a").collect do |e| e.last end.sort)
|
48
|
+
@d.insert!("a", ["d","c","b"])
|
49
|
+
assert_equal(["b","c","d"].sort,
|
50
|
+
@d.fetch("a").collect do |e| e.last end.sort)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_too_many
|
54
|
+
@d.insert!("a", ["b","c"])
|
55
|
+
assert_equal(["b","c"].sort,
|
56
|
+
@d.fetch("a").collect do |e| e.last end.sort)
|
57
|
+
@d.insert!("a", ["d"])
|
58
|
+
assert_equal(["d"],
|
59
|
+
@d.fetch("a").collect do |e| e.last end)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_wrong_timestamp
|
63
|
+
@d.insert!("a", ["b","c"], "epap")
|
64
|
+
assert_equal(["b","c"].sort,
|
65
|
+
@d.fetch("a").collect do |e| e.last end.sort)
|
66
|
+
@d.insert!("a", ["x", "y"], "epao")
|
67
|
+
assert_equal(["x","y"].sort,
|
68
|
+
@d.fetch("a").collect do |e| e.last end.sort)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
data/tests/pirate_test.rb
CHANGED
@@ -4,33 +4,72 @@ require File.join(File.dirname(__FILE__), 'test_helper')
|
|
4
4
|
class PirateTest < Test::Unit::TestCase
|
5
5
|
|
6
6
|
def setup
|
7
|
-
|
7
|
+
@j = Archipelago::Disco::Jockey.new
|
8
8
|
@p = Archipelago::Pirate::Captain.new(:chest_description => {:class => "TestChest"},
|
9
|
-
:tranny_description => {:class => "TestManager"}
|
10
|
-
|
11
|
-
|
12
|
-
@
|
13
|
-
|
14
|
-
@
|
9
|
+
:tranny_description => {:class => "TestManager"},
|
10
|
+
:jockey => @j,
|
11
|
+
:initial_lookup_timeout => 0)
|
12
|
+
@c = TestChest.new(:captain => @p,
|
13
|
+
:persistence_directory => Pathname.new(__FILE__).parent.join("chest.db"))
|
14
|
+
@c.publish!(:jockey => @j)
|
15
|
+
assert(@j.instance_eval do
|
16
|
+
@service_change_subscribers_by_event_type
|
17
|
+
end[:lost].include?([@p.instance_eval do
|
18
|
+
@service_descriptions
|
19
|
+
end[:chests], @c.service_id]))
|
20
|
+
assert(@j.instance_eval do
|
21
|
+
@service_change_subscribers_by_event_type
|
22
|
+
end[:found].include?([@p.instance_eval do
|
23
|
+
@service_descriptions
|
24
|
+
end[:chests], @c.service_id]))
|
25
|
+
assert_within(10) do
|
26
|
+
@p.update_services!
|
27
|
+
@p.chests.keys.include?(@c.service_id)
|
28
|
+
end
|
29
|
+
assert_equal(@c.service_id, @c.instance_eval do @predecessor_id end)
|
30
|
+
|
31
|
+
@c2 = TestChest.new(:captain => @p,
|
32
|
+
:persistence_directory => Pathname.new(__FILE__).parent.join("chest2.db"))
|
33
|
+
@c2.publish!(:jockey => @j)
|
34
|
+
assert_within(10) do
|
35
|
+
@p.update_services!
|
36
|
+
@p.chests.keys.include?(@c2.service_id)
|
37
|
+
end
|
38
|
+
assert_within(10) do
|
39
|
+
@c2.service_id == @c.instance_eval do @predecessor_id end
|
40
|
+
end
|
41
|
+
assert_within(10) do
|
42
|
+
@c.service_id == @c2.instance_eval do @predecessor_id end
|
43
|
+
end
|
44
|
+
|
45
|
+
@tm = TestManager.new(:captain => @p,
|
46
|
+
:persistence_directory => Pathname.new(__FILE__).parent.join("tranny.db"))
|
15
47
|
@tm.publish!
|
16
|
-
@p.update_services!
|
17
48
|
assert_within(10) do
|
49
|
+
@p.update_services!
|
50
|
+
@p.trannies.keys.include?(@tm.service_id)
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
assert_within(10) do
|
55
|
+
@p.update_services!
|
18
56
|
@p.chests.keys.sort == [@c.service_id, @c2.service_id].sort
|
19
57
|
end
|
20
58
|
assert_within(10) do
|
59
|
+
@p.update_services!
|
21
60
|
@p.trannies.keys == [@tm.service_id]
|
22
61
|
end
|
23
62
|
end
|
24
63
|
|
25
64
|
def teardown
|
26
|
-
@
|
27
|
-
@c.stop!
|
65
|
+
@c.close!
|
28
66
|
@c.persistence_provider.unlink!
|
29
|
-
@c2.
|
67
|
+
@c2.close!
|
30
68
|
@c2.persistence_provider.unlink!
|
31
|
-
@tm.
|
69
|
+
@tm.close!
|
32
70
|
@tm.persistence_provider.unlink!
|
33
|
-
|
71
|
+
@p.stop!
|
72
|
+
@j.stop!
|
34
73
|
end
|
35
74
|
|
36
75
|
def test_include
|
@@ -122,18 +161,18 @@ class PirateTest < Test::Unit::TestCase
|
|
122
161
|
end
|
123
162
|
trans = nil
|
124
163
|
assert_raise(Archipelago::Pirate::CommitFailedException) do
|
125
|
-
@p.transaction do |
|
126
|
-
|
127
|
-
|
164
|
+
@p.transaction do |copy|
|
165
|
+
trans = copy.active_transaction
|
166
|
+
copy["hehu"] = "haha"
|
128
167
|
assert(!p2.include?("hehu"))
|
129
168
|
assert(!p2.include?("hehu", nil))
|
130
169
|
assert_equal(nil, p2.active_transaction)
|
131
170
|
trans2 = nil
|
132
|
-
p2.transaction do |
|
133
|
-
|
134
|
-
|
135
|
-
assert_equal("haha",
|
136
|
-
assert_equal("hoj",
|
171
|
+
p2.transaction do |copy2|
|
172
|
+
trans2 = copy2.active_transaction
|
173
|
+
copy2["hehu"] = "hoj"
|
174
|
+
assert_equal("haha", copy["hehu"])
|
175
|
+
assert_equal("hoj", copy["hehu", trans2])
|
137
176
|
end
|
138
177
|
assert_equal(:commited, trans2.state)
|
139
178
|
assert_equal(:active, trans.state)
|
@@ -145,6 +184,20 @@ class PirateTest < Test::Unit::TestCase
|
|
145
184
|
assert_equal("hoj", @p["hehu"])
|
146
185
|
end
|
147
186
|
|
187
|
+
def test_wrong_chest_exception
|
188
|
+
chests = [@c, @c2].sort do |a,b|
|
189
|
+
a.service_id <=> b.service_id
|
190
|
+
end
|
191
|
+
begin
|
192
|
+
$DO_ASSERT_MINE = true
|
193
|
+
assert_raise(Archipelago::Treasure::WrongChestException) do
|
194
|
+
chests.last.call_instance_method(chests.last.service_id.next, :bruhuf, nil)
|
195
|
+
end
|
196
|
+
ensure
|
197
|
+
$DO_ASSERT_MINE = false
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
148
201
|
def test_write_read_transaction
|
149
202
|
$T = true
|
150
203
|
@p["hej"] = "haha"
|
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
3
|
+
|
4
|
+
class SanitationBenchmark < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@d = Archipelago::Dump::Site.new(:persistence_directory => Pathname.new(__FILE__).parent.join("site.db"))
|
8
|
+
@d.publish!
|
9
|
+
@c = Archipelago::Sanitation::Officer.new
|
10
|
+
assert_within(10) do
|
11
|
+
@c.update_services!
|
12
|
+
@c.sites.keys == [@d.service_id]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def teardown
|
17
|
+
@d.close!
|
18
|
+
@d.instance_eval do @persistence_provider.unlink! end
|
19
|
+
@c.stop!
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_set_get
|
23
|
+
do_set_get(8)
|
24
|
+
do_set_get(128)
|
25
|
+
do_set_get(512)
|
26
|
+
do_set_get(1024)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def do_set_get(size)
|
32
|
+
k = "apa"
|
33
|
+
v = " " * size
|
34
|
+
bm("Sanitation#[]= (#{size})", :n => 100) do
|
35
|
+
@c[k] = v
|
36
|
+
k = k.next
|
37
|
+
end
|
38
|
+
k = "apa"
|
39
|
+
bm("Sanitation#[] (#{size})", :n => 100) do
|
40
|
+
t = @c[k]
|
41
|
+
k = k.next
|
42
|
+
end
|
43
|
+
k = "apa"
|
44
|
+
bm("Sanitation#delete", :n => 100) do
|
45
|
+
t = @c.delete!(k)
|
46
|
+
k = k.next
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,219 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
3
|
+
|
4
|
+
class SanitationTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@c = Archipelago::Sanitation::Officer.new(:initial_lookup_timeout => 0)
|
8
|
+
@d = Archipelago::Dump::Site.new(:officer => @c,
|
9
|
+
:persistence_directory => Pathname.new(__FILE__).parent.join("site.db"))
|
10
|
+
@d.publish!
|
11
|
+
begin
|
12
|
+
assert_within(10) do
|
13
|
+
@c.update_services!
|
14
|
+
@c.sites.keys == [@d.service_id]
|
15
|
+
end
|
16
|
+
rescue Test::Unit::AssertionFailedError => e
|
17
|
+
puts "#{@c.sites.keys.inspect} != #{[@d.service_id].inspect}"
|
18
|
+
raise e
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def teardown
|
23
|
+
@d.close!
|
24
|
+
@d.instance_eval do @persistence_provider.unlink! end
|
25
|
+
@c.stop!
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_sanitation_backed_chest
|
29
|
+
chest = Archipelago::Treasure::Chest.new(:persistence_directory => Pathname.new(__FILE__).parent.join("site_chest.db"),
|
30
|
+
:officer => @c)
|
31
|
+
chest.publish!
|
32
|
+
begin
|
33
|
+
assert_equal(nil, chest["klibb"])
|
34
|
+
assert_equal("kladd", chest["klibb"] = "kladd")
|
35
|
+
assert_equal("kladd", chest["klibb"])
|
36
|
+
assert_equal("KLADD", chest["klibb"].upcase!)
|
37
|
+
klibb = chest["klibb"]
|
38
|
+
assert_equal("kladd", klibb.downcase)
|
39
|
+
assert_equal("kladd", klibb.downcase!)
|
40
|
+
assert_equal("KLADD", klibb.upcase)
|
41
|
+
assert_equal("kladd", klibb)
|
42
|
+
@d.close!
|
43
|
+
@c.update_services!(:validate => true)
|
44
|
+
assert_raise(Archipelago::Sanitation::NoRemoteDatabaseAvailableException) do
|
45
|
+
klibb.upcase!
|
46
|
+
end
|
47
|
+
ensure
|
48
|
+
chest.close!
|
49
|
+
chest.instance_eval do @persistence_provider.unlink! end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_missing_bits
|
54
|
+
s1 = Oneliner::SuperString.new("brappa")
|
55
|
+
@d.insert!("a", [s1.encode(9)], "abab")
|
56
|
+
assert_raise(Archipelago::Sanitation::NotEnoughDataException) do
|
57
|
+
@c["a"]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def test_get_set
|
63
|
+
@c["hej"] = "hoho"
|
64
|
+
assert_equal("hoho", @c["hej"])
|
65
|
+
@c.delete!("hej")
|
66
|
+
assert_equal(@c["hej"], nil)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_multi
|
70
|
+
#
|
71
|
+
# Setup the network
|
72
|
+
#
|
73
|
+
@d.close!
|
74
|
+
dumps = []
|
75
|
+
cleaner2 = Archipelago::Sanitation::Officer.new(:minimum_nr_of_chunks => 3,
|
76
|
+
:initial_lookup_timeout => 0)
|
77
|
+
begin
|
78
|
+
10.times do |n|
|
79
|
+
dumps[n] = Archipelago::Dump::Site.new(:officer => cleaner2,
|
80
|
+
:service_description => {:service_id => n.to_s},
|
81
|
+
:persistence_directory => Pathname.new(__FILE__).parent.join("master_test_#{n}.db"))
|
82
|
+
dumps[n].publish!
|
83
|
+
end
|
84
|
+
#
|
85
|
+
# Wait until it is alive
|
86
|
+
#
|
87
|
+
assert_within(30) do
|
88
|
+
cleaner2.update_services!
|
89
|
+
dumps.collect do |d| d.service_id end.sort == cleaner2.sites.keys.sort
|
90
|
+
end
|
91
|
+
#
|
92
|
+
# Perform checks on all dumps
|
93
|
+
#
|
94
|
+
10.times do |n|
|
95
|
+
if n < 9
|
96
|
+
assert(dumps[n].instance_eval do right_before?(dumps[n+1].service_id) end,
|
97
|
+
"#{dumps[n].service_id} is supposed to be right_before? #{dumps[n+1].service_id}, but isnt. services are #{cleaner2.sites.keys.inspect}")
|
98
|
+
assert(dumps[n+1].instance_eval do right_after?(dumps[n].service_id) end,
|
99
|
+
"#{dumps[n+1].service_id} is supposed to be right_after? #{dumps[n].service_id}, but isnt. services are #{cleaner2.sites.keys.inspect}")
|
100
|
+
else
|
101
|
+
assert(dumps[n].instance_eval do right_before?(dumps[0].service_id) end,
|
102
|
+
"#{dumps[n].service_id} is supposed to be right_before? #{dumps[0].service_id}, but isnt. services are #{cleaner2.sites.keys.inspect}")
|
103
|
+
assert(dumps[0].instance_eval do right_after?(dumps[n].service_id) end,
|
104
|
+
"#{dumps[0].service_id} is supposed to be right_after? #{dumps[n].service_id}, but isnt. services are #{cleaner2.sites.keys.inspect}")
|
105
|
+
end
|
106
|
+
if n > 0
|
107
|
+
assert_equal(dumps[n - 1].service_id, cleaner2.predecessor(dumps[n].service_id))
|
108
|
+
else
|
109
|
+
assert_equal(dumps[9].service_id, cleaner2.predecessor(dumps[0].service_id))
|
110
|
+
end
|
111
|
+
end
|
112
|
+
#
|
113
|
+
# Check that only fresh data is returned
|
114
|
+
#
|
115
|
+
s1 = Oneliner::SuperString.new("brappa")
|
116
|
+
s2 = Oneliner::SuperString.new("brappa2")
|
117
|
+
assert_equal(0, dumps[0].db.size)
|
118
|
+
assert_equal(0, dumps[0].db.size)
|
119
|
+
dumps[0].insert!("a", [s1.encode(20)], "aaaa")
|
120
|
+
dumps[1].insert!("a", [s2.encode(200)], "aaab")
|
121
|
+
assert(cleaner2.responsible_sites("a").include?(dumps[0].service_id))
|
122
|
+
assert(cleaner2.responsible_sites("a").include?(dumps[1].service_id))
|
123
|
+
assert_equal(s2.to_s, cleaner2["a"])
|
124
|
+
#
|
125
|
+
# Check the utility methods of sanitation
|
126
|
+
#
|
127
|
+
assert_equal([dumps[9].service_id, dumps[0].service_id, dumps[1].service_id].sort,
|
128
|
+
cleaner2.instance_eval do
|
129
|
+
get_greatest_less_than(:sites, dumps[2].service_id, 3)
|
130
|
+
end.collect do |d| d[:service_id] end.sort)
|
131
|
+
assert_equal([dumps[8].service_id, dumps[9].service_id, dumps[0].service_id].sort,
|
132
|
+
cleaner2.instance_eval do
|
133
|
+
get_least_greater_than(:sites, dumps[7].service_id, 3)
|
134
|
+
end.collect do |d| d[:service_id] end.sort)
|
135
|
+
assert_equal(dumps[3].service_id,
|
136
|
+
cleaner2.second_master_to(dumps[4].service_id))
|
137
|
+
assert_equal(dumps[9].service_id,
|
138
|
+
cleaner2.second_master_to(dumps[0].service_id))
|
139
|
+
#
|
140
|
+
# Check the recovery methods
|
141
|
+
#
|
142
|
+
assert_equal({
|
143
|
+
"6"=>0,
|
144
|
+
"7"=>0,
|
145
|
+
"8"=>0,
|
146
|
+
"9"=>0,
|
147
|
+
"0"=>1,
|
148
|
+
"1"=>1,
|
149
|
+
"2"=>0,
|
150
|
+
"3"=>0,
|
151
|
+
"4"=>0,
|
152
|
+
"5"=>0
|
153
|
+
},
|
154
|
+
chunks_by_id(cleaner2, "a"))
|
155
|
+
cleaner2.redistribute("a")
|
156
|
+
healthy_chunks = {
|
157
|
+
"6"=>0,
|
158
|
+
"7"=>0,
|
159
|
+
"8"=>0,
|
160
|
+
"9"=>0,
|
161
|
+
"0"=>1,
|
162
|
+
"1"=>1,
|
163
|
+
"2"=>1,
|
164
|
+
"3"=>0,
|
165
|
+
"4"=>0,
|
166
|
+
"5"=>0
|
167
|
+
}
|
168
|
+
assert_equal(healthy_chunks,
|
169
|
+
chunks_by_id(cleaner2, "a"))
|
170
|
+
dumps[1].close!
|
171
|
+
cleaner2.update_services!(:validate => true)
|
172
|
+
dumps[0].instance_eval do lost_peer({:service_id => dumps[1].service_id}) end
|
173
|
+
dumps[2].instance_eval do lost_peer({:service_id => dumps[1].service_id}) end
|
174
|
+
assert_equal({"6"=>0, "7"=>0, "8"=>0, "9"=>0, "0"=>1, "2"=>1, "3"=>1, "4"=>0, "5"=>0},
|
175
|
+
chunks_by_id(cleaner2, "a"))
|
176
|
+
|
177
|
+
dumps[1] = Archipelago::Dump::Site.new(:officer => cleaner2,
|
178
|
+
:service_description => {:service_id => "1"},
|
179
|
+
:persistence_directory => Pathname.new(__FILE__).parent.join("master_test_1.db"))
|
180
|
+
dumps[1].publish!
|
181
|
+
begin
|
182
|
+
assert_within(20) do
|
183
|
+
cleaner2.update_services!
|
184
|
+
["0","1","2","3","4","5","6","7","8","9"].sort == cleaner2.sites.keys.sort
|
185
|
+
end
|
186
|
+
rescue Test::Unit::AssertionFailedError => e
|
187
|
+
pp chunks_by_id(cleaner2, "a")
|
188
|
+
raise e
|
189
|
+
end
|
190
|
+
assert_equal({"0"=>1, "1"=>1, "2"=>1},
|
191
|
+
cleaner2.responsible_sites("a"))
|
192
|
+
dumps[3].instance_eval do @edge_check_thread.wakeup end
|
193
|
+
cleaner2.update_services!(:validate => true)
|
194
|
+
begin
|
195
|
+
assert_within(20) do
|
196
|
+
chunks_by_id(cleaner2, "a") == healthy_chunks
|
197
|
+
end
|
198
|
+
rescue Test::Unit::AssertionFailedError => e
|
199
|
+
pp chunks_by_id(cleaner2, "a")
|
200
|
+
raise e
|
201
|
+
end
|
202
|
+
ensure
|
203
|
+
dumps.extend(Archipelago::Current::ThreadedCollection)
|
204
|
+
dumps.t_each do |dump|
|
205
|
+
dump.close!
|
206
|
+
dump.instance_eval do @persistence_provider.unlink! end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
private
|
212
|
+
|
213
|
+
def chunks_by_id(officer, key)
|
214
|
+
officer.sites.values.inject({}) do |result, service_desc|
|
215
|
+
result.merge({service_desc[:service_id] => service_desc[:service].fetch(key).size})
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|