archipelago 0.1.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.
@@ -0,0 +1,21 @@
1
+
2
+ require File.join(File.dirname(__FILE__), 'profile_helper')
3
+ require 'treasure'
4
+ require 'drb'
5
+
6
+ DRb.start_service
7
+ @c = TestChest.new
8
+ @tm = TestManager.new
9
+
10
+ tr = @tm.begin
11
+ k = "hej"
12
+ v = "oj"
13
+ @c[k,tr] = v
14
+ v = @c[k,tr]
15
+ 1000.times do |n|
16
+ t = v.upcase
17
+ end
18
+
19
+ @c.persistence_provider.unlink
20
+ File.unlink(@tm.db.filename)
21
+ DRb.stop_service
data/profiles/README ADDED
@@ -0,0 +1,3 @@
1
+ These are just simple scripts to profile certain parts of the system.
2
+
3
+ Use ruby-prof to run them and get good profiling.
@@ -0,0 +1,25 @@
1
+
2
+ home = File.expand_path(File.dirname(__FILE__))
3
+ $: << File.join(home, "..", "lib")
4
+
5
+ require 'pp'
6
+ require 'tranny'
7
+ require 'treasure'
8
+
9
+ class TestManager < Archipelago::Tranny::Manager
10
+ attr_reader :db
11
+ def log_error(e)
12
+ puts e
13
+ pp e.backtrace
14
+ end
15
+ end
16
+
17
+ class TestChest < Archipelago::Treasure::Chest
18
+ attr_reader :persistence_provider
19
+ end
20
+
21
+ class TestTransaction
22
+ def join(o)
23
+ end
24
+ end
25
+
data/scripts/chest.rb ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV.size < 1
4
+ puts "Usage: #{$0} DB-PATH [DRB-URI]"
5
+ exit 1
6
+ end
7
+
8
+ $: << File.join(File.dirname(__FILE__), "..", "lib")
9
+
10
+ require 'treasure'
11
+
12
+ if ARGV.size > 1
13
+ DRb.start_service(ARGV[1])
14
+ else
15
+ DRb.start_service
16
+ end
17
+ c = Archipelago::Treasure::Chest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(ARGV[0])))
18
+ c.publish!
19
+
20
+ DRb.thread.join
data/scripts/console ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ exec 'irb', '-r', File.join(File.dirname(__FILE__), 'pirate.rb'), "-I", 'lib'
data/scripts/pirate.rb ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pirate'
4
+
5
+ DRb.start_service("druby://localhost:#{rand(1000) + 5000}")
6
+ @p = Archipelago::Pirate::Captain.new
data/scripts/tranny.rb ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV.size < 1
4
+ puts "Usage: #{$0} DB-PATH DRB-URI"
5
+ exit 1
6
+ end
7
+
8
+ $: << File.join(File.dirname(__FILE__), "..", "lib")
9
+
10
+ require 'treasure'
11
+
12
+ if ARGV.size > 1
13
+ DRb.start_service(ARGV[1])
14
+ else
15
+ DRb.start_service
16
+ end
17
+ t = Archipelago::Tranny::Manager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(ARGV[0])))
18
+ t.publish!
19
+
20
+ DRb.thread.join
@@ -0,0 +1,28 @@
1
+
2
+ require File.join(File.dirname(__FILE__), 'test_helper')
3
+ require 'current'
4
+
5
+ class CurrentTest < Test::Unit::TestCase
6
+
7
+ def test_synchronized
8
+ t = true
9
+
10
+ a = "hej"
11
+ a.extend(Archipelago::Current::Synchronized)
12
+
13
+ o = "gnu"
14
+ a.synchronize_on(o) do
15
+ Thread.new do
16
+ a.synchronize_on(o) do
17
+ t = false
18
+ end
19
+ end
20
+ Thread.pass
21
+ assert(t)
22
+ end
23
+ assert_within(0.5) do
24
+ !t
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,179 @@
1
+
2
+ require File.join(File.dirname(__FILE__), 'test_helper')
3
+ require 'disco'
4
+ require 'drb'
5
+ require 'socket'
6
+ require 'ipaddr'
7
+ require 'thread'
8
+
9
+ class RemoteValidator
10
+ include DRb::DRbUndumped
11
+ attr_accessor :valid
12
+ def initialize(valid)
13
+ @valid = valid
14
+ end
15
+ def valid?
16
+ @valid
17
+ end
18
+ end
19
+
20
+ class DiscoTest < Test::Unit::TestCase
21
+
22
+ def setup
23
+ DRb.start_service
24
+ @d1 = TestJockey.new(:thrifty_publishing => false,
25
+ :thrifty_replying => false,
26
+ :thrifty_caching => false)
27
+ @d2 = TestJockey.new(:thrifty_publishing => false)
28
+ @v1 = RemoteValidator.new(true)
29
+ @p1 = Archipelago::Disco::Record.new(:service_id => 1,
30
+ :validator => DRbObject.new(@v1),
31
+ :epa => "blar")
32
+ @d1.publish(@p1)
33
+ assert(!@d2.lookup(Archipelago::Disco::Query.new(:epa => "blar")).empty?)
34
+
35
+ @listener = UDPSocket.new
36
+ @listener.setsockopt(Socket::IPPROTO_IP,
37
+ Socket::IP_ADD_MEMBERSHIP,
38
+ IPAddr.new(Archipelago::Disco::ADDRESS).hton + Socket.gethostbyname("0.0.0.0")[3])
39
+
40
+ @listener.setsockopt(Socket::SOL_SOCKET,
41
+ Socket::SO_REUSEADDR,
42
+ true)
43
+ begin
44
+ @listener.setsockopt(Socket::SOL_SOCKET,
45
+ Socket::SO_REUSEPORT,
46
+ true)
47
+ rescue
48
+ # /moo
49
+ end
50
+ @listener.bind('', Archipelago::Disco::PORT)
51
+ @ltq = []
52
+ @lt = Thread.new do
53
+ loop do
54
+ begin
55
+ @ltq << @listener.recv(1024)
56
+ rescue Exception => e
57
+ puts e
58
+ pp e.backtrace
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def teardown
65
+ @d1.stop
66
+ @d2.stop
67
+ DRb.stop_service
68
+ @lt.kill
69
+ @listener.close
70
+ end
71
+
72
+ def test_publish_lookup
73
+ empty = true
74
+ Thread.new do
75
+ empty = @d2.lookup(Archipelago::Disco::Query.new(:epa => "blar2")).empty?
76
+ end
77
+
78
+ assert(empty)
79
+
80
+ @d1.publish(Archipelago::Disco::Record.new(:service_id => 1,
81
+ :validator => Archipelago::Disco::MockValidator.new,
82
+ :epa => "blar2"))
83
+
84
+ assert_within(0.5) do
85
+ !empty
86
+ end
87
+ end
88
+
89
+ def test_publish_invalidate
90
+ @v1.valid = false
91
+ assert(@d2.lookup(Archipelago::Disco::Query.new(:epa => "blar"), 0).empty?)
92
+ end
93
+
94
+ def test_thrifty_publishing
95
+ @ltq.clear
96
+
97
+ @d1.publish(Archipelago::Disco::Record.new(:glada => "jaa", :validator => Archipelago::Disco::MockValidator.new, :service_id => 344))
98
+ sleep 0.1
99
+ assert(@ltq.any? do |d|
100
+ o = Marshal.load(d)
101
+ case o
102
+ when Archipelago::Disco::Record
103
+ o[:glada] == "jaa"
104
+ else
105
+ false
106
+ end
107
+ end)
108
+
109
+ @d1.stop
110
+ @d2.stop
111
+
112
+ @ltq.clear
113
+ c3 = Archipelago::Disco::Jockey.new(:thrifty_publishing => true)
114
+ c3.publish(Archipelago::Disco::Record.new(:glad => "ja", :validator => Archipelago::Disco::MockValidator.new, :service_id => 33))
115
+ sleep 0.1
116
+ assert(@ltq.empty?)
117
+
118
+ c1 = Archipelago::Disco::Jockey.new(:thrifty_publishing => true)
119
+ assert(!c1.lookup(Archipelago::Disco::Query.new(:glad => "ja")).empty?)
120
+
121
+ c1.stop
122
+ c3.stop
123
+ end
124
+
125
+ def test_thrifty_replying
126
+ @d1.publish(Archipelago::Disco::Record.new(:gladaa => "jaaa", :validator => Archipelago::Disco::MockValidator.new, :service_id => 3444))
127
+
128
+ @ltq.clear
129
+ assert(!@d2.lookup(Archipelago::Disco::Query.new(:gladaa => "jaaa")).empty?)
130
+ assert(@ltq.any? do |d|
131
+ o = Marshal.load(d)
132
+ case o
133
+ when Archipelago::Disco::Record
134
+ o[:gladaa] == "jaaa"
135
+ else
136
+ false
137
+ end
138
+ end)
139
+
140
+
141
+ @d1.stop
142
+ @d2.stop
143
+ c3 = Archipelago::Disco::Jockey.new(:thrifty_replying => true, :thrifty_publishing => true)
144
+ c3.publish(Archipelago::Disco::Record.new(:glad2 => "ja2", :validator => Archipelago::Disco::MockValidator.new, :service_id => 34))
145
+
146
+ @ltq.clear
147
+
148
+ c1 = Archipelago::Disco::Jockey.new
149
+ assert(!c1.lookup(Archipelago::Disco::Query.new(:glad2 => "ja2"), 2).empty?)
150
+
151
+ assert(!@ltq.any? do |data|
152
+ o = Marshal.load(data)
153
+ if Archipelago::Disco::Record === o
154
+ o[:glad2] == "ja2"
155
+ else
156
+ false
157
+ end
158
+ end)
159
+
160
+ c1.stop
161
+ c3.stop
162
+ end
163
+
164
+ def test_thrifty_caching
165
+ @d2.publish(Archipelago::Disco::Record.new(:bojkotta => "jag", :validator => Archipelago::Disco::MockValidator.new, :service_id => 411))
166
+ sleep 0.1
167
+ assert(@d1.remote_services.include?(411))
168
+
169
+ c1 = TestJockey.new(:thrifty_caching => true)
170
+ assert(!c1.local_services.include?(41))
171
+ assert(!c1.remote_services.include?(41))
172
+ @d1.publish(Archipelago::Disco::Record.new(:bojkott => "ja", :validator => Archipelago::Disco::MockValidator.new, :service_id => 41))
173
+ sleep 0.1
174
+ assert(!c1.local_services.include?(41))
175
+ assert(!c1.remote_services.include?(41))
176
+
177
+ end
178
+
179
+ end
@@ -0,0 +1,75 @@
1
+
2
+ require File.join(File.dirname(__FILE__), 'test_helper')
3
+ require 'treasure'
4
+ require 'drb'
5
+ require 'tranny'
6
+ require 'hashish'
7
+ require 'pirate'
8
+
9
+ class PirateTest < Test::Unit::TestCase
10
+
11
+ def setup
12
+ DRb.start_service("druby://localhost:#{rand(1000) + 5000}")
13
+ @p = Archipelago::Pirate::Captain.new(:chest_description => {:class => "TestChest"},
14
+ :tranny_description => {:class => "TestManager"})
15
+ @c = TestChest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("chest.db")))
16
+ @c.publish!
17
+ @c2 = TestChest.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("chest2.db")))
18
+ @c2.publish!
19
+ @tm = TestManager.new
20
+ @tm.publish!
21
+ assert_within(10) do
22
+ !@p.chests.empty?
23
+ end
24
+ assert_within(10) do
25
+ !@p.trannies.empty?
26
+ end
27
+ end
28
+
29
+ def teardown
30
+ @c.persistence_provider.unlink
31
+ @c2.persistence_provider.unlink
32
+ @tm.persistence_provider.unlink
33
+ DRb.stop_service
34
+ end
35
+
36
+ def test_write_read
37
+ 0.upto(100) do |n|
38
+ @p["#{n}"] = "#{n}"
39
+ end
40
+ chest_ids = Set.new
41
+ 0.upto(100) do |n|
42
+ chest_ids << @c.service_id if @c["#{n}"]
43
+ chest_ids << @c2.service_id if @c2["#{n}"]
44
+ end
45
+
46
+ assert(chest_ids.include?(@c.service_id), "This may fail due to bad luck, try again")
47
+ assert(chest_ids.include?(@c2.service_id), "This may fail due to bad luck, try again")
48
+
49
+ @p["brupp"] = "jojo"
50
+ assert_equal("jojo", @p["brupp"])
51
+ s1 = @p["brupp"]
52
+ s2 = @p["brupp"]
53
+ assert_equal(s1, s2)
54
+ end
55
+
56
+ def test_write_read_transaction
57
+ $T = true
58
+ @p["hej"] = "haha"
59
+ p2 = @p.begin
60
+ assert_equal(p2["hej"], @p["hej"])
61
+ p2["hej"] = "bums"
62
+ assert(p2["hej"] != @p["hej"])
63
+ p2.commit!
64
+ assert_equal("bums", p2["hej"])
65
+ assert_equal(p2["hej"], @p["hej"])
66
+
67
+ p2 = @p.begin
68
+ p2["hej"] = "glass"
69
+ assert(p2["hej"] != @p["hej"])
70
+ p2.abort!
71
+ assert("bums", @p["hej"])
72
+ $T = false
73
+ end
74
+
75
+ end
@@ -0,0 +1,60 @@
1
+
2
+ home = File.expand_path(File.dirname(__FILE__))
3
+ $: << File.join(home, "..", "lib")
4
+
5
+ require 'pp'
6
+ require 'test/unit'
7
+ require 'tranny'
8
+ require 'treasure'
9
+ require 'benchmark'
10
+
11
+ class TestTransaction
12
+ def join(o)
13
+ end
14
+ def state
15
+ :active
16
+ end
17
+ end
18
+
19
+ class TestManager < Archipelago::Tranny::Manager
20
+ attr_reader :persistence_provider
21
+ def log_error(e)
22
+ puts e
23
+ pp e.backtrace
24
+ end
25
+ end
26
+
27
+ class TestJockey < Archipelago::Disco::Jockey
28
+ attr_reader :remote_services, :local_services
29
+ end
30
+
31
+ class TestChest < Archipelago::Treasure::Chest
32
+ attr_reader :persistence_provider
33
+ end
34
+
35
+ class Test::Unit::TestCase
36
+
37
+ def bm(label, options = {})
38
+ n = options[:n] || 1000
39
+ width = options[:width] || 50
40
+ Benchmark.benchmark(" " * width + Benchmark::Tms::CAPTION, width, Benchmark::Tms::FMTSTR, "ms/call") do |b|
41
+ times = b.report("#{n}x#{label}") do
42
+ n.times do
43
+ yield
44
+ end
45
+ end
46
+ [times * 1000 / n.to_f]
47
+ end
48
+ end
49
+
50
+ def assert_within(timeout, &block)
51
+ t = Time.new
52
+ rval = yield
53
+ while !rval && t > Time.new - timeout
54
+ rval = yield
55
+ sleep(0.05)
56
+ end
57
+ assert(rval)
58
+ end
59
+
60
+ end
@@ -0,0 +1,70 @@
1
+
2
+ require File.join(File.dirname(__FILE__), 'test_helper')
3
+ require 'tranny'
4
+ require 'drb'
5
+
6
+ class TrannyTest < Test::Unit::TestCase
7
+
8
+ def setup
9
+ DRb.start_service
10
+ @tm = TestManager.new(:db_path => Pathname.new(__FILE__).parent.join("tranny.db"))
11
+ end
12
+
13
+ def teardown
14
+ @tm.persistence_provider.unlink
15
+ DRb.stop_service
16
+ end
17
+
18
+ class Participant
19
+ include DRb::DRbUndumped
20
+
21
+ attr_accessor :state
22
+ attr_accessor :mode
23
+
24
+ def assert_equal(a,b)
25
+ raise "#{a} != #{b}" unless a == b
26
+ end
27
+ def initialize(mode)
28
+ @mode = mode
29
+ @state = :none
30
+ end
31
+ def abort!(t)
32
+ @state = :aborted
33
+ end
34
+ def prepare!(t)
35
+ assert_equal(:voting, t.state)
36
+ @mode
37
+ end
38
+ def commit!(t)
39
+ assert_equal(:commited, t.state)
40
+ @state = :commited
41
+ end
42
+ end
43
+
44
+ def test_successful_commit
45
+ p1 = Participant.new(:commit)
46
+ p2 = Participant.new(:commit)
47
+ trans = @tm.begin
48
+ assert_equal(:active, trans.state)
49
+ trans.join(DRbObject.new(p1))
50
+ trans.join(DRbObject.new(p2))
51
+ assert_equal(:commited, trans.commit!)
52
+ assert_equal(:commited, trans.state)
53
+ assert_equal(:commited, p1.state)
54
+ assert_equal(:commited, p2.state)
55
+ end
56
+
57
+ def test_aborted_commit
58
+ p1 = Participant.new(:commit)
59
+ p2 = Participant.new(:abort)
60
+ trans = @tm.begin
61
+ assert_equal(:active, trans.state)
62
+ trans.join(DRbObject.new(p1))
63
+ trans.join(DRbObject.new(p2))
64
+ assert_equal(:aborted, trans.commit!)
65
+ assert_equal(:aborted, trans.state)
66
+ assert_equal(:aborted, p1.state)
67
+ assert_equal(:none, p2.state)
68
+ end
69
+
70
+ end