roma 0.8.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/LICENSE.rdoc +675 -0
- data/README.rdoc +0 -0
- data/Rakefile +70 -0
- data/bin/mkrecent +7 -0
- data/bin/mkroute +7 -0
- data/bin/recoverlost +8 -0
- data/bin/recoverlost_alist +8 -0
- data/bin/romad +7 -0
- data/bin/sample_watcher +8 -0
- data/bin/sample_watcher2 +8 -0
- data/bin/simple_bench +8 -0
- data/bin/ssroute +7 -0
- data/bin/tribunus +7 -0
- data/lib/roma/async_process.rb +696 -0
- data/lib/roma/command/bg_command_receiver.rb +188 -0
- data/lib/roma/command/mh_command_receiver.rb +117 -0
- data/lib/roma/command/receiver.rb +287 -0
- data/lib/roma/command/rt_command_receiver.rb +147 -0
- data/lib/roma/command/st_command_receiver.rb +564 -0
- data/lib/roma/command/util_command_receiver.rb +67 -0
- data/lib/roma/command/vn_command_receiver.rb +143 -0
- data/lib/roma/command_plugin.rb +11 -0
- data/lib/roma/config.rb +64 -0
- data/lib/roma/event/con_pool.rb +140 -0
- data/lib/roma/event/handler.rb +159 -0
- data/lib/roma/plugin/plugin_alist.rb +1572 -0
- data/lib/roma/plugin/plugin_debug.rb +19 -0
- data/lib/roma/plugin/plugin_test.rb +14 -0
- data/lib/roma/romad.rb +582 -0
- data/lib/roma/routing/cb_rttable.rb +326 -0
- data/lib/roma/routing/merkle_tree.rb +54 -0
- data/lib/roma/routing/rttable.rb +148 -0
- data/lib/roma/stats.rb +112 -0
- data/lib/roma/storage/basic_storage.rb +510 -0
- data/lib/roma/storage/dbm_storage.rb +80 -0
- data/lib/roma/storage/dummy_storage.rb +44 -0
- data/lib/roma/storage/rh_storage.rb +35 -0
- data/lib/roma/storage/sqlite3_storage.rb +73 -0
- data/lib/roma/storage/tc_storage.rb +133 -0
- data/lib/roma/tools/mkrecent.rb +138 -0
- data/lib/roma/tools/mkroute.rb +52 -0
- data/lib/roma/tools/recoverlost.rb +9 -0
- data/lib/roma/tools/recoverlost_alist.rb +9 -0
- data/lib/roma/tools/recoverlost_lib.rb +217 -0
- data/lib/roma/tools/sample_watcher.rb +38 -0
- data/lib/roma/tools/sample_watcher2.rb +38 -0
- data/lib/roma/tools/simple_bench.rb +57 -0
- data/lib/roma/tools/ssroute.rb +23 -0
- data/lib/roma/tools/tribunus.rb +299 -0
- data/lib/roma/version.rb +4 -0
- data/lib/roma/write_behind.rb +179 -0
- data/test/rcirb.rb +16 -0
- data/test/roma-test-utils.rb +65 -0
- data/test/run-test.rb +16 -0
- data/test/t_cpdata.rb +277 -0
- data/test/t_listplugin.rb +592 -0
- data/test/t_rclient.rb +318 -0
- data/test/t_routing_data.rb +100 -0
- data/test/t_storage.rb +644 -0
- data/test/t_writebehind.rb +200 -0
- metadata +134 -0
@@ -0,0 +1,696 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'thread'
|
3
|
+
require 'digest/sha1'
|
4
|
+
|
5
|
+
module Roma
|
6
|
+
|
7
|
+
class AsyncMessage
|
8
|
+
attr_accessor :event
|
9
|
+
attr_accessor :args
|
10
|
+
attr_accessor :callback
|
11
|
+
|
12
|
+
def initialize(ev,ag=nil,&cb)
|
13
|
+
@event = ev
|
14
|
+
@args = ag
|
15
|
+
@callback = cb
|
16
|
+
@retry_count = 0
|
17
|
+
@retry_max = 10
|
18
|
+
@retry_wait = 0.1
|
19
|
+
end
|
20
|
+
|
21
|
+
def retry?
|
22
|
+
@retry_max > @retry_count
|
23
|
+
end
|
24
|
+
|
25
|
+
def incr_count
|
26
|
+
@retry_count += 1
|
27
|
+
end
|
28
|
+
|
29
|
+
def wait
|
30
|
+
sleep(@retry_wait)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module AsyncProcess
|
35
|
+
|
36
|
+
@@async_queue = Queue.new
|
37
|
+
|
38
|
+
def self.queue
|
39
|
+
@@async_queue
|
40
|
+
end
|
41
|
+
|
42
|
+
def start_async_process
|
43
|
+
@async_thread = Thread.new{
|
44
|
+
async_process_loop
|
45
|
+
}
|
46
|
+
rescue =>e
|
47
|
+
@log.error("#{e}\n#{$@}")
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def stop_async_process
|
53
|
+
count = 0
|
54
|
+
while @@async_queue.empty? == false && count < 100
|
55
|
+
count += 1
|
56
|
+
sleep 0.1
|
57
|
+
end
|
58
|
+
@async_thread.exit
|
59
|
+
end
|
60
|
+
|
61
|
+
def async_process_loop
|
62
|
+
loop {
|
63
|
+
while msg = @@async_queue.pop
|
64
|
+
if send("asyncev_#{msg.event}",msg.args)
|
65
|
+
msg.callback.call(msg,true) if msg.callback
|
66
|
+
else
|
67
|
+
if msg.retry?
|
68
|
+
Thread.new{
|
69
|
+
msg.wait
|
70
|
+
msg.incr_count
|
71
|
+
@@async_queue.push(msg)
|
72
|
+
}
|
73
|
+
else
|
74
|
+
@log.error("async process retry out:#{msg.inspect}")
|
75
|
+
msg.callback.call(msg,false) if msg.callback
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
}
|
80
|
+
rescue =>e
|
81
|
+
@log.error("#{e}\n#{$@}")
|
82
|
+
retry
|
83
|
+
end
|
84
|
+
|
85
|
+
def asyncev_broadcast_cmd(args)
|
86
|
+
@log.debug("asyncev_broadcast_cmd #{args.inspect}")
|
87
|
+
cmd, nids, tout = args
|
88
|
+
Thread::new{
|
89
|
+
async_broadcast_cmd("#{cmd}\r\n", nids, tout)
|
90
|
+
}
|
91
|
+
true
|
92
|
+
end
|
93
|
+
|
94
|
+
def asyncev_start_acquire_vnodes_process(args)
|
95
|
+
@log.debug("asyncev_start_acquire_vnodes_process")
|
96
|
+
if @stats.run_acquire_vnodes
|
97
|
+
@log.error("asyncev_start_acquire_vnodes_process:already in being")
|
98
|
+
return true
|
99
|
+
end
|
100
|
+
@stats.run_acquire_vnodes = true
|
101
|
+
Thread::new{
|
102
|
+
begin
|
103
|
+
acquire_vnodes_process
|
104
|
+
rescue =>e
|
105
|
+
@log.error("asyncev_start_acquire_vnodes_process:#{e.inspect} #{$@}")
|
106
|
+
ensure
|
107
|
+
@stats.run_acquire_vnodes = false
|
108
|
+
@stats.join_ap = nil
|
109
|
+
end
|
110
|
+
}
|
111
|
+
true
|
112
|
+
end
|
113
|
+
|
114
|
+
def asyncev_start_dumpfile_process(args)
|
115
|
+
@log.debug("asyncev_start_dumpfile_process #{args.inspect}")
|
116
|
+
key, path, cmd = args
|
117
|
+
path = Roma::Config::STORAGE_DUMP_PATH + '/' + path
|
118
|
+
Thread.new{
|
119
|
+
begin
|
120
|
+
except_vnh = {}
|
121
|
+
@rttable.each_vnode{|vn,nids|
|
122
|
+
if nids[0]!=@stats.ap_str
|
123
|
+
except_vnh[vn]=vn
|
124
|
+
end
|
125
|
+
}
|
126
|
+
# cmd expect the :dumpfile or :rdumpfile.
|
127
|
+
delete_to_end_of_dump(key) if cmd == :dumpfile
|
128
|
+
sleep 0.1
|
129
|
+
@storages.each_pair{|hname,st|
|
130
|
+
st.dump_file("#{path}/#{@stats.ap_str}/#{hname}",except_vnh)
|
131
|
+
}
|
132
|
+
ret = set_to_end_of_dump(key,@stats.ap_str)
|
133
|
+
if ret==nil || ret!="STORED"
|
134
|
+
@log.error("asyncev_start_dumpfile_process:result of set_to_end_of_dump was #{ret.inspect}")
|
135
|
+
end
|
136
|
+
@log.info("asyncev_start_dumpfile_process has done.")
|
137
|
+
rescue =>e
|
138
|
+
@log.error("#{e}\n#{$@}")
|
139
|
+
end
|
140
|
+
}
|
141
|
+
true
|
142
|
+
end
|
143
|
+
|
144
|
+
def delete_to_end_of_dump(key)
|
145
|
+
con = Roma::Messaging::ConPool.instance.get_connection(@stats.ap_str)
|
146
|
+
con.write("delete #{key}\eroma\r\n")
|
147
|
+
res = con.gets
|
148
|
+
res.chomp! if res
|
149
|
+
Roma::Messaging::ConPool.instance.return_connection(@stats.ap_str,con)
|
150
|
+
res
|
151
|
+
end
|
152
|
+
|
153
|
+
def set_to_end_of_dump(key,nid)
|
154
|
+
count = 0
|
155
|
+
begin
|
156
|
+
sleep 0.1
|
157
|
+
con = Roma::Messaging::ConPool.instance.get_connection(nid)
|
158
|
+
con.write("add #{key}\eroma 0 86400 #{nid.length}\r\n#{nid}\r\n")
|
159
|
+
res = con.gets
|
160
|
+
unless res=="STORED\r\n"
|
161
|
+
con.write("append #{key}\eroma 0 86400 #{nid.length+1}\r\n,#{nid}\r\n")
|
162
|
+
res = con.gets
|
163
|
+
end
|
164
|
+
Roma::Messaging::ConPool.instance.return_connection(nid,con)
|
165
|
+
count += 1
|
166
|
+
end while(res!="STORED\r\n" && count < 5)
|
167
|
+
res.chomp! if res
|
168
|
+
res
|
169
|
+
end
|
170
|
+
|
171
|
+
def asyncev_redundant(args)
|
172
|
+
nid,hname,k,d,clk,expt,v = args
|
173
|
+
@log.debug("asyncev_redundant #{args.inspect}")
|
174
|
+
unless @rttable.nodes.include?(nid)
|
175
|
+
@log.warn("async redundant failed:#{nid} dose not found in routing table.#{k}\e#{hname} #{d} #{clk} #{expt} #{v.length}")
|
176
|
+
return true # no retry
|
177
|
+
end
|
178
|
+
res = async_send_cmd(nid,"rset #{k}\e#{hname} #{d} #{clk} #{expt} #{v.length}\r\n#{v}\r\n",10)
|
179
|
+
unless res
|
180
|
+
@log.warn("async redundant failed:#{k}\e#{hname} #{d} #{clk} #{expt} #{v.length} -> #{nid}")
|
181
|
+
return false # retry
|
182
|
+
end
|
183
|
+
true
|
184
|
+
end
|
185
|
+
|
186
|
+
def asyncev_zredundant(args)
|
187
|
+
nid,hname,k,d,clk,expt,zv = args
|
188
|
+
@log.debug("asyncev_zredundant #{args.inspect}")
|
189
|
+
unless @rttable.nodes.include?(nid)
|
190
|
+
@log.warn("async zredundant failed:#{nid} dose not found in routing table.#{k}\e#{hname} #{d} #{clk} #{expt} #{zv.length}")
|
191
|
+
return true # no retry
|
192
|
+
end
|
193
|
+
res = async_send_cmd(nid,"rzset #{k}\e#{hname} #{d} #{clk} #{expt} #{zv.length}\r\n#{zv}\r\n",10)
|
194
|
+
unless res
|
195
|
+
@log.warn("async zredundant failed:#{k}\e#{hname} #{d} #{clk} #{expt} #{v.length} -> #{nid}")
|
196
|
+
return false # retry
|
197
|
+
end
|
198
|
+
true
|
199
|
+
end
|
200
|
+
|
201
|
+
def asyncev_reqpushv(args)
|
202
|
+
vn, nid, p = args
|
203
|
+
@log.debug("asyncev_reqpushv #{args.inspect}")
|
204
|
+
Thread::new{
|
205
|
+
sync_a_vnode(vn.to_i, nid, p == 'true')
|
206
|
+
}
|
207
|
+
end
|
208
|
+
|
209
|
+
def asyncev_start_recover_process(args)
|
210
|
+
@log.debug("asyncev_start_recover_process #{args.inspect}")
|
211
|
+
@stats.run_recover = true
|
212
|
+
Thread::new{
|
213
|
+
begin
|
214
|
+
if args != nil
|
215
|
+
acquired_recover_process
|
216
|
+
elsif args[0] == '-s'
|
217
|
+
recover_process
|
218
|
+
elsif args[0] == '-r' || args[0] == nil
|
219
|
+
acquired_recover_process
|
220
|
+
else
|
221
|
+
@log.error("asyncev_start_recover_process:argument error #{args.inspect}")
|
222
|
+
end
|
223
|
+
rescue => e
|
224
|
+
@log.error("asyncev_start_recover_process:#{e.inspect} #{$@}")
|
225
|
+
end
|
226
|
+
@stats.run_recover = false
|
227
|
+
}
|
228
|
+
end
|
229
|
+
|
230
|
+
def asyncev_start_release_process(args)
|
231
|
+
@log.debug("asyncev_start_release_process #{args}")
|
232
|
+
@stats.run_release = true
|
233
|
+
Thread::new{
|
234
|
+
begin
|
235
|
+
release_process
|
236
|
+
rescue => e
|
237
|
+
@log.error("asyncev_start_release_process:#{e.inspect} #{$@}")
|
238
|
+
end
|
239
|
+
@stats.run_relase = false
|
240
|
+
}
|
241
|
+
end
|
242
|
+
|
243
|
+
def asyncev_start_sync_process(args)
|
244
|
+
@log.debug("asyncev_start_sync_process")
|
245
|
+
@stats.run_recover = true
|
246
|
+
Thread::new{
|
247
|
+
sync_process(args)
|
248
|
+
@stats.run_recover = false
|
249
|
+
}
|
250
|
+
end
|
251
|
+
|
252
|
+
def sync_process(st)
|
253
|
+
own_nid = @stats.ap_str
|
254
|
+
@do_sync_process = true
|
255
|
+
@rttable.each_vnode{ |vn, nids|
|
256
|
+
break unless @do_sync_process
|
257
|
+
# my process charges of the primary node
|
258
|
+
if nids[0] == own_nid
|
259
|
+
nids[1..-1].each{ |nid|
|
260
|
+
unless sync_a_vnode(vn, nid)
|
261
|
+
@log.warn("sync_process:error at vn=#{vn} nid=#{nid}")
|
262
|
+
end
|
263
|
+
}
|
264
|
+
end
|
265
|
+
}
|
266
|
+
@log.info("Sync process has done.")
|
267
|
+
rescue =>e
|
268
|
+
@log.error("#{e.inspect} #{$@}")
|
269
|
+
ensure
|
270
|
+
@do_sync_process = false
|
271
|
+
Roma::Messaging::ConPool.instance.close_all
|
272
|
+
end
|
273
|
+
|
274
|
+
def acquired_recover_process
|
275
|
+
@log.info("acquired_recover_process:start")
|
276
|
+
exclude_nodes = @rttable.nodes
|
277
|
+
|
278
|
+
if @stats.enabled_repetition_host_in_routing
|
279
|
+
exclude_nodes = [@stats.ap_str]
|
280
|
+
else
|
281
|
+
myhost = @stats.ap_str.split(/[:_]/)[0]
|
282
|
+
exclude_nodes.delete_if{|nid| nid.split(/[:_]/)[0] != myhost }
|
283
|
+
end
|
284
|
+
|
285
|
+
@do_acquired_recover_process = true
|
286
|
+
loop {
|
287
|
+
break unless @do_acquired_recover_process
|
288
|
+
vnodes = @rttable.select_a_short_vnodes(exclude_nodes)
|
289
|
+
@log.info("acquired_recover_process:#{vnodes.length} short vnodes found.")
|
290
|
+
break if vnodes.length == 0
|
291
|
+
vn, nodes = vnodes[rand(vnodes.length)]
|
292
|
+
if nodes.length != 0
|
293
|
+
ret = req_push_a_vnode(vn, nodes[0], rand(@rttable.rn) == 0)
|
294
|
+
if ret == :rejected
|
295
|
+
sleep 1
|
296
|
+
elsif ret == false
|
297
|
+
break
|
298
|
+
end
|
299
|
+
sleep 1
|
300
|
+
end
|
301
|
+
}
|
302
|
+
@log.info("acquired_recover_process has done.")
|
303
|
+
rescue => e
|
304
|
+
@log.error("#{e.inspect} #{$@}")
|
305
|
+
ensure
|
306
|
+
@do_acquired_recover_process = false
|
307
|
+
end
|
308
|
+
|
309
|
+
def acquire_vnodes_process
|
310
|
+
count = 0
|
311
|
+
nv = @rttable.v_idx.length
|
312
|
+
@do_acquire_vnodes_process = true
|
313
|
+
while (@rttable.vnode_balance(@stats.ap_str) == :less && count < nv) do
|
314
|
+
break unless @do_acquire_vnodes_process
|
315
|
+
ret = acquire_vnode
|
316
|
+
if ret == :rejected
|
317
|
+
sleep 5
|
318
|
+
next
|
319
|
+
elsif ret == false
|
320
|
+
break
|
321
|
+
end
|
322
|
+
sleep 1
|
323
|
+
count += 1
|
324
|
+
end
|
325
|
+
@log.info("acquire_vnodes_prosess has done.")
|
326
|
+
rescue => e
|
327
|
+
@log.error("#{e.inspect} #{$@}")
|
328
|
+
ensure
|
329
|
+
@do_acquire_vnodes_process = false
|
330
|
+
end
|
331
|
+
|
332
|
+
def acquire_vnode
|
333
|
+
widthout_nodes = @rttable.nodes
|
334
|
+
|
335
|
+
if @stats.enabled_repetition_host_in_routing
|
336
|
+
widthout_nodes = [@stats.ap_str]
|
337
|
+
else
|
338
|
+
myhost = @stats.ap_str.split(/[:_]/)[0]
|
339
|
+
widthout_nodes.delete_if{|nid| nid.split(/[:_]/)[0] != myhost }
|
340
|
+
end
|
341
|
+
|
342
|
+
vn, nodes = @rttable.sample_vnode(widthout_nodes)
|
343
|
+
unless vn
|
344
|
+
@log.warn("acquire_vnode:sample_vnode dose not found")
|
345
|
+
return false
|
346
|
+
end
|
347
|
+
#
|
348
|
+
# tunning point
|
349
|
+
# sleep 0.1
|
350
|
+
#
|
351
|
+
req_push_a_vnode(vn, nodes[0], rand(@rttable.rn) == 0)
|
352
|
+
end
|
353
|
+
|
354
|
+
def req_push_a_vnode(vn, src_nid, is_primary)
|
355
|
+
con = Roma::Messaging::ConPool.instance.get_connection(src_nid)
|
356
|
+
con.write("reqpushv #{vn} #{@stats.ap_str} #{is_primary}\r\n")
|
357
|
+
res = con.gets # receive 'PUSHED\r\n' | 'REJECTED\r\n'
|
358
|
+
if res == "REJECTED\r\n"
|
359
|
+
@log.warn("req_push_a_vnode:request was rejected from #{src_nid}.")
|
360
|
+
return :rejected
|
361
|
+
end
|
362
|
+
Roma::Messaging::ConPool.instance.return_connection(src_nid,con)
|
363
|
+
# waiting for pushv
|
364
|
+
count = 0
|
365
|
+
while @rttable.search_nodes(vn).include?(@stats.ap_str)==false && count < 300
|
366
|
+
sleep 0.1
|
367
|
+
count += 1
|
368
|
+
end
|
369
|
+
if count >= 300
|
370
|
+
@log.warn("req_push_a_vnode:request has been time-out.vn=#{vn} nid=#{src_nid}")
|
371
|
+
return :timeout
|
372
|
+
end
|
373
|
+
true
|
374
|
+
rescue =>e
|
375
|
+
@log.error("req_push_a_vnode:#{e.inspect} #{$@}")
|
376
|
+
@rttable.proc_failed(src_nid)
|
377
|
+
false
|
378
|
+
end
|
379
|
+
|
380
|
+
def recover_process
|
381
|
+
@log.info("recover_process:start.")
|
382
|
+
nodes = @rttable.nodes
|
383
|
+
|
384
|
+
unless @stats.enabled_repetition_host_in_routing
|
385
|
+
host = @stats.ap_str.split(/[:_]/)[0]
|
386
|
+
nodes.delete_if{|nid| nid.split(/[:_]/)[0] == host }
|
387
|
+
else
|
388
|
+
nodes.delete(@stats.ap_str)
|
389
|
+
end
|
390
|
+
|
391
|
+
if nodes.length == 0
|
392
|
+
@log.error("New redundant node dose not found.")
|
393
|
+
return
|
394
|
+
end
|
395
|
+
|
396
|
+
@do_recover_process = true
|
397
|
+
@rttable.each_vnode{ |vn, nids|
|
398
|
+
break unless @do_recover_process
|
399
|
+
# my process charges of a primary node and it's short of redundant
|
400
|
+
if nids[0] == @stats.ap_str && nids.length < @rttable.rn
|
401
|
+
unless sync_a_vnode(vn, nodes[rand(nodes.length)])
|
402
|
+
@log.warn("recover_process:error at hname=#{hname} vn=#{vn}")
|
403
|
+
end
|
404
|
+
end
|
405
|
+
}
|
406
|
+
@log.info("Recover process has done.")
|
407
|
+
rescue =>e
|
408
|
+
@log.error("#{e}\n#{$@}")
|
409
|
+
ensure
|
410
|
+
@do_recover_process = false
|
411
|
+
Roma::Messaging::ConPool.instance.close_all
|
412
|
+
end
|
413
|
+
|
414
|
+
def release_process
|
415
|
+
@log.info("release_process:start.")
|
416
|
+
nodes = @rttable.nodes
|
417
|
+
|
418
|
+
unless @stats.enabled_repetition_host_in_routing
|
419
|
+
host = @stats.ap_str.split(/[:_]/)[0]
|
420
|
+
nodes.delete_if{|nid| nid.split(/[:_]/)[0] == host }
|
421
|
+
else
|
422
|
+
nodes.delete(@stats.ap_str)
|
423
|
+
end
|
424
|
+
|
425
|
+
if nodes.length < @rttable.rn
|
426
|
+
@log.error("Physcal node dose not found.")
|
427
|
+
return
|
428
|
+
end
|
429
|
+
|
430
|
+
@do_release_process = true
|
431
|
+
@rttable.each_vnode{ |vn, nids|
|
432
|
+
break unless @do_release_process
|
433
|
+
if nids.include?(@stats.ap_str)
|
434
|
+
buf = nodes.clone
|
435
|
+
|
436
|
+
unless @stats.enabled_repetition_host_in_routing
|
437
|
+
hosts = []
|
438
|
+
nids.each{|nid| hosts << nid.split(/[:_]/)[0]}
|
439
|
+
buf.delete_if{|nid| hosts.include?(nid.split(/[:_]/)[0])}
|
440
|
+
else
|
441
|
+
nids.each{|nid| buf.delete(nid) }
|
442
|
+
end
|
443
|
+
|
444
|
+
new_nid = buf[rand(buf.length)]
|
445
|
+
new_nids = nids.map{|n| n == @stats.ap_str ? new_nid : n }
|
446
|
+
unless sync_a_vnode_for_release(vn, new_nid, new_nids)
|
447
|
+
@log.warn("release_process:error at hname=#{hname} vn=#{vn}")
|
448
|
+
end
|
449
|
+
end
|
450
|
+
}
|
451
|
+
@log.info("Release process has done.")
|
452
|
+
rescue =>e
|
453
|
+
@log.error("#{e}\n#{$@}")
|
454
|
+
ensure
|
455
|
+
@do_release_process = false
|
456
|
+
Roma::Messaging::ConPool.instance.close_all
|
457
|
+
end
|
458
|
+
|
459
|
+
def sync_a_vnode_for_release(vn, to_nid, new_nids)
|
460
|
+
if @stats.run_iterate_storage == true
|
461
|
+
@log.warn("sync_a_vnode:already in being.#{vn} #{to_nid}")
|
462
|
+
return false
|
463
|
+
end
|
464
|
+
nids = @rttable.search_nodes(vn)
|
465
|
+
|
466
|
+
if nids.include?(to_nid)==false || (is_primary && nids[0]!=to_nid)
|
467
|
+
@log.debug("sync_a_vnode_for_release:#{vn} #{to_nid}")
|
468
|
+
# change routing data at the vnode and synchronize a data
|
469
|
+
nids << to_nid
|
470
|
+
return false unless @rttable.transaction(vn, nids)
|
471
|
+
|
472
|
+
# synchronize a data
|
473
|
+
@storages.each_key{ |hname|
|
474
|
+
res = push_a_vnode_stream(hname, vn, to_nid)
|
475
|
+
|
476
|
+
if res != "STORED"
|
477
|
+
@rttable.rollback(vn)
|
478
|
+
@log.error("push_a_vnode was failed:hname=#{hname} vn=#{vn}:#{res}")
|
479
|
+
return false
|
480
|
+
end
|
481
|
+
}
|
482
|
+
|
483
|
+
if (clk = @rttable.commit(vn)) == false
|
484
|
+
@rttable.rollback(vn)
|
485
|
+
@log.error("sync_a_vnode:routing table commit failed")
|
486
|
+
return false
|
487
|
+
end
|
488
|
+
|
489
|
+
clk = @rttable.set_route(vn, clk, new_nids)
|
490
|
+
if clk.is_a?(Integer) == false
|
491
|
+
clk,new_nids = @rttable.search_nodes_with_clk(vn)
|
492
|
+
end
|
493
|
+
|
494
|
+
cmd = "setroute #{vn} #{clk - 1}"
|
495
|
+
new_nids.each{ |nn| cmd << " #{nn}"}
|
496
|
+
res = async_broadcast_cmd("#{cmd}\r\n")
|
497
|
+
@log.debug("async_a_vnode_for_release:async_broadcast_cmd(#{cmd}) #{res}")
|
498
|
+
end
|
499
|
+
|
500
|
+
return true
|
501
|
+
rescue =>e
|
502
|
+
@log.error("#{e}\n#{$@}")
|
503
|
+
false
|
504
|
+
end
|
505
|
+
|
506
|
+
def sync_a_vnode(vn, to_nid, is_primary=nil)
|
507
|
+
if @stats.run_iterate_storage == true
|
508
|
+
@log.warn("sync_a_vnode:already in being.#{vn} #{to_nid} #{is_primary}")
|
509
|
+
return false
|
510
|
+
end
|
511
|
+
nids = @rttable.search_nodes(vn)
|
512
|
+
|
513
|
+
if nids.include?(to_nid)==false || (is_primary && nids[0]!=to_nid)
|
514
|
+
@log.debug("sync_a_vnode:#{vn} #{to_nid} #{is_primary}")
|
515
|
+
# change routing data at the vnode and synchronize a data
|
516
|
+
nids << to_nid
|
517
|
+
return false unless @rttable.transaction(vn, nids)
|
518
|
+
|
519
|
+
# synchronize a data
|
520
|
+
@storages.each_key{ |hname|
|
521
|
+
res = push_a_vnode_stream(hname, vn, to_nid)
|
522
|
+
|
523
|
+
if res != "STORED"
|
524
|
+
@rttable.rollback(vn)
|
525
|
+
@log.error("push_a_vnode was failed:hname=#{hname} vn=#{vn}:#{res}")
|
526
|
+
return false
|
527
|
+
end
|
528
|
+
}
|
529
|
+
|
530
|
+
if (clk = @rttable.commit(vn)) == false
|
531
|
+
@rttable.rollback(vn)
|
532
|
+
@log.error("sync_a_vnode:routing table commit failed")
|
533
|
+
return false
|
534
|
+
end
|
535
|
+
|
536
|
+
nids = edit_nodes(nids, to_nid, is_primary)
|
537
|
+
clk = @rttable.set_route(vn, clk, nids)
|
538
|
+
if clk.is_a?(Integer) == false
|
539
|
+
clk,nids = @rttable.search_nodes_with_clk(vn)
|
540
|
+
end
|
541
|
+
|
542
|
+
cmd = "setroute #{vn} #{clk - 1}"
|
543
|
+
nids.each{ |nn| cmd << " #{nn}"}
|
544
|
+
res = async_broadcast_cmd("#{cmd}\r\n")
|
545
|
+
@log.debug("sync_a_vnode:async_broadcast_cmd(#{cmd}) #{res}")
|
546
|
+
else
|
547
|
+
# synchronize a data
|
548
|
+
@storages.each_key{ |hname|
|
549
|
+
res = push_a_vnode_stream(hname, vn, to_nid)
|
550
|
+
if res != "STORED"
|
551
|
+
@log.error("push_a_vnode was failed:hname=#{hname} vn=#{vn}:#{res}")
|
552
|
+
return false
|
553
|
+
end
|
554
|
+
}
|
555
|
+
end
|
556
|
+
|
557
|
+
return true
|
558
|
+
rescue =>e
|
559
|
+
@log.error("#{e}\n#{$@}")
|
560
|
+
false
|
561
|
+
end
|
562
|
+
|
563
|
+
def edit_nodes(nodes, new_nid, is_primary)
|
564
|
+
if @rttable.rn == 1
|
565
|
+
return [new_nid]
|
566
|
+
end
|
567
|
+
if nodes.length > @rttable.rn
|
568
|
+
nodes.delete(new_nid)
|
569
|
+
nodes.delete(nodes.last)
|
570
|
+
nodes << new_nid
|
571
|
+
end
|
572
|
+
if is_primary
|
573
|
+
nodes.delete(new_nid)
|
574
|
+
nodes.insert(0,new_nid)
|
575
|
+
end
|
576
|
+
nodes
|
577
|
+
end
|
578
|
+
|
579
|
+
def push_a_vnode(hname, vn, nid)
|
580
|
+
dmp = @storages[hname].dump(vn)
|
581
|
+
unless dmp
|
582
|
+
@log.info("hname=#{hname} vn=#{vn} has a empty data.")
|
583
|
+
return "STORED"
|
584
|
+
end
|
585
|
+
con = Roma::Messaging::ConPool.instance.get_connection(nid)
|
586
|
+
|
587
|
+
con.write("pushv #{hname} #{vn}\r\n")
|
588
|
+
res = con.gets # READY\r\n or error string
|
589
|
+
if res != "READY\r\n"
|
590
|
+
con.close
|
591
|
+
return res.chomp
|
592
|
+
end
|
593
|
+
con.write("#{dmp.length}\r\n#{dmp}\r\nEND\r\n")
|
594
|
+
res = con.gets # STORED\r\n or error string
|
595
|
+
|
596
|
+
Roma::Messaging::ConPool.instance.return_connection(nid,con)
|
597
|
+
res.chomp! if res
|
598
|
+
res
|
599
|
+
rescue Errno::EPIPE
|
600
|
+
@log.debug("Errno::EPIPE retry")
|
601
|
+
retry
|
602
|
+
rescue =>e
|
603
|
+
@log.error("#{e.inspect}\n#{$@}")
|
604
|
+
"#{e}"
|
605
|
+
end
|
606
|
+
|
607
|
+
def push_a_vnode_stream(hname, vn, nid)
|
608
|
+
@stats.run_iterate_storage = true
|
609
|
+
@log.info("push_a_vnode_stream:hname=#{hname} vn=#{vn} nid=#{nid}")
|
610
|
+
con = Roma::Messaging::ConPool.instance.get_connection(nid)
|
611
|
+
|
612
|
+
con.write("spushv #{hname} #{vn}\r\n")
|
613
|
+
|
614
|
+
res = con.gets # READY\r\n or error string
|
615
|
+
if res != "READY\r\n"
|
616
|
+
con.close
|
617
|
+
return res.chomp
|
618
|
+
end
|
619
|
+
|
620
|
+
@storages[hname].each_vn_dump(vn){|data|
|
621
|
+
@stats.run_iterate_storage = true
|
622
|
+
con.write(data)
|
623
|
+
sleep @stats.stream_copy_wait_param
|
624
|
+
}
|
625
|
+
con.write("\0"*20) # end of steram
|
626
|
+
|
627
|
+
res = con.gets # STORED\r\n or error string
|
628
|
+
Roma::Messaging::ConPool.instance.return_connection(nid,con)
|
629
|
+
res.chomp! if res
|
630
|
+
res
|
631
|
+
rescue =>e
|
632
|
+
@log.error("#{e}\n#{$@}")
|
633
|
+
e.to_s
|
634
|
+
ensure
|
635
|
+
@stats.run_iterate_storage = false
|
636
|
+
end
|
637
|
+
|
638
|
+
|
639
|
+
def asyncev_start_storage_clean_up_process(args)
|
640
|
+
# @log.info("#{__method__}")
|
641
|
+
if @stats.run_storage_clean_up
|
642
|
+
@log.error("#{__method__}:already in being")
|
643
|
+
return
|
644
|
+
end
|
645
|
+
@stats.run_storage_clean_up = true
|
646
|
+
Thread::new{
|
647
|
+
begin
|
648
|
+
storage_clean_up_process
|
649
|
+
rescue =>e
|
650
|
+
@log.error("#{__method__}:#{e.inspect} #{$@}")
|
651
|
+
ensure
|
652
|
+
@stats.run_storage_clean_up = false
|
653
|
+
end
|
654
|
+
}
|
655
|
+
end
|
656
|
+
|
657
|
+
def storage_clean_up_process
|
658
|
+
# @log.info("#{__method__}:start")
|
659
|
+
me = @stats.ap_str
|
660
|
+
vnhash={}
|
661
|
+
@rttable.each_vnode{|vn, nids|
|
662
|
+
if nids.include?(me)
|
663
|
+
if nids[0] == me
|
664
|
+
vnhash[vn] = :primary
|
665
|
+
else
|
666
|
+
vnhash[vn] = :secondary
|
667
|
+
end
|
668
|
+
end
|
669
|
+
}
|
670
|
+
t = Time.now.to_i - Roma::Config::STORAGE_DELMARK_EXPTIME
|
671
|
+
count = 0
|
672
|
+
@storages.each_pair{|hname,st|
|
673
|
+
st.each_clean_up(t, vnhash){|key, vn|
|
674
|
+
count += 1
|
675
|
+
@stats.out_count += 1
|
676
|
+
# @log.debug("#{__method__}:key=#{key} vn=#{vn}")
|
677
|
+
nodes = @rttable.search_nodes_for_write(vn)
|
678
|
+
next if(nodes.length <= 1)
|
679
|
+
nodes[1..-1].each{|nid|
|
680
|
+
res = async_send_cmd(nid,"out #{key}\e#{hname} #{vn}\r\n")
|
681
|
+
unless res
|
682
|
+
@log.warn("send out command failed:#{key}\e#{hname} #{vn} -> #{nid}")
|
683
|
+
end
|
684
|
+
# @log.debug("#{__method__}:res=#{res}")
|
685
|
+
}
|
686
|
+
}
|
687
|
+
}
|
688
|
+
if count>0
|
689
|
+
@log.info("#{__method__}:#{count} keys deleted.")
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
693
|
+
|
694
|
+
end # module AsyncProcess
|
695
|
+
|
696
|
+
end # module Roma
|