rgossip 0.1.1 → 0.1.2
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/lib/rgossip/client.rb +72 -20
- data/lib/rgossip/gossipper.rb +9 -8
- data/lib/rgossip/node.rb +7 -3
- data/lib/rgossip/receiver.rb +14 -5
- data/lib/rgossip.rb +13 -2
- metadata +11 -9
data/README
CHANGED
@@ -18,7 +18,7 @@ gem install rgossip
|
|
18
18
|
require 'rgossip'
|
19
19
|
|
20
20
|
#RGossip.debug = true
|
21
|
-
#RGossip.
|
21
|
+
#RGossip.port = 20870 # default: 10870(udp)
|
22
22
|
|
23
23
|
gossip = RGossip::Client.new ['10.150.174.161', '10.150.185.250', '10.150.174.30']
|
24
24
|
# RGossip::Client#initialize(initial_nodes = [], address = nil, data = nil)
|
data/lib/rgossip/client.rb
CHANGED
@@ -6,52 +6,62 @@ module RGossip
|
|
6
6
|
attr_reader :dead_list
|
7
7
|
attr_reader :my_node
|
8
8
|
|
9
|
-
def initialize(initial_nodes = [], address = nil, data = nil)
|
9
|
+
def initialize(initial_nodes = [], address = nil, data = nil, callback = nil)
|
10
10
|
raise 'too large data' if data && data.length > RGossip.bufsiz
|
11
11
|
|
12
12
|
@address = address || IPSocket.getaddress(Socket.gethostname)
|
13
13
|
|
14
14
|
RGossip.log("Initialize Client: initial_nodes=#{initial_nodes.inspect} address: #{@address} data: #{data.inspect}")
|
15
15
|
|
16
|
+
@callback = callback
|
16
17
|
@node_list = Nodes.new
|
17
18
|
@dead_list = Nodes.new
|
18
|
-
|
19
|
+
|
20
|
+
@my_node = Node.new(@node_list, @dead_list, @address, data, nil, self.method(:perform_callback))
|
19
21
|
@my_node.update_timestamp
|
20
22
|
@node_list << @my_node
|
21
23
|
|
22
24
|
initial_nodes.uniq.each do |i|
|
23
|
-
@node_list << Node.new(@node_list, @dead_list, i, nil)
|
25
|
+
@node_list << Node.new(@node_list, @dead_list, name2addr(i), nil, nil, self.method(:perform_callback))
|
24
26
|
end
|
27
|
+
|
28
|
+
@gossiper = Gossiper.new(@my_node, @node_list)
|
29
|
+
@receiver = Receiver.new(@my_node, @node_list, @dead_list, self.method(:perform_callback))
|
25
30
|
end
|
26
31
|
|
27
32
|
def start
|
28
33
|
return if @running
|
29
|
-
RGossip.log("Start Client: address=#{@address}")
|
30
34
|
|
31
|
-
|
32
|
-
|
35
|
+
begin
|
36
|
+
RGossip.log("Start Client: address=#{@address}")
|
33
37
|
|
34
|
-
|
35
|
-
|
36
|
-
|
38
|
+
@node_list.each do |node|
|
39
|
+
if node.address != @my_node.address
|
40
|
+
node.start_timer
|
41
|
+
end
|
37
42
|
end
|
38
|
-
end
|
39
43
|
|
40
|
-
|
41
|
-
|
42
|
-
|
44
|
+
@gossiper.start
|
45
|
+
@receiver.start
|
46
|
+
ensure
|
47
|
+
@running = true
|
48
|
+
end
|
43
49
|
end
|
44
50
|
|
45
51
|
def stop
|
46
52
|
return unless @running
|
47
|
-
RGossip.log("Stop Client")
|
48
53
|
|
49
|
-
|
50
|
-
|
51
|
-
@running = true
|
54
|
+
begin
|
55
|
+
RGossip.log("Stop Client")
|
52
56
|
|
53
|
-
|
54
|
-
|
57
|
+
@gossiper.stop
|
58
|
+
@receiver.stop
|
59
|
+
|
60
|
+
@gossiper = nil
|
61
|
+
@receiver = nil
|
62
|
+
ensure
|
63
|
+
@running = true
|
64
|
+
end
|
55
65
|
end
|
56
66
|
|
57
67
|
def join
|
@@ -63,16 +73,36 @@ module RGossip
|
|
63
73
|
!!@running
|
64
74
|
end
|
65
75
|
|
76
|
+
def address
|
77
|
+
@my_node.address
|
78
|
+
end
|
79
|
+
|
80
|
+
def data
|
81
|
+
@node_list.synchronize {
|
82
|
+
@my_node.data
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
66
86
|
def data=(v)
|
67
87
|
@node_list.synchronize {
|
68
88
|
@my_node.data = v
|
69
89
|
}
|
70
90
|
end
|
71
91
|
|
92
|
+
def callback=(v)
|
93
|
+
@node_list.synchronize {
|
94
|
+
@dead_list.synchronize {
|
95
|
+
@callback = v
|
96
|
+
}
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
72
100
|
def add_node(address)
|
101
|
+
address = name2addr(address)
|
102
|
+
|
73
103
|
@node_list.synchronize {
|
74
104
|
raise 'node is exist' if @node_list.any? {|i| i.address == address }
|
75
|
-
@node_list << Node.new(@node_list, @dead_list, address, nil)
|
105
|
+
@node_list << Node.new(@node_list, @dead_list, address, nil, nil, self.method(:perform_callback))
|
76
106
|
}
|
77
107
|
end
|
78
108
|
|
@@ -99,5 +129,27 @@ module RGossip
|
|
99
129
|
end
|
100
130
|
}
|
101
131
|
end
|
132
|
+
|
133
|
+
private
|
134
|
+
def name2addr(name)
|
135
|
+
if /\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z/ =~ name
|
136
|
+
name
|
137
|
+
else
|
138
|
+
IPSocket.getaddress(name)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def perform_callback(args)
|
143
|
+
return unless @callback
|
144
|
+
|
145
|
+
case @callback.arity
|
146
|
+
when 0
|
147
|
+
@callback.call
|
148
|
+
when 1
|
149
|
+
@callback.call(args)
|
150
|
+
else
|
151
|
+
@callback.call(*args)
|
152
|
+
end
|
153
|
+
end
|
102
154
|
end # Client
|
103
155
|
end # RGossip
|
data/lib/rgossip/gossipper.rb
CHANGED
@@ -7,18 +7,24 @@ module RGossip
|
|
7
7
|
def initialize(my_node, node_list)
|
8
8
|
@my_node = my_node
|
9
9
|
@node_list = node_list
|
10
|
-
@running = true
|
11
10
|
end
|
12
11
|
|
13
12
|
def start
|
14
13
|
RGossip.log("Start Gossiper: interval=#{@@interval}")
|
14
|
+
@running = true
|
15
15
|
|
16
16
|
@thread = Thread.start {
|
17
17
|
begin
|
18
18
|
sock = UDPSocket.open
|
19
19
|
|
20
20
|
while @running
|
21
|
-
|
21
|
+
begin
|
22
|
+
@node_list.synchronize { gossip(sock) }
|
23
|
+
rescue Exception => e
|
24
|
+
raise e unless RGossip.error_handler
|
25
|
+
RGossip.error_handler.call(e)
|
26
|
+
end
|
27
|
+
|
22
28
|
sleep(@@interval)
|
23
29
|
end
|
24
30
|
ensure
|
@@ -47,12 +53,7 @@ module RGossip
|
|
47
53
|
RGossip.log("Gossip: destination=#{dest.address}")
|
48
54
|
|
49
55
|
@node_list.serialize_to_chunks.each do |chunk|
|
50
|
-
|
51
|
-
sock.send(chunk, 0, dest.address, RGossip.port)
|
52
|
-
rescue Exception => e
|
53
|
-
raise e unless RGossip.error_handler
|
54
|
-
RGossip.error_handler.call(e)
|
55
|
-
end
|
56
|
+
sock.send(chunk, 0, dest.address, RGossip.port)
|
56
57
|
end
|
57
58
|
end
|
58
59
|
end # Gossiper
|
data/lib/rgossip/node.rb
CHANGED
@@ -3,17 +3,19 @@ module RGossip
|
|
3
3
|
attr_reader :address
|
4
4
|
attr_accessor :timestamp
|
5
5
|
attr_accessor :data
|
6
|
+
attr_accessor :callback
|
6
7
|
|
7
8
|
@@lifetime = 10
|
8
9
|
def self.lifetime; @@lifetime; end
|
9
10
|
def self.lifetime=(v); @@lifetime = v; end
|
10
11
|
|
11
|
-
def initialize(node_list, dead_list, address, data, timestamp = nil)
|
12
|
+
def initialize(node_list, dead_list, address, data, timestamp, callback = nil)
|
12
13
|
@node_list = node_list
|
13
14
|
@dead_list = dead_list
|
14
15
|
@address = address
|
15
16
|
@data = data
|
16
17
|
@timestamp = timestamp || ""
|
18
|
+
@callback = callback
|
17
19
|
|
18
20
|
@timer = Timer.new(@@lifetime) do
|
19
21
|
RGossip.log("Timeout Node: address=#{@address}")
|
@@ -27,6 +29,8 @@ module RGossip
|
|
27
29
|
@dead_list.synchronize {
|
28
30
|
@dead_list << self
|
29
31
|
}
|
32
|
+
|
33
|
+
@callback.call([:delete, address, timestamp, data]) if @callback
|
30
34
|
end
|
31
35
|
end
|
32
36
|
|
@@ -40,13 +44,13 @@ module RGossip
|
|
40
44
|
end
|
41
45
|
|
42
46
|
def start_timer
|
43
|
-
RGossip.log("Start Timer: address=#{@address}")
|
47
|
+
RGossip.log("Start Timer: address=#{@address} lifetime=#{@@lifetime}")
|
44
48
|
|
45
49
|
@timer.start
|
46
50
|
end
|
47
51
|
|
48
52
|
def reset_timer
|
49
|
-
RGossip.log("Reset Timer: address=#{@address}")
|
53
|
+
RGossip.log("Reset Timer: address=#{@address} lifetime=#{@@lifetime}")
|
50
54
|
|
51
55
|
@timer.reset
|
52
56
|
end
|
data/lib/rgossip/receiver.rb
CHANGED
@@ -4,15 +4,18 @@ module RGossip
|
|
4
4
|
def self.timeout; @@timeout; end
|
5
5
|
def self.timeout=(v); @@timeout = v; end
|
6
6
|
|
7
|
-
|
7
|
+
attr_accessor :callback
|
8
|
+
|
9
|
+
def initialize(my_node, node_list, dead_list, callback = nil)
|
8
10
|
@my_node = my_node
|
9
11
|
@node_list = node_list
|
10
12
|
@dead_list = dead_list
|
11
|
-
@
|
13
|
+
@callback = callback
|
12
14
|
end
|
13
15
|
|
14
16
|
def start
|
15
17
|
RGossip.log("Start Receiver: port=#{RGossip.port}")
|
18
|
+
@running = true
|
16
19
|
|
17
20
|
@thread = Thread.start {
|
18
21
|
begin
|
@@ -70,25 +73,31 @@ module RGossip
|
|
70
73
|
node.timestamp = timestamp
|
71
74
|
node.data = data
|
72
75
|
node.reset_timer
|
76
|
+
|
77
|
+
@callback.call([:update, address, timestamp, data]) if @callback
|
73
78
|
end
|
74
79
|
elsif (index = @dead_list.synchronize { @dead_list.index {|i| i.address == address } })
|
75
|
-
RGossip.log("Come back Node: address=#{address} timestamp=#{timestamp}")
|
76
|
-
|
77
80
|
@dead_list.synchronize {
|
78
81
|
node = @dead_list[index]
|
79
82
|
|
80
83
|
if timestamp > node.timestamp
|
84
|
+
RGossip.log("Come back Node: address=#{address} timestamp=#{timestamp}")
|
85
|
+
|
81
86
|
@dead_list.delete_at(index)
|
82
87
|
@node_list << node
|
83
88
|
node.start_timer
|
89
|
+
|
90
|
+
@callback.call([:comeback, address, timestamp, data]) if @callback
|
84
91
|
end
|
85
92
|
}
|
86
93
|
else
|
87
94
|
RGossip.log("Add Node: address=#{address} timestamp=#{timestamp}")
|
88
95
|
|
89
|
-
node = Node.new(@node_list, @dead_list, address, data, timestamp)
|
96
|
+
node = Node.new(@node_list, @dead_list, address, data, timestamp, @callback)
|
90
97
|
@node_list << node
|
91
98
|
node.start_timer
|
99
|
+
|
100
|
+
@callback.call([:add, address, timestamp, data]) if @callback
|
92
101
|
end
|
93
102
|
end
|
94
103
|
end
|
data/lib/rgossip.rb
CHANGED
@@ -11,6 +11,8 @@ require 'rgossip/receiver'
|
|
11
11
|
require 'rgossip/timer'
|
12
12
|
|
13
13
|
module RGossip
|
14
|
+
DEFAULT_LOGGER = Logger.new($stderr)
|
15
|
+
|
14
16
|
@@port = 10870
|
15
17
|
def self.port; @@port; end
|
16
18
|
def self.port=(v); @@port = v; end
|
@@ -23,7 +25,16 @@ module RGossip
|
|
23
25
|
def self.allowance; @@allowance; end
|
24
26
|
def self.allowance=(v); @@allowance = v; end
|
25
27
|
|
26
|
-
@@error_handler = lambda
|
28
|
+
@@error_handler = lambda do |e|
|
29
|
+
message = (["#{e.class}: #{e.message}"] + (e.backtrace || [])).join("\n\tfrom ")
|
30
|
+
|
31
|
+
if self.debug_logger
|
32
|
+
self.debug_logger.call(message)
|
33
|
+
else
|
34
|
+
$stderr.puts(message)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
27
38
|
def self.error_handler; @@error_handler; end
|
28
39
|
def self.error_handler=(v); @@error_handler = v; end
|
29
40
|
|
@@ -31,7 +42,7 @@ module RGossip
|
|
31
42
|
def self.debug; @@debug; end
|
32
43
|
def self.debug=(v); @@debug = v; end
|
33
44
|
|
34
|
-
@@debug_logger = lambda {|message|
|
45
|
+
@@debug_logger = lambda {|message| DEFAULT_LOGGER.debug(message) }
|
35
46
|
def self.debug_logger; @@debug_logger; end
|
36
47
|
def self.debug_logger=(v); @@debug_logger = v; end
|
37
48
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rgossip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- winebarrel
|
@@ -15,7 +15,8 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-23 00:00:00 +09:00
|
19
|
+
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: msgpack
|
@@ -41,13 +42,14 @@ extra_rdoc_files: []
|
|
41
42
|
|
42
43
|
files:
|
43
44
|
- README
|
44
|
-
- lib/rgossip/timer.rb
|
45
|
-
- lib/rgossip/gossipper.rb
|
46
45
|
- lib/rgossip/client.rb
|
47
|
-
- lib/rgossip/
|
48
|
-
- lib/rgossip/nodes.rb
|
46
|
+
- lib/rgossip/gossipper.rb
|
49
47
|
- lib/rgossip/node.rb
|
48
|
+
- lib/rgossip/nodes.rb
|
49
|
+
- lib/rgossip/receiver.rb
|
50
|
+
- lib/rgossip/timer.rb
|
50
51
|
- lib/rgossip.rb
|
52
|
+
has_rdoc: true
|
51
53
|
homepage: https://bitbucket.org/winebarrel/rgossip
|
52
54
|
licenses: []
|
53
55
|
|
@@ -77,7 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
79
|
requirements: []
|
78
80
|
|
79
81
|
rubyforge_project:
|
80
|
-
rubygems_version: 1.
|
82
|
+
rubygems_version: 1.4.2
|
81
83
|
signing_key:
|
82
84
|
specification_version: 3
|
83
85
|
summary: Basic implementation of a gossip protocol. This is a porting of Java implementation. see http://code.google.com/p/gossip-protocol-java/
|