roma 0.8.13 → 0.8.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +20 -0
- data/Gemfile +17 -0
- data/Rakefile +2 -2
- data/ruby/server/bin/cpdb +6 -0
- data/ruby/server/bin/safecopy_integration_test +10 -0
- data/ruby/server/bin/safecopy_test +10 -0
- data/ruby/server/lib/roma/async_process.rb +87 -3
- data/ruby/server/lib/roma/command/sys_command_receiver.rb +181 -5
- data/ruby/server/lib/roma/command/vn_command_receiver.rb +9 -3
- data/ruby/server/lib/roma/event/con_pool.rb +1 -1
- data/ruby/server/lib/roma/event/handler.rb +11 -5
- data/ruby/server/lib/roma/messaging/con_pool.rb +1 -1
- data/ruby/server/lib/roma/romad.rb +3 -1
- data/ruby/server/lib/roma/stats.rb +19 -1
- data/ruby/server/lib/roma/storage/basic_storage.rb +342 -82
- data/ruby/server/lib/roma/storage/dummy_storage.rb +0 -2
- data/ruby/server/lib/roma/storage/rh_storage.rb +13 -12
- data/ruby/server/lib/roma/storage/sqlite3_storage.rb +4 -0
- data/ruby/server/lib/roma/storage/tc_storage.rb +6 -20
- data/ruby/server/lib/roma/tools/cpdb.rb +103 -0
- data/ruby/server/lib/roma/tools/safecopy_integration_test.rb +247 -0
- data/ruby/server/lib/roma/tools/safecopy_test.rb +184 -0
- data/ruby/server/lib/roma/tools/simple_bench.rb +16 -16
- data/ruby/server/lib/roma/version.rb +1 -1
- data/ruby/server/test/t_storage.rb +223 -41
- metadata +25 -20
@@ -8,15 +8,18 @@ module Roma
|
|
8
8
|
def get(k); self[k]; end
|
9
9
|
def out(k); delete(k); end
|
10
10
|
def rnum; length; end
|
11
|
+
def sync; true; end
|
11
12
|
end
|
12
13
|
|
13
14
|
class RubyHashStorage < BasicStorage
|
14
15
|
|
15
16
|
def opendb
|
16
17
|
create_div_hash
|
17
|
-
@divnum.times
|
18
|
+
@divnum.times do |i|
|
18
19
|
@hdb[i] = open_db(nil)
|
19
|
-
|
20
|
+
@hdbc[i] = nil
|
21
|
+
@dbs[i] = :normal
|
22
|
+
end
|
20
23
|
end
|
21
24
|
|
22
25
|
if RUBY_VERSION >= '1.9.2'
|
@@ -42,25 +45,23 @@ module Roma
|
|
42
45
|
}
|
43
46
|
end
|
44
47
|
|
45
|
-
def
|
48
|
+
def each_unpacked_db(target_vn, db)
|
46
49
|
count = 0
|
47
50
|
tn = Time.now.to_i
|
48
|
-
keys =
|
49
|
-
keys.each
|
50
|
-
v =
|
51
|
+
keys = db[@hdiv[target_vn]].keys
|
52
|
+
keys.each do |k|
|
53
|
+
v = db[@hdiv[target_vn]][k]
|
51
54
|
vn, last, clk, expt, val = unpack_data(v)
|
52
55
|
if vn != target_vn || (expt != 0 && tn > expt)
|
53
56
|
count += 1
|
54
57
|
sleep @each_vn_dump_sleep if count % @each_vn_dump_sleep_count == 0
|
55
58
|
next
|
56
59
|
end
|
57
|
-
|
58
|
-
|
59
|
-
else
|
60
|
-
yield [vn, last, clk, expt, k.length, k, 0].pack("NNNNNa#{k.length}N")
|
61
|
-
end
|
62
|
-
}
|
60
|
+
yield vn, last, clk, expt, k, val
|
61
|
+
end
|
63
62
|
end
|
63
|
+
private :each_unpacked_db
|
64
|
+
|
64
65
|
|
65
66
|
def each_hdb_dump(i,except_vnh = nil)
|
66
67
|
count = 0
|
@@ -32,7 +32,7 @@ module Roma
|
|
32
32
|
end
|
33
33
|
ret
|
34
34
|
end
|
35
|
-
end
|
35
|
+
end # class TokyoCabinet::HDB
|
36
36
|
|
37
37
|
def initialize
|
38
38
|
super
|
@@ -51,33 +51,18 @@ module Roma
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def opendb
|
54
|
-
create_div_hash
|
55
|
-
path = ''
|
56
|
-
@storage_path.split('/').each{|p|
|
57
|
-
if p.length==0
|
58
|
-
path = '/'
|
59
|
-
next
|
60
|
-
end
|
61
|
-
path << p
|
62
|
-
Dir::mkdir(path) unless File.exist?(path)
|
63
|
-
path << '/'
|
64
|
-
}
|
65
|
-
|
66
54
|
@fname_lock = "#{@storage_path}/lock"
|
67
55
|
if File.exist?(@fname_lock)
|
68
56
|
raise RuntimeError.new("Lock file already exists.")
|
69
57
|
end
|
70
|
-
open(@fname_lock,"w"){}
|
71
58
|
|
72
|
-
|
73
|
-
|
74
|
-
}
|
59
|
+
super
|
60
|
+
|
61
|
+
open(@fname_lock,"w"){}
|
75
62
|
end
|
76
63
|
|
77
64
|
def closedb
|
78
|
-
|
79
|
-
buf = @hdb; @hdb = []
|
80
|
-
buf.each{ |hdb| close_db(hdb) }
|
65
|
+
super
|
81
66
|
|
82
67
|
File.unlink(@fname_lock) if @fname_lock
|
83
68
|
@fname_lock = nil
|
@@ -202,6 +187,7 @@ module Roma
|
|
202
187
|
opts += "#bnum=#{prop['bnum']}" if prop.key?('bnum')
|
203
188
|
opts += "#capnum=#{prop['capnum']}" if prop.key?('capnum')
|
204
189
|
opts += "#capsiz=#{prop['capsiz']}" if prop.key?('capsiz')
|
190
|
+
|
205
191
|
opts = nil unless opts.length > 0
|
206
192
|
opts
|
207
193
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
module Roma
|
6
|
+
class SafeCopy
|
7
|
+
|
8
|
+
attr_reader :storages
|
9
|
+
|
10
|
+
def initialize(addr, port)
|
11
|
+
@con = TCPSocket.open(addr, port)
|
12
|
+
get_storage_info
|
13
|
+
end
|
14
|
+
|
15
|
+
def backup_all
|
16
|
+
@storages.keys.each do |k|
|
17
|
+
backup(k)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def backup(hname)
|
22
|
+
stat = get_safecopy_stats(hname)
|
23
|
+
if stat.uniq != [:normal]
|
24
|
+
puts "storages[#{hname}].storage.safecopy_stats #{stat.to_s}"
|
25
|
+
puts "ERROR: Status except the :normal exists."
|
26
|
+
return
|
27
|
+
end
|
28
|
+
@storages[hname].each_with_index do |fname, num|
|
29
|
+
ret = set_storage_status(hname, num, "safecopy")
|
30
|
+
if ret != "PUSHED\r\n"
|
31
|
+
puts ret
|
32
|
+
puts "ERROR: Can't change storage status to safecopy."
|
33
|
+
return
|
34
|
+
end
|
35
|
+
wait(hname, num, :safecopy_flushed)
|
36
|
+
puts "copy file : #{fname}"
|
37
|
+
# file copy
|
38
|
+
`cp #{fname} #{fname}.#{Time.now.strftime("%Y%m%d%H%M%S")}`
|
39
|
+
ret = set_storage_status(hname, num, "normal")
|
40
|
+
if ret != "PUSHED\r\n"
|
41
|
+
puts ret
|
42
|
+
puts "ERROR: Can't change storage status to normal."
|
43
|
+
return
|
44
|
+
end
|
45
|
+
wait(hname, num, :normal)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def wait(hname, num, stat)
|
50
|
+
print "waiting for storages[#{hname}][#{num}] == #{stat} "
|
51
|
+
while get_safecopy_stats(hname)[num] != stat
|
52
|
+
print "."
|
53
|
+
sleep 5
|
54
|
+
end
|
55
|
+
puts
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_storage_info
|
59
|
+
@storages = {}
|
60
|
+
stats do |line|
|
61
|
+
if /^storages\[(.+)\]\.storage\[(\d+)\]\.path\s(.+)/ =~ line
|
62
|
+
@storages[$1] = [] unless @storages.key? $1
|
63
|
+
@storages[$1][$2.to_i] = $3.chomp
|
64
|
+
# puts "#{$1} #{$2} #{$3}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_safecopy_stats(hname)
|
70
|
+
ret = nil
|
71
|
+
stats do |line|
|
72
|
+
if /^storages\[#{hname}\]\.storage\.safecopy_stats\s(.+)/ =~ line
|
73
|
+
ret = $1.chomp
|
74
|
+
end
|
75
|
+
end
|
76
|
+
eval ret
|
77
|
+
end
|
78
|
+
|
79
|
+
def set_storage_status(hname, num, stat)
|
80
|
+
@con.puts "set_storage_status #{num} #{stat} #{hname}\r\n"
|
81
|
+
@con.gets
|
82
|
+
end
|
83
|
+
|
84
|
+
def stats
|
85
|
+
@con.puts "stat storage\r\n"
|
86
|
+
yield $_ while @con.gets != "END\r\n"
|
87
|
+
end
|
88
|
+
|
89
|
+
def close
|
90
|
+
@con.close if @con
|
91
|
+
end
|
92
|
+
|
93
|
+
end # SafeCopy
|
94
|
+
end # Roma
|
95
|
+
|
96
|
+
if ARGV.length < 1
|
97
|
+
puts File.basename(__FILE__) + " [port]"
|
98
|
+
exit
|
99
|
+
end
|
100
|
+
|
101
|
+
sc = Roma::SafeCopy.new("localhost", ARGV[0].to_i)
|
102
|
+
sc.backup_all
|
103
|
+
sc.close
|
@@ -0,0 +1,247 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'date'
|
4
|
+
require 'roma/client/rclient'
|
5
|
+
|
6
|
+
@cnt = 0
|
7
|
+
@tmax = 0
|
8
|
+
@tmin = 100
|
9
|
+
|
10
|
+
@m = Mutex.new
|
11
|
+
|
12
|
+
Thread.new do
|
13
|
+
sleep_time=10
|
14
|
+
while(true)
|
15
|
+
sleep sleep_time
|
16
|
+
printf("\s\sqps=%d max=%f min=%f ave=%f\n",@cnt/sleep_time,@tmax,@tmin,sleep_time/@cnt.to_f)
|
17
|
+
@cnt=0
|
18
|
+
@tmax=0
|
19
|
+
@tmin=100
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def random_rquest_sender(ini_nodes, n)
|
24
|
+
puts __method__
|
25
|
+
rc=Roma::Client::RomaClient.new(ini_nodes)
|
26
|
+
|
27
|
+
loop do
|
28
|
+
i=rand(n)
|
29
|
+
ts = DateTime.now
|
30
|
+
case rand(3)
|
31
|
+
when 0
|
32
|
+
res=rc.set(i.to_s,'hoge'+i.to_s)
|
33
|
+
puts "set k=#{i} #{res}" if res==nil || res.chomp != 'STORED'
|
34
|
+
when 1
|
35
|
+
res=rc.get(i.to_s)
|
36
|
+
puts "get k=#{i} #{res}" if res == :error
|
37
|
+
when 2
|
38
|
+
res=rc.delete(i.to_s)
|
39
|
+
puts "del k=#{i} #{res}" if res != 'DELETED' && res != 'NOT_FOUND'
|
40
|
+
end
|
41
|
+
t=(DateTime.now - ts).to_f * 86400.0
|
42
|
+
@tmax=t if t > @tmax
|
43
|
+
@tmin=t if t < @tmin
|
44
|
+
@cnt+=1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def set_counts(ini_nodes, range, key_prefix, value)
|
49
|
+
puts "\s\s#{__method__} #{range} #{value}"
|
50
|
+
rc=Roma::Client::RomaClient.new(ini_nodes)
|
51
|
+
@range_cnt = 0
|
52
|
+
|
53
|
+
range.each do |i|
|
54
|
+
ts = DateTime.now
|
55
|
+
@range_cnt = i
|
56
|
+
res=rc.set("#{key_prefix}_#{i}","#{value}")
|
57
|
+
puts "set #{key_prefix}_#{i}=#{value} #{res}" if res==nil || res.chomp != 'STORED'
|
58
|
+
t=(DateTime.now - ts).to_f * 86400.0
|
59
|
+
@tmax=t if t > @tmax
|
60
|
+
@tmin=t if t < @tmin
|
61
|
+
@cnt+=1
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def check_count(ini_nodes, range, key_prefix, value)
|
66
|
+
puts "\s\s#{__method__} #{range} #{value}"
|
67
|
+
rc=Roma::Client::RomaClient.new(ini_nodes)
|
68
|
+
|
69
|
+
range.each do |i|
|
70
|
+
ts = DateTime.now
|
71
|
+
res = rc.get("#{key_prefix}_#{i}")
|
72
|
+
if res != value.to_s
|
73
|
+
puts "error k=#{key_prefix}_#{i} #{res}"
|
74
|
+
end
|
75
|
+
|
76
|
+
t=(DateTime.now - ts).to_f * 86400.0
|
77
|
+
@tmax=t if t > @tmax
|
78
|
+
@tmin=t if t < @tmin
|
79
|
+
@cnt+=1
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def send_cmd(nid, cmd)
|
84
|
+
conn = Roma::Client::ConPool.instance.get_connection(nid)
|
85
|
+
conn.write "#{cmd}\r\n"
|
86
|
+
ret = conn.gets
|
87
|
+
Roma::Client::ConPool.instance.return_connection(nid, conn)
|
88
|
+
ret
|
89
|
+
rescue =>e
|
90
|
+
STDERR.puts "#{nid} #{cmd} #{e.inspect}"
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def stats(nid, regexp=nil)
|
95
|
+
conn = Roma::Client::ConPool.instance.get_connection(nid)
|
96
|
+
if regexp
|
97
|
+
conn.write "stats #{regexp}\r\n"
|
98
|
+
else
|
99
|
+
conn.write "stats\r\n"
|
100
|
+
end
|
101
|
+
ret = ""
|
102
|
+
while(conn.gets != "END\r\n")
|
103
|
+
ret << $_
|
104
|
+
end
|
105
|
+
Roma::Client::ConPool.instance.return_connection(nid, conn)
|
106
|
+
ret
|
107
|
+
rescue =>e
|
108
|
+
STDERR.puts "#{nid} #{e.inspect}"
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
|
112
|
+
def safecopy_stats(nid)
|
113
|
+
ret = stats(nid, 'storage.safecopy_stats')
|
114
|
+
return eval $1 if ret =~ /^.+\s(\[.+\])/
|
115
|
+
nil
|
116
|
+
end
|
117
|
+
|
118
|
+
def set_storage_status(nid, fno, stat)
|
119
|
+
send_cmd(ARGV[0], "set_storage_status #{fno} #{stat}")
|
120
|
+
end
|
121
|
+
|
122
|
+
def wait_status(nid, fno, stat)
|
123
|
+
while safecopy_stats(nid)[fno] != stat
|
124
|
+
sleep 5
|
125
|
+
end
|
126
|
+
stat
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_change_status
|
130
|
+
|
131
|
+
puts "write (0...10000) = 0"
|
132
|
+
set_counts(ARGV, 0...10000, "default_key",0)
|
133
|
+
Thread.new { random_rquest_sender(ARGV, 10000) }
|
134
|
+
|
135
|
+
set_counts(ARGV, 0...1000, "flushing_key", 0)
|
136
|
+
set_counts(ARGV, 0...1000, "caching_key", 0)
|
137
|
+
|
138
|
+
nid = ARGV[0]
|
139
|
+
|
140
|
+
sleep(5)
|
141
|
+
|
142
|
+
10.times do |n|
|
143
|
+
puts "\n#{n+1}th loop(#{n}.tc)****************************************************************** "
|
144
|
+
|
145
|
+
#========================================================================================
|
146
|
+
#flushing(normal => safecopy_flushed)
|
147
|
+
flush_loop_count = 0
|
148
|
+
@range_cnt = 0
|
149
|
+
@flag = false
|
150
|
+
|
151
|
+
t = Thread.new {
|
152
|
+
loop{
|
153
|
+
flush_loop_count += 1
|
154
|
+
set_counts(ARGV, 0...1000, "flushing_key", flush_loop_count)
|
155
|
+
@flag = true
|
156
|
+
}
|
157
|
+
}
|
158
|
+
while !@flag do
|
159
|
+
puts "\s\s[debug]sleep flushing start"
|
160
|
+
sleep(1)
|
161
|
+
puts "\s\s[debug]sleep flushing end"
|
162
|
+
end
|
163
|
+
puts "\s\s#{set_storage_status(nid, n, 'safecopy')}"
|
164
|
+
puts "#{wait_status(nid, n, :safecopy_flushed)}"
|
165
|
+
|
166
|
+
#sleep(5)
|
167
|
+
t.kill
|
168
|
+
|
169
|
+
flushing_range_cnt = @range_cnt
|
170
|
+
puts "\s\s#{safecopy_stats(nid)}\n\n"
|
171
|
+
|
172
|
+
#========================================================================================
|
173
|
+
#Caching(safecopy_flushed => normal)
|
174
|
+
#sleep(30)
|
175
|
+
cache_loop_count = 0
|
176
|
+
@range_cnt = 0
|
177
|
+
@flag = false
|
178
|
+
t = Thread.new {
|
179
|
+
loop{
|
180
|
+
cache_loop_count += 1
|
181
|
+
set_counts(ARGV, 0...1000, "caching_key", cache_loop_count)
|
182
|
+
@flag = true
|
183
|
+
}
|
184
|
+
}
|
185
|
+
while !@flag do
|
186
|
+
puts "\s\s[debug]sleep caching start"
|
187
|
+
sleep(1)
|
188
|
+
puts "\s\s[debug]sleep caching end"
|
189
|
+
end
|
190
|
+
|
191
|
+
puts "\s\s#{set_storage_status(nid, n, 'normal')}"
|
192
|
+
puts "#{wait_status(nid, n, :normal)}"
|
193
|
+
|
194
|
+
#sleep(5)
|
195
|
+
t.kill
|
196
|
+
|
197
|
+
caching_range_cnt = @range_cnt
|
198
|
+
puts "\s\s#{safecopy_stats(nid)}"
|
199
|
+
|
200
|
+
#========================================================================================
|
201
|
+
#check
|
202
|
+
puts "\n[Check]"
|
203
|
+
puts "\s\sflushing key"
|
204
|
+
check_count(ARGV, 0..flushing_range_cnt, "flushing_key", flush_loop_count)
|
205
|
+
check_count(ARGV, flushing_range_cnt+1...1000, "flushing_key", flush_loop_count-1)
|
206
|
+
|
207
|
+
puts "\n\s\scaching key"
|
208
|
+
check_count(ARGV, 0..caching_range_cnt, "caching_key", cache_loop_count)
|
209
|
+
check_count(ARGV, caching_range_cnt+1...1000, "caching_key", cache_loop_count-1) if cache_loop_count != 1
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_round
|
214
|
+
n = 0
|
215
|
+
1000.times do |i|
|
216
|
+
set_counts(ARGV, 0...10000, i)
|
217
|
+
check_count(ARGV, 0...10000, i)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
param = { :num=>10000, :th=>1 }
|
222
|
+
|
223
|
+
opts = OptionParser.new
|
224
|
+
|
225
|
+
opts.on("-r", "--round", "round request"){|v| param[:round] = v }
|
226
|
+
opts.on("-c", "--count [x]", "counts of the test times"){|v| param[:count] = v.to_i }
|
227
|
+
|
228
|
+
opts.banner = "usage:#{File.basename($0)} [options] addr:port"
|
229
|
+
opts.parse!(ARGV)
|
230
|
+
|
231
|
+
if ARGV.length == 0
|
232
|
+
STDERR.puts opts.help
|
233
|
+
exit
|
234
|
+
end
|
235
|
+
|
236
|
+
if param.key?(:round)
|
237
|
+
test_round
|
238
|
+
else
|
239
|
+
param[:count] = 1 if !param.key?(:count)
|
240
|
+
|
241
|
+
param[:count].times do |count|
|
242
|
+
puts "#{count+1}th test========================================================================================="
|
243
|
+
test_change_status
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
puts "#{File.basename($0)} has done."
|