roma 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/LICENSE.rdoc +675 -0
  2. data/README.rdoc +0 -0
  3. data/Rakefile +70 -0
  4. data/bin/mkrecent +7 -0
  5. data/bin/mkroute +7 -0
  6. data/bin/recoverlost +8 -0
  7. data/bin/recoverlost_alist +8 -0
  8. data/bin/romad +7 -0
  9. data/bin/sample_watcher +8 -0
  10. data/bin/sample_watcher2 +8 -0
  11. data/bin/simple_bench +8 -0
  12. data/bin/ssroute +7 -0
  13. data/bin/tribunus +7 -0
  14. data/lib/roma/async_process.rb +696 -0
  15. data/lib/roma/command/bg_command_receiver.rb +188 -0
  16. data/lib/roma/command/mh_command_receiver.rb +117 -0
  17. data/lib/roma/command/receiver.rb +287 -0
  18. data/lib/roma/command/rt_command_receiver.rb +147 -0
  19. data/lib/roma/command/st_command_receiver.rb +564 -0
  20. data/lib/roma/command/util_command_receiver.rb +67 -0
  21. data/lib/roma/command/vn_command_receiver.rb +143 -0
  22. data/lib/roma/command_plugin.rb +11 -0
  23. data/lib/roma/config.rb +64 -0
  24. data/lib/roma/event/con_pool.rb +140 -0
  25. data/lib/roma/event/handler.rb +159 -0
  26. data/lib/roma/plugin/plugin_alist.rb +1572 -0
  27. data/lib/roma/plugin/plugin_debug.rb +19 -0
  28. data/lib/roma/plugin/plugin_test.rb +14 -0
  29. data/lib/roma/romad.rb +582 -0
  30. data/lib/roma/routing/cb_rttable.rb +326 -0
  31. data/lib/roma/routing/merkle_tree.rb +54 -0
  32. data/lib/roma/routing/rttable.rb +148 -0
  33. data/lib/roma/stats.rb +112 -0
  34. data/lib/roma/storage/basic_storage.rb +510 -0
  35. data/lib/roma/storage/dbm_storage.rb +80 -0
  36. data/lib/roma/storage/dummy_storage.rb +44 -0
  37. data/lib/roma/storage/rh_storage.rb +35 -0
  38. data/lib/roma/storage/sqlite3_storage.rb +73 -0
  39. data/lib/roma/storage/tc_storage.rb +133 -0
  40. data/lib/roma/tools/mkrecent.rb +138 -0
  41. data/lib/roma/tools/mkroute.rb +52 -0
  42. data/lib/roma/tools/recoverlost.rb +9 -0
  43. data/lib/roma/tools/recoverlost_alist.rb +9 -0
  44. data/lib/roma/tools/recoverlost_lib.rb +217 -0
  45. data/lib/roma/tools/sample_watcher.rb +38 -0
  46. data/lib/roma/tools/sample_watcher2.rb +38 -0
  47. data/lib/roma/tools/simple_bench.rb +57 -0
  48. data/lib/roma/tools/ssroute.rb +23 -0
  49. data/lib/roma/tools/tribunus.rb +299 -0
  50. data/lib/roma/version.rb +4 -0
  51. data/lib/roma/write_behind.rb +179 -0
  52. data/test/rcirb.rb +16 -0
  53. data/test/roma-test-utils.rb +65 -0
  54. data/test/run-test.rb +16 -0
  55. data/test/t_cpdata.rb +277 -0
  56. data/test/t_listplugin.rb +592 -0
  57. data/test/t_rclient.rb +318 -0
  58. data/test/t_routing_data.rb +100 -0
  59. data/test/t_storage.rb +644 -0
  60. data/test/t_writebehind.rb +200 -0
  61. metadata +134 -0
@@ -0,0 +1,1572 @@
1
+ require 'timeout'
2
+ require 'roma/messaging/con_pool'
3
+ require 'json'
4
+
5
+ module Roma
6
+ module CommandPlugin
7
+
8
+ module PluginAshiatoList
9
+ include ::Roma::CommandPlugin
10
+
11
+ # alist_at <key> <index> [forward]\r\n
12
+ #
13
+ # (
14
+ # [VALUE <key> 0 <value length>\r\n
15
+ # <value>\r\n]
16
+ # END\r\n
17
+ # |SERVER_ERROR <error message>\r\n)
18
+ def ev_alist_at(s)
19
+ hname, k, d, vn, nodes = calc_hash(s[1])
20
+ return forward1(nodes[0], s) if nodes[0] != @nid
21
+
22
+ ddata = @storages[hname].get(vn, k, d)
23
+ @stats.read_count += 1
24
+ if ddata
25
+ v = Marshal.load(ddata)[0]
26
+ return send_data("END\r\n") if v.length <= s[2].to_i
27
+ ret = v.at(s[2].to_i)
28
+ return send_data("VALUE #{s[1]} 0 #{ret.length}\r\n#{ret}\r\nEND\r\n")
29
+ else
30
+ return send_data("END\r\n")
31
+ end
32
+ rescue => e
33
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
34
+ send_data("#{msg}\r\n")
35
+ @log.error("#{e} #{$@}")
36
+ end
37
+
38
+ # alist_clear <key> [forward]\r\n
39
+ #
40
+ # (CLEARED|NOT_CLEARED|SERVER_ERROR <error message>)\r\n
41
+ def ev_alist_clear(s)
42
+ hname, k, d, vn, nodes = calc_hash(s[1])
43
+ return forward2(nodes[0], s) if nodes[0] != @nid
44
+
45
+ ddata = @storages[hname].get(vn, k, d)
46
+ return send_data("NOT_FOUND\r\n") unless ddata
47
+
48
+ expt = 0x7fffffff
49
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump([[],[]]))
50
+ @stats.delete_count += 1
51
+ Roma::WriteBehindProcess::push(hname, 3, k, ddata)
52
+
53
+ if ret
54
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
55
+ send_data("CLEARED\r\n")
56
+ else
57
+ send_data("NOT_CLEARED\r\n")
58
+ end
59
+ rescue => e
60
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
61
+ send_data("#{msg}\r\n")
62
+ @log.error("#{e} #{$@}")
63
+ end
64
+
65
+ # alist_delete <key> <bytes> [forward]\r\n
66
+ # <data block>\r\n
67
+ #
68
+ # (DELETED|NOT_DELETED|NOT_FOUND|SERVER_ERROR <error message>)\r\n
69
+ def ev_alist_delete(s)
70
+ hname, k, d, vn, nodes = calc_hash(s[1])
71
+ data = read_bytes(s[2].to_i)
72
+ read_bytes(2)
73
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
74
+
75
+ ddata = @storages[hname].get(vn, k, d)
76
+ return send_data("NOT_FOUND\r\n") unless ddata
77
+
78
+ v = Marshal.load(ddata)
79
+ return send_data("NOT_DELETED\r\n") unless v[0].include?(data)
80
+ while(idx = v[0].index(data))
81
+ v[0].delete_at(idx)
82
+ v[1].delete_at(idx)
83
+ end
84
+
85
+ expt = 0x7fffffff
86
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
87
+ @stats.delete_count += 1
88
+
89
+ Roma::WriteBehindProcess::push(hname, 2, k, data)
90
+
91
+ if ret
92
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
93
+ send_data("DELETED\r\n")
94
+ else
95
+ send_data("NOT_DELETED\r\n")
96
+ end
97
+ rescue => e
98
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
99
+ send_data("#{msg}\r\n")
100
+ @log.error("#{e} #{$@}")
101
+ end
102
+
103
+ # alist_delete_at <key> <index> [forward]\r\n
104
+ #
105
+ # (DELETED|NOT_DELETED|NOT_FOUND|SERVER_ERROR <error message>)\r\n
106
+ def ev_alist_delete_at(s)
107
+ hname, k, d, vn, nodes = calc_hash(s[1])
108
+ return forward2(nodes[0], s) if nodes[0] != @nid
109
+
110
+ ddata = @storages[hname].get(vn, k, d)
111
+ return send_data("NOT_FOUND\r\n") unless ddata
112
+
113
+ v = Marshal.load(ddata)
114
+ dret = v[0].delete_at(s[2].to_i)
115
+ return send_data("NOT_DELETED\r\n") unless dret
116
+ v[1].delete_at(s[2].to_i)
117
+
118
+ expt = 0x7fffffff
119
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
120
+ @stats.delete_count += 1
121
+
122
+ Roma::WriteBehindProcess::push(hname, 2, k, dret)
123
+
124
+ if ret
125
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
126
+ send_data("DELETED\r\n")
127
+ else
128
+ send_data("NOT_DELETED\r\n")
129
+ end
130
+ rescue => e
131
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
132
+ send_data("#{msg}\r\n")
133
+ @log.error("${e} #{$@}")
134
+ end
135
+
136
+ # alist_empty? <key> [forward]\r\n
137
+ #
138
+ # (true|false|NOT_FOUND|SERVER_ERROR <error message>)\r\n
139
+ def ev_alist_empty?(s)
140
+ hname, k, d, vn, nodes = calc_hash(s[1])
141
+ return forward2(nodes[0], s) if nodes[0] != @nid
142
+
143
+ ddata = @storages[hname].get(vn, k, d)
144
+ @stats.read_count += 1
145
+
146
+ return send_data("NOT_FOUND\r\n") unless ddata
147
+
148
+ v = Marshal.load(ddata)
149
+ ret = v[0].empty?
150
+
151
+ send_data("#{ret}\r\n")
152
+ rescue => e
153
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
154
+ send_data("#{msg}\r\n")
155
+ @log.error("#{e} #{$@}")
156
+ end
157
+
158
+ # alist_first <key> [forward]\r\n
159
+ #
160
+ # (
161
+ # [VALUE <key> 0 <value length>\r\n
162
+ # <value>\r\n]
163
+ # END\r\n
164
+ # |SERVER_ERROR <error message>\r\n)
165
+ def ev_alist_first(s)
166
+ hname, k, d, vn, nodes = calc_hash(s[1])
167
+ return forward1(nodes[0], s) if nodes[0] != @nid
168
+
169
+ ddata = @storages[hname].get(vn, k, d)
170
+ @stats.read_count += 1
171
+
172
+ if ddata
173
+ v = Marshal.load(ddata)[0]
174
+ return send_data("END\r\n") if v.length == 0
175
+ ret = v.first
176
+ return send_data("VALUE #{s[1]} 0 #{ret.length}\r\n#{ret}\r\nEND\r\n")
177
+ else
178
+ return send_data("END\r\n")
179
+ end
180
+ rescue => e
181
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
182
+ send_data("#{msg}\r\n")
183
+ @log.error("#{e} #{$@}")
184
+ end
185
+
186
+ # alist_gets <key> [index|range] [forward]\r\n
187
+ #
188
+ # (
189
+ # [VALUE <key> 0 <length of length string>\r\n
190
+ # <length string>\r\n
191
+ # (VALUE <key> 0 <value length>\r\n
192
+ # <value>\r\n)*
193
+ # ]
194
+ # END\r\n
195
+ # |SERVER_ERROR <error message>\r\n)
196
+ def ev_alist_gets(s)
197
+ hname, k, d, vn, nodes = calc_hash(s[1])
198
+ return forward1(nodes[0], s) if nodes[0] != @nid
199
+
200
+ ddata = @storages[hname].get(vn, k, 0)
201
+ @stats.read_count += 1
202
+
203
+ if ddata
204
+ v = Marshal.load(ddata)[0]
205
+ if /(?:^(\d+)$|^(\d+)..((?:-)?\d+)$)/ =~ s[2]
206
+ if $1
207
+ if v.length <= $1.to_i
208
+ return send_data("END\r\n")
209
+ end
210
+ buf = v[Range.new($1.to_i,$1.to_i)]
211
+ else
212
+ buf = v[Range.new($2.to_i,$3.to_i)]
213
+ end
214
+ else
215
+ buf = v
216
+ end
217
+ len = v.length
218
+ send_data("VALUE #{s[1]} 0 #{len.to_s.length}\r\n#{len.to_s}\r\n")
219
+ buf.each{|val|
220
+ send_data("VALUE #{s[1]} 0 #{val.length}\r\n#{val}\r\n")
221
+ }
222
+ return send_data("END\r\n")
223
+ else
224
+ return send_data("END\r\n")
225
+ end
226
+ rescue => e
227
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
228
+ send_data("#{msg}\r\n")
229
+ @log.error("#{e} #{$@}")
230
+ end
231
+
232
+ # alist_gets_with_time <key> [index|range] [forward]\r\n
233
+ #
234
+ # (
235
+ # [VALUE <key> 0 <length of length string>\r\n
236
+ # <length string>\r\n
237
+ # (VALUE <key> 0 <value length>\r\n
238
+ # <value string>\r\n
239
+ # VALUE <key> 0 <value length>\r\n
240
+ # <time string>\r\n)*
241
+ # ]
242
+ # END\r\n
243
+ # |SERVER_ERROR <error message>\r\n)
244
+ def ev_alist_gets_with_time(s)
245
+ hname, k, d, vn, nodes = calc_hash(s[1])
246
+ return forward1(nodes[0], s) if nodes[0] != @nid
247
+
248
+ ddata = @storages[hname].get(vn, k, 0)
249
+ @stats.read_count += 1
250
+
251
+ if ddata
252
+ v = Marshal.load(ddata)
253
+ if /(?:^(\d+)$|^(\d+)..((?:-)?\d+)$)/ =~ s[2]
254
+ if $1
255
+ if v[0].length <= $1.to_i
256
+ return send_data("END\r\n")
257
+ end
258
+ v_buf = v[0][Range.new($1.to_i,$1.to_i)]
259
+ t_buf = v[1][Range.new($1.to_i,$1.to_i)]
260
+ else
261
+ v_buf = v[0][Range.new($2.to_i,$3.to_i)]
262
+ t_buf = v[1][Range.new($2.to_i,$3.to_i)]
263
+ end
264
+ else
265
+ v_buf = v[0]
266
+ t_buf = v[1]
267
+ end
268
+ len = v[0].length
269
+ send_data("VALUE #{s[1]} 0 #{len.to_s.length}\r\n#{len.to_s}\r\n")
270
+ v_buf.each_with_index{|val,idx|
271
+ send_data("VALUE #{s[1]} 0 #{val.length}\r\n#{val}\r\n")
272
+ send_data("VALUE #{s[1]} 0 #{t_buf[idx].to_s.length}\r\n#{t_buf[idx]}\r\n")
273
+ }
274
+ return send_data("END\r\n")
275
+ else
276
+ return send_data("END\r\n")
277
+ end
278
+ rescue => e
279
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
280
+ send_data("#{msg}\r\n")
281
+ @log.error("#{e} #{$@}")
282
+ end
283
+
284
+
285
+ # alist_include? <key> <bytes> [forward]\r\n
286
+ # <data block>\r\n
287
+ #
288
+ # (true|false|NOT_FOUND|SERVER_ERROR <error message>)\r\n
289
+ def ev_alist_include?(s)
290
+ hname, k, d, vn, nodes = calc_hash(s[1])
291
+ data = read_bytes(s[2].to_i)
292
+ read_bytes(2)
293
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
294
+
295
+ ddata = @storages[hname].get(vn, k, d)
296
+ @stats.read_count += 1
297
+
298
+ return send_data("NOT_FOUND\r\n") unless ddata
299
+
300
+ v = Marshal.load(ddata)[0]
301
+ ret = v.include?(data)
302
+
303
+ send_data("#{ret}\r\n")
304
+ rescue => e
305
+ send_data("SERVER_ERROR #{e} #{$@}\r\n")
306
+ @log.error("#{e} #{$@}")
307
+ end
308
+
309
+ # alist_index <key> <bytes> [forward]\r\n
310
+ # <data block>\r\n
311
+ #
312
+ # (<index>|nil|NOT_FOUND|SERVER_ERROR <error message>)\r\n
313
+ def ev_alist_index(s)
314
+ hname, k, d, vn, nodes = calc_hash(s[1])
315
+ data = read_bytes(s[2].to_i)
316
+ read_bytes(2)
317
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
318
+
319
+ ddata = @storages[hname].get(vn, k, d)
320
+ @stats.read_count += 1
321
+
322
+ return send_data("NOT_FOUND\r\n") unless ddata
323
+
324
+ v = Marshal.load(ddata)[0]
325
+ ret = v.index(data)
326
+ if ret
327
+ send_data("#{ret}\r\n")
328
+ else
329
+ send_data("nil\r\n")
330
+ end
331
+ rescue => e
332
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
333
+ send_data("#{msg}\r\n")
334
+ @log.error("#{e} #{$@}")
335
+ end
336
+
337
+ # alist_insert <key> <index> <bytes> [forward]\r\n
338
+ # <data block>\r\n
339
+ #
340
+ # (STORED|NOT_STORED|SERVER_ERROR <error message>)\r\n
341
+ def ev_alist_insert(s)
342
+ hname, k, d, vn, nodes = calc_hash(s[1])
343
+ data = read_bytes(s[3].to_i)
344
+ read_bytes(2)
345
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
346
+
347
+ ddata = @storages[hname].get(vn, k, d)
348
+ if ddata
349
+ v = Marshal.load(ddata)
350
+ else
351
+ v = [[],[]]
352
+ end
353
+
354
+ v[0].insert(s[2].to_i,data)
355
+ v[1].insert(s[2].to_i,Time.now.to_i)
356
+ expt = 0x7fffffff
357
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
358
+ @stats.write_count += 1
359
+
360
+ if ret
361
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
362
+ send_data("STORED\r\n")
363
+ else
364
+ send_data("NOT_STORED\r\n")
365
+ end
366
+ rescue => e
367
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
368
+ send_data("#{msg}\r\n")
369
+ @log.error("#{e} #{$@}")
370
+ end
371
+
372
+ def ev_alist_sized_prepend(s); ev_alist_sized_insert(s); end
373
+
374
+ # alist_sized_insert <key> <array-size> <bytes> [forward]\r\n
375
+ # <data block>\r\n
376
+ #
377
+ # (STORED|NOT_STORED|SERVER_ERROR <error message>)\r\n
378
+ def ev_alist_sized_insert(s)
379
+ hname, k, d, vn, nodes = calc_hash(s[1])
380
+ data = read_bytes(s[3].to_i)
381
+ read_bytes(2)
382
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
383
+
384
+ ddata = @storages[hname].get(vn, k, d)
385
+ if ddata
386
+ v = Marshal.load(ddata)
387
+ else
388
+ v = [[],[]]
389
+ end
390
+
391
+ v[0].insert(0,data)
392
+ v[0] = v[0][0..(s[2].to_i - 1)]
393
+ v[1].insert(0,Time.now.to_i)
394
+ v[1] = v[1][0..(s[2].to_i - 1)]
395
+
396
+ expt = 0x7fffffff
397
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
398
+ @stats.write_count += 1
399
+
400
+ if ret
401
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
402
+ send_data("STORED\r\n")
403
+ else
404
+ send_data("NOT_STORED\r\n")
405
+ end
406
+ rescue => e
407
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
408
+ send_data("#{msg}\r\n")
409
+ @log.error("#{e} #{$@}")
410
+ end
411
+
412
+ def ev_alist_delete_and_prepend(s); ev_alist_swap_and_insert(s); end
413
+
414
+ # alist_swap_and_insert <key> <bytes> [forward]\r\n
415
+ # <data block>\r\n
416
+ #
417
+ # (STORED|NOT_STORED|SERVER_ERROR <error message>)\r\n
418
+ def ev_alist_swap_and_insert(s)
419
+ hname, k, d, vn, nodes = calc_hash(s[1])
420
+ data = read_bytes(s[2].to_i)
421
+ read_bytes(2)
422
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
423
+
424
+ ddata = @storages[hname].get(vn, k, d)
425
+ if ddata
426
+ v = Marshal.load(ddata)
427
+ else
428
+ v = [[],[]]
429
+ end
430
+
431
+ idx = v[0].index(data)
432
+ if idx
433
+ v[0].delete_at(idx)
434
+ v[1].delete_at(idx)
435
+ end
436
+ v[0].insert(0,data)
437
+ v[1].insert(0,Time.now.to_i)
438
+
439
+ expt = 0x7fffffff
440
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
441
+ @stats.write_count += 1
442
+
443
+ Roma::WriteBehindProcess::push(hname, 1, k, data)
444
+
445
+ if ret
446
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
447
+ send_data("STORED\r\n")
448
+ else
449
+ send_data("NOT_STORED\r\n")
450
+ end
451
+ rescue => e
452
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
453
+ send_data("#{msg}\r\n")
454
+ @log.error("#{e} #{$@}")
455
+ end
456
+
457
+ def ev_alist_sized_delete_and_prepend(s); ev_alist_swap_and_sized_insert(s); end
458
+
459
+ # alist_swap_and_sized_insert <key> <array-size> <bytes> [forward]\r\n
460
+ # <data block>\r\n
461
+ #
462
+ # (STORED|NOT_STORED|SERVER_ERROR <error message>)\r\n
463
+ def ev_alist_swap_and_sized_insert(s)
464
+ hname, k, d, vn, nodes = calc_hash(s[1])
465
+ data = read_bytes(s[3].to_i)
466
+ read_bytes(2)
467
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
468
+
469
+ ddata = @storages[hname].get(vn, k, d)
470
+ if ddata
471
+ v = Marshal.load(ddata)
472
+ else
473
+ v = [[],[]]
474
+ end
475
+
476
+ idx = v[0].index(data)
477
+ if idx
478
+ v[0].delete_at(idx)
479
+ v[1].delete_at(idx)
480
+ end
481
+ v[0].insert(0,data)
482
+ v[1].insert(0,Time.now.to_i)
483
+ v[0] = v[0][0..(s[2].to_i - 1)]
484
+ v[1] = v[1][0..(s[2].to_i - 1)]
485
+
486
+ expt = 0x7fffffff
487
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
488
+ @stats.write_count += 1
489
+
490
+ Roma::WriteBehindProcess::push(hname, 1, k, data)
491
+
492
+ if ret
493
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
494
+ send_data("STORED\r\n")
495
+ else
496
+ send_data("NOT_STORED\r\n")
497
+ end
498
+ rescue => e
499
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
500
+ send_data("#{msg}\r\n")
501
+ @log.error("#{e} #{$@}")
502
+ end
503
+
504
+ # alist_expired_swap_and_insert <key> <expire-time> <bytes> [forward]\r\n
505
+ # <data block>\r\n
506
+ #
507
+ # the data expire-time's ago will be deleated.
508
+ # the unit of the expire-time's is a second.
509
+ # however,as follows when there is a suffix.
510
+ # 'h' as +expire-time+ suffix is hour.
511
+ # 'd' as +expire-time+ suffix is day.
512
+ #
513
+ # (STORED|NOT_STORED|SERVER_ERROR <error message>)\r\n
514
+ def ev_alist_expired_swap_and_insert(s)
515
+ hname, k, d, vn, nodes = calc_hash(s[1])
516
+ data = read_bytes(s[3].to_i)
517
+ read_bytes(2)
518
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
519
+
520
+ et = expired_str_to_i(s[2])
521
+ return send_data("SERVER_ERROR format error in expire-time.\r\n") unless et
522
+
523
+ v = to_alist_value_for_write(hname, vn, k, d)
524
+ unless v
525
+ return send_data("SERVER_ERROR data other than alist's format already exist.\r\n")
526
+ end
527
+
528
+ # @log.debug("#{s[2]} et=#{et}")
529
+ v = expired_swap(v, data, et)
530
+
531
+ v[0].insert(0,data)
532
+ v[1].insert(0,Time.now.to_i)
533
+
534
+ expt = 0x7fffffff
535
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
536
+ @stats.write_count += 1
537
+
538
+ Roma::WriteBehindProcess::push(hname, 1, k, data)
539
+
540
+ if ret
541
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
542
+ send_data("STORED\r\n")
543
+ else
544
+ send_data("NOT_STORED\r\n")
545
+ end
546
+ rescue => e
547
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
548
+ send_data("#{msg}\r\n")
549
+ @log.error("#{e} #{$@}")
550
+ end
551
+
552
+ # alist_expired_swap_and_sized_insert <key> <expire-time> <array-size> <bytes> [forward]\r\n
553
+ # <data block>\r\n
554
+ #
555
+ # the data expire-time's ago will be deleated.
556
+ # the unit of the expire-time's is a second.
557
+ # however,as follows when there is a suffix.
558
+ # 'h' as +expire-time+ suffix is hour.
559
+ # 'd' as +expire-time+ suffix is day.
560
+ #
561
+ # (STORED|NOT_STORED|SERVER_ERROR <error message>)\r\n
562
+ def ev_alist_expired_swap_and_sized_insert(s)
563
+ hname, k, d, vn, nodes = calc_hash(s[1])
564
+ data = read_bytes(s[4].to_i)
565
+ read_bytes(2)
566
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
567
+
568
+ et = expired_str_to_i(s[2])
569
+ return send_data("SERVER_ERROR format error in expire-time.\r\n") unless et
570
+
571
+ v = to_alist_value_for_write(hname, vn, k, d)
572
+ unless v
573
+ return send_data("SERVER_ERROR data other than alist's format already exist.\r\n")
574
+ end
575
+
576
+ # @log.debug("#{s[2]} et=#{et}")
577
+ v = expired_swap(v, data, et)
578
+
579
+ v[0].insert(0,data)
580
+ v[0] = v[0][0..(s[3].to_i - 1)]
581
+ v[1].insert(0,Time.now.to_i)
582
+ v[1] = v[1][0..(s[3].to_i - 1)]
583
+
584
+ expt = 0x7fffffff
585
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
586
+ @stats.write_count += 1
587
+
588
+ Roma::WriteBehindProcess::push(hname, 1, k, data)
589
+
590
+ if ret
591
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
592
+ send_data("STORED\r\n")
593
+ else
594
+ send_data("NOT_STORED\r\n")
595
+ end
596
+ rescue => e
597
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
598
+ send_data("#{msg}\r\n")
599
+ @log.error("#{e} #{$@}")
600
+ end
601
+
602
+
603
+ # alist_join_with_time <key> <bytes> [index|range] [forward]\r\n
604
+ # <separator block>\r\n
605
+ #
606
+ # (
607
+ # [VALUE <key> 0 <length of length string>\r\n
608
+ # <length string>\r\n
609
+ # VALUE <key> 0 <value length>\r\n
610
+ # <value string>\r\n
611
+ # VALUE <key> 0 <value length>\r\n
612
+ # <time string>\r\n]
613
+ # END\r\n
614
+ # |SERVER_ERROR <error message>\r\n)
615
+ def ev_alist_join_with_time(s)
616
+ hname, k, d, vn, nodes = calc_hash(s[1])
617
+ data = read_bytes(s[2].to_i)
618
+ read_bytes(2)
619
+ return forward1(nodes[0], s, data) if nodes[0] != @nid
620
+
621
+ ddata = @storages[hname].get(vn, k, 0)
622
+ @stats.read_count += 1
623
+ if ddata
624
+ v = Marshal.load(ddata)
625
+ if /(?:^(\d+)$|^(\d+)..((?:-)?\d+)$)/ =~ s[3]
626
+ if $1
627
+ if v[0].length <= $1.to_i
628
+ return send_data("END\r\n")
629
+ end
630
+ v_buf = v[0][Range.new($1.to_i,$1.to_i)]
631
+ t_buf = v[1][Range.new($1.to_i,$1.to_i)]
632
+ else
633
+ v_buf = v[0][Range.new($2.to_i,$3.to_i)]
634
+ t_buf = v[1][Range.new($2.to_i,$3.to_i)]
635
+ end
636
+ else
637
+ v_buf = v[0]
638
+ t_buf = v[1]
639
+ end
640
+ len = v[0].length
641
+ v_ret = v_buf.join(data)
642
+ t_ret = t_buf.join(data)
643
+ send_data("VALUE #{s[1]} 0 #{len.to_s.length}\r\n#{len.to_s}\r\n")
644
+ send_data("VALUE #{s[1]} 0 #{v_ret.length}\r\n#{v_ret}\r\n")
645
+ return send_data("VALUE #{s[1]} 0 #{t_ret.length}\r\n#{t_ret}\r\nEND\r\n")
646
+ else
647
+ return send_data("END\r\n")
648
+ end
649
+ rescue => e
650
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
651
+ send_data("#{msg}\r\n")
652
+ @log.error("#{e} #{$@}")
653
+ end
654
+
655
+ # alist_join <key> <bytes> [index|range] [forward]\r\n
656
+ # <separator block>\r\n
657
+ #
658
+ # (
659
+ # [VALUE <key> 0 <length of length string>\r\n
660
+ # <length string>\r\n
661
+ # VALUE <key> 0 <value length>\r\n
662
+ # <value>\r\n]
663
+ # END\r\n
664
+ # |SERVER_ERROR <error message>\r\n)
665
+ def ev_alist_join(s)
666
+ hname, k, d, vn, nodes = calc_hash(s[1])
667
+ data = read_bytes(s[2].to_i)
668
+ read_bytes(2)
669
+ return forward1(nodes[0], s, data) if nodes[0] != @nid
670
+
671
+ ddata = @storages[hname].get(vn, k, 0)
672
+ @stats.read_count += 1
673
+
674
+ if ddata
675
+ v = Marshal.load(ddata)[0]
676
+ if /(?:^(\d+)$|^(\d+)..((?:-)?\d+)$)/ =~ s[3]
677
+ if $1
678
+ if v.length <= $1.to_i
679
+ return send_data("END\r\n")
680
+ end
681
+ buf = v[Range.new($1.to_i,$1.to_i)]
682
+ else
683
+ buf = v[Range.new($2.to_i,$3.to_i)]
684
+ end
685
+ else
686
+ buf = v
687
+ end
688
+ len = v.length
689
+ ret = buf.join(data)
690
+ send_data("VALUE #{s[1]} 0 #{len.to_s.length}\r\n#{len.to_s}\r\n")
691
+ return send_data("VALUE #{s[1]} 0 #{ret.length}\r\n#{ret}\r\nEND\r\n")
692
+ else
693
+ return send_data("END\r\n")
694
+ end
695
+ rescue => e
696
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
697
+ send_data("#{msg}\r\n")
698
+ @log.error("#{e} #{$@}")
699
+ end
700
+
701
+ # alist_to_json <key> [index|range] [forward]\r\n
702
+ #
703
+ # (
704
+ # VALUE <key> 0 <length of json string>\r\n
705
+ # <json string>\r\n
706
+ # END\r\n
707
+ # |SERVER_ERROR <error message>\r\n)
708
+ def ev_alist_to_json(s)
709
+ hname, k, d, vn, nodes = calc_hash(s[1])
710
+ return forward1(nodes[0], s) if nodes[0] != @nid
711
+
712
+ ddata = @storages[hname].get(vn, k, 0)
713
+ @stats.read_count += 1
714
+
715
+ if ddata
716
+ v = Marshal.load(ddata)[0]
717
+ ret = nil
718
+ if /(?:^(\d+)$|^(\d+)..((?:-)?\d+)$)/ =~ s[2]
719
+ if $1
720
+ if v.length <= $1.to_i
721
+ return send_data("END\r\n")
722
+ end
723
+ ret = JSON.generate(v[Range.new($1.to_i,$1.to_i)])
724
+ else
725
+ ret = JSON.generate(v[Range.new($2.to_i,$3.to_i)])
726
+ end
727
+ else
728
+ ret = JSON.generate(v)
729
+ end
730
+ return send_data("VALUE #{s[1]} 0 #{ret.length}\r\n#{ret}\r\nEND\r\n")
731
+ else
732
+ return send_data("END\r\n")
733
+ end
734
+ rescue => e
735
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
736
+ send_data("#{msg}\r\n")
737
+ @log.error("#{e} #{$@}")
738
+ end
739
+
740
+ # alist_last <key> [forward]\r\n
741
+ #
742
+ # (
743
+ # [VALUE <key> 0 <value length>\r\n
744
+ # <value>\r\n]
745
+ # END\r\n
746
+ # |SERVER_ERROR <error message>\r\n)
747
+ def ev_alist_last(s)
748
+ hname, k, d, vn, nodes = calc_hash(s[1])
749
+ return forward1(nodes[0], s) if nodes[0] != @nid
750
+
751
+ ddata = @storages[hname].get(vn, k, d)
752
+ @stats.read_count += 1
753
+
754
+ if ddata
755
+ v = Marshal.load(ddata)[0]
756
+ return send_data("END\r\n") if v.length == 0
757
+ ret = v.last
758
+ return send_data("VALUE #{s[1]} 0 #{ret.length}\r\n#{ret}\r\nEND\r\n")
759
+ else
760
+ return send_data("END\r\n")
761
+ end
762
+ rescue => e
763
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
764
+ send_data("#{msg}\r\n")
765
+ @log.error("#{e} #{$@}")
766
+ end
767
+
768
+ # alist_length <key> [forward]\r\n
769
+ #
770
+ # (<length>|NOT_FOUND|SERVER_ERROR <error message>)\r\n
771
+ def ev_alist_length(s)
772
+ hname, k, d, vn, nodes = calc_hash(s[1])
773
+ return forward2(nodes[0], s) if nodes[0] != @nid
774
+ ddata = @storages[hname].get(vn, k, d)
775
+ @stats.read_count += 1
776
+
777
+ return send_data("NOT_FOUND\r\n") unless ddata
778
+ v = Marshal.load(ddata)[0]
779
+ ret = v.length
780
+ send_data("#{ret}\r\n")
781
+ rescue => e
782
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
783
+ send_data("#{msg}\r\n")
784
+ @log.error("#{e} #{$@}")
785
+ end
786
+
787
+ # alist_pop <key> [forward]\r\n
788
+ #
789
+ # (
790
+ # [VALUE <key> 0 <value length>\r\n
791
+ # <value>\r\n]
792
+ # END
793
+ # |NOT_STORED|SERVER_ERROR <error message>)\r\n
794
+ def ev_alist_pop(s)
795
+ hname, k, d, vn, nodes = calc_hash(s[1])
796
+ return forward1(nodes[0], s) if nodes[0] != @nid
797
+
798
+ ddata = @storages[hname].get(vn, k, d)
799
+ if ddata
800
+ v = Marshal.load(ddata)
801
+ return send_data("END\r\n") if v[0].length ==0
802
+ else
803
+ return send_data("END\r\n")
804
+ end
805
+
806
+ retv = v[0].pop
807
+ v[1].pop
808
+ expt = 0x7fffffff
809
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
810
+ @stats.read_count += 1
811
+ @stats.write_count += 1
812
+
813
+ if ret
814
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
815
+ send_data("VALUE #{s[1]} 0 #{retv.length}\r\n#{retv}\r\nEND\r\n")
816
+ else
817
+ send_data("NOT_STORED\r\n")
818
+ end
819
+ rescue => e
820
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
821
+ send_data("#{msg}\r\n")
822
+ @log.error("#{e} #{$@}")
823
+ end
824
+
825
+ # alist_push <key> <bytes> [forward]\r\n
826
+ # <data block>\r\n
827
+ #
828
+ # (STORED|NOT_STORED|SERVER_ERROR <error message>)\r\n
829
+ def ev_alist_push(s)
830
+ hname, k, d, vn, nodes = calc_hash(s[1])
831
+ data = read_bytes(s[2].to_i)
832
+ read_bytes(2)
833
+ if nodes[0] != @nid
834
+ @log.debug("forward to #{nodes[0]}");
835
+ return forward2(nodes[0], s, data)
836
+ end
837
+
838
+ ddata = @storages[hname].get(vn, k, d)
839
+ if ddata
840
+ v = Marshal.load(ddata)
841
+ else
842
+ v = [[],[]]
843
+ end
844
+
845
+ v[0].push(data)
846
+ v[1].push(Time.now.to_i)
847
+ expt = 0x7fffffff
848
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
849
+ @stats.write_count += 1
850
+
851
+ if ret
852
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
853
+ send_data("STORED\r\n")
854
+ else
855
+ send_data("NOT_STORED\r\n")
856
+ end
857
+ rescue => e
858
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
859
+ send_data("#{msg}\r\n")
860
+ @log.error("#{e} #{$@}")
861
+ end
862
+
863
+ # alist_sized_push <key> <array-size> <bytes> [forward]\r\n
864
+ # <data block>\r\n
865
+ #
866
+ # (STORED|NOT_PUSHED|NOT_STORED|SERVER_ERROR <error message>)\r\n
867
+ def ev_alist_sized_push(s)
868
+ hname, k, d, vn, nodes = calc_hash(s[1])
869
+ data = read_bytes(s[3].to_i)
870
+ read_bytes(2)
871
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
872
+
873
+ ddata = @storages[hname].get(vn, k, d)
874
+ if ddata
875
+ v = Marshal.load(ddata)
876
+ else
877
+ v = [[],[]]
878
+ end
879
+
880
+ max = s[2].to_i
881
+ return send_data("NOT_PUSHED\r\n") if v[0].length >= max
882
+
883
+ v[0].push(data)
884
+ v[0] = v[0][0..(max - 1)]
885
+ v[1].push(Time.now.to_i)
886
+ v[1] = v[1][0..(max - 1)]
887
+
888
+ expt = 0x7fffffff
889
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
890
+ @stats.write_count += 1
891
+
892
+ if ret
893
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
894
+ send_data("STORED\r\n")
895
+ else
896
+ send_data("NOT_STORED\r\n")
897
+ end
898
+ rescue => e
899
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
900
+ send_data("#{msg}\r\n")
901
+ @log.error("#{e} #{$@}")
902
+ end
903
+
904
+ # alist_swap_and_push <key> <bytes> [forward]\r\n
905
+ # <data block>\r\n
906
+ #
907
+ # (STORED|NOT_STORED|SERVER_ERROR <error message>)\r\n
908
+ def ev_alist_swap_and_push(s)
909
+ hname, k, d, vn, nodes = calc_hash(s[1])
910
+ data = read_bytes(s[2].to_i)
911
+ read_bytes(2)
912
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
913
+
914
+ ddata = @storages[hname].get(vn, k, d)
915
+ if ddata
916
+ v = Marshal.load(ddata)
917
+ else
918
+ v = [[],[]]
919
+ end
920
+
921
+ idx = v[0].index(data)
922
+ if idx
923
+ v[0].delete_at(idx)
924
+ v[1].delete_at(idx)
925
+ end
926
+ v[0].push(data)
927
+ v[1].push(Time.now.to_i)
928
+
929
+ expt = 0x7fffffff
930
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
931
+ @stats.write_count += 1
932
+
933
+ if ret
934
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
935
+ send_data("STORED\r\n")
936
+ else
937
+ send_data("NOT_STORED\r\n")
938
+ end
939
+ rescue => e
940
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
941
+ send_data("#{msg}\r\n")
942
+ @log.error("#{e} #{$@}")
943
+ end
944
+
945
+ # alist_swap_and_sized_push <key> <array-size> <bytes> [forward]\r\n
946
+ # <data block>\r\n
947
+ #
948
+ # (STORED|NOT_PUSHED|NOT_STORED|SERVER_ERROR <error message>)\r\n
949
+ def ev_alist_swap_and_sized_push(s)
950
+ hname, k, d, vn, nodes = calc_hash(s[1])
951
+ data = read_bytes(s[3].to_i)
952
+ read_bytes(2)
953
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
954
+
955
+ ddata = @storages[hname].get(vn, k, d)
956
+ if ddata
957
+ v = Marshal.load(ddata)
958
+ else
959
+ v = [[],[]]
960
+ end
961
+
962
+ max = s[2].to_i
963
+
964
+ idx = v[0].index(data)
965
+ if idx
966
+ v[0].delete_at(idx)
967
+ v[1].delete_at(idx)
968
+ else
969
+ return send_data("NOT_PUSHED\r\n") if v[0].length >= max
970
+ end
971
+ v[0].push(data)
972
+ v[0] = v[0][0..(max - 1)]
973
+ v[1].push(Time.now.to_i)
974
+ v[1] = v[1][0..(max - 1)]
975
+
976
+ expt = 0x7fffffff
977
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
978
+ @stats.write_count += 1
979
+
980
+ if ret
981
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
982
+ send_data("STORED\r\n")
983
+ else
984
+ send_data("NOT_STORED\r\n")
985
+ end
986
+ rescue => e
987
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
988
+ send_data("#{msg}\r\n")
989
+ @log.error("#{e} #{$@}")
990
+ end
991
+
992
+ # alist_expired_swap_and_push <key> <expire-time> <bytes> [forward]\r\n
993
+ # <data block>\r\n
994
+ #
995
+ # the data expire-time's ago will be deleated.
996
+ # the unit of the expire-time's is a second.
997
+ # however,as follows when there is a suffix.
998
+ # 'h' as +expire-time+ suffix is hour.
999
+ # 'd' as +expire-time+ suffix is day.
1000
+ #
1001
+ # (STORED|NOT_STORED|SERVER_ERROR <error message>)\r\n
1002
+ def ev_alist_expired_swap_and_push(s)
1003
+ hname, k, d, vn, nodes = calc_hash(s[1])
1004
+ data = read_bytes(s[3].to_i)
1005
+ read_bytes(2)
1006
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
1007
+
1008
+ et = expired_str_to_i(s[2])
1009
+ return send_data("SERVER_ERROR format error in expire-time.\r\n") unless et
1010
+
1011
+ v = to_alist_value_for_write(hname, vn, k, d)
1012
+ unless v
1013
+ return send_data("SERVER_ERROR data other than alist's format already exist.\r\n")
1014
+ end
1015
+
1016
+ # @log.debug("#{s[2]} et=#{et}")
1017
+ v = expired_swap(v, data, et)
1018
+
1019
+ v[0].push(data)
1020
+ v[1].push(Time.now.to_i)
1021
+
1022
+ expt = 0x7fffffff
1023
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
1024
+ @stats.write_count += 1
1025
+
1026
+ if ret
1027
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
1028
+ send_data("STORED\r\n")
1029
+ else
1030
+ send_data("NOT_STORED\r\n")
1031
+ end
1032
+ rescue => e
1033
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
1034
+ send_data("#{msg}\r\n")
1035
+ @log.error("#{e} #{$@}")
1036
+ end
1037
+
1038
+ # alist_expired_swap_and_sized_push <key> <expire-time> <array-size> <bytes> [forward]\r\n
1039
+ # <data block>\r\n
1040
+ #
1041
+ # the data expire-time's ago will be deleated.
1042
+ # the unit of the expire-time's is a second.
1043
+ # however,as follows when there is a suffix.
1044
+ # 'h' as +expire-time+ suffix is hour.
1045
+ # 'd' as +expire-time+ suffix is day.
1046
+ #
1047
+ # (STORED|NOT_STORED|SERVER_ERROR <error message>)\r\n
1048
+ def ev_alist_expired_swap_and_sized_push(s)
1049
+ hname, k, d, vn, nodes = calc_hash(s[1])
1050
+ data = read_bytes(s[4].to_i)
1051
+ read_bytes(2)
1052
+ return forward2(nodes[0], s, data) if nodes[0] != @nid
1053
+
1054
+ et = expired_str_to_i(s[2])
1055
+ return send_data("SERVER_ERROR format error in expire-time.\r\n") unless et
1056
+
1057
+ v = to_alist_value_for_write(hname, vn, k, d)
1058
+ unless v
1059
+ return send_data("SERVER_ERROR data other than alist's format already exist.\r\n")
1060
+ end
1061
+
1062
+ # @log.debug("#{s[2]} et=#{et}")
1063
+ v = expired_swap(v, data, et)
1064
+
1065
+ max = s[3].to_i
1066
+ return send_data("NOT_PUSHED\r\n") if v[0].length >= max
1067
+
1068
+ v[0].push(data)
1069
+ v[0] = v[0][0..(max - 1)]
1070
+ v[1].push(Time.now.to_i)
1071
+ v[1] = v[1][0..(max - 1)]
1072
+
1073
+ expt = 0x7fffffff
1074
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
1075
+ @stats.write_count += 1
1076
+
1077
+ if ret
1078
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
1079
+ send_data("STORED\r\n")
1080
+ else
1081
+ send_data("NOT_STORED\r\n")
1082
+ end
1083
+ rescue => e
1084
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
1085
+ send_data("#{msg}\r\n")
1086
+ @log.error("#{e} #{$@}")
1087
+ end
1088
+
1089
+
1090
+ # alist_shift <key> [forward]\r\n
1091
+ #
1092
+ # (
1093
+ # [VALUE <key> 0 <value length>\r\n
1094
+ # <value>\r\n]
1095
+ # END
1096
+ # |NOT_STORED|SERVER_ERROR <error message>)\r\n
1097
+ def ev_alist_shift(s)
1098
+ hname, k, d, vn, nodes = calc_hash(s[1])
1099
+ return forward1(nodes[0], s) if nodes[0] != @nid
1100
+
1101
+ ddata = @storages[hname].get(vn, k, d)
1102
+ if ddata
1103
+ v = Marshal.load(ddata)
1104
+ return send_data("END\r\n") if v[0].length ==0
1105
+ else
1106
+ return send_data("END\r\n")
1107
+ end
1108
+
1109
+ retv = v[0].shift
1110
+ v[1].shift
1111
+ expt = 0x7fffffff
1112
+ ret = @storages[hname].set(vn, k, d, expt ,Marshal.dump(v))
1113
+ @stats.read_count += 1
1114
+ @stats.write_count += 1
1115
+
1116
+ if ret
1117
+ redundant(nodes[1..-1], hname, k, d, ret[2], expt, ret[4])
1118
+ send_data("VALUE #{s[1]} 0 #{retv.length}\r\n#{retv}\r\nEND\r\n")
1119
+ else
1120
+ send_data("NOT_STORED\r\n")
1121
+ end
1122
+ rescue => e
1123
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
1124
+ send_data("#{msg}\r\n")
1125
+ @log.error("#{e} #{$@}")
1126
+ end
1127
+
1128
+ # alist_to_s <key> [index|range] [forward]\r\n
1129
+ #
1130
+ # (
1131
+ # [VALUE <key> 0 <length of length string>\r\n
1132
+ # <length string>\r\n
1133
+ # VALUE <key> 0 <value length>\r\n
1134
+ # <value>\r\n]
1135
+ # END\r\n
1136
+ # |SERVER_ERROR <error message>\r\n)
1137
+ def ev_alist_to_s(s)
1138
+ hname, k, d, vn, nodes = calc_hash(s[1])
1139
+ return forward1(nodes[0], s) if nodes[0] != @nid
1140
+
1141
+ ddata = @storages[hname].get(vn, k, 0)
1142
+ @stats.read_count += 1
1143
+
1144
+ return send_data("END\r\n") unless ddata
1145
+ v = to_alist_value(ddata)
1146
+ if v
1147
+ ret = nil
1148
+ if /(?:^(\d+)$|^(\d+)..((?:-)?\d+)$)/ =~ s[2]
1149
+ if $1
1150
+ ret = v[0][Range.new($1.to_i,$1.to_i)].to_s
1151
+ else
1152
+ ret = v[0][Range.new($2.to_i,$3.to_i)].to_s
1153
+ end
1154
+ else
1155
+ ret = v[0].to_s
1156
+ end
1157
+ len = v[0].length
1158
+ send_data("VALUE #{s[1]} 0 #{len.to_s.length}\r\n#{len.to_s}\r\n")
1159
+ return send_data("VALUE #{s[1]} 0 #{ret.length}\r\n#{ret}\r\nEND\r\n")
1160
+ else
1161
+ return send_data("SERVER_ERROR data other than alist's format already exist.\r\n")
1162
+ end
1163
+ rescue => e
1164
+ msg = "SERVER_ERROR #{e} #{$@}".tr("\r\n"," ")
1165
+ send_data("#{msg}\r\n")
1166
+ @log.error("#{e} #{$@}")
1167
+ end
1168
+
1169
+
1170
+ # alist_spushv <hash-name> <vnode-id>
1171
+ # src dst
1172
+ # | ['alist_spushv' <hname> <vn>\r\n]->|
1173
+ # |<-['READY'\r\n] |
1174
+ # | [<dumpdata>]->|
1175
+ # | : |
1176
+ # | : |
1177
+ # | [<end of dump>]->|
1178
+ # |<-['STORED'\r\n] |
1179
+ def ev_alist_spushv(s)
1180
+ send_data("READY\r\n")
1181
+ @stats.run_receive_a_vnode = true
1182
+ count = 0
1183
+ loop {
1184
+ context_bin = read_bytes(20, 100)
1185
+ vn, last, clk, expt, klen = context_bin.unpack('NNNNN')
1186
+ break if klen == 0 # end of dump ?
1187
+ k = read_bytes(klen)
1188
+ vlen_bin = read_bytes(4, 100)
1189
+ vlen, = vlen_bin.unpack('N')
1190
+ v = read_bytes(vlen, 100)
1191
+ val = to_alist_value(v)
1192
+ if val
1193
+ # @log.debug("listdata #{vn} #{k} #{val.inspect}")
1194
+ count += 1 if merge_list(s[1], vn, last, clk, expt, k, v, val)
1195
+ else
1196
+ # @log.debug("not listdata #{vn} #{k} #{val}")
1197
+ count += 1 if @storages[s[1]].load_stream_dump(vn, last, clk, expt, k, v)
1198
+ end
1199
+ }
1200
+ send_data("STORED\r\n")
1201
+ @log.debug("alist #{count} keys loaded.")
1202
+ rescue => e
1203
+ @log.error("#{e}\n#{$@}")
1204
+ ensure
1205
+ @stats.run_receive_a_vnode = false
1206
+ end
1207
+
1208
+ private
1209
+
1210
+ def expired_swap(v, rcv_val, et)
1211
+ del = [rcv_val]
1212
+ expt = Time.now.to_i - et
1213
+ v[1].each_with_index{|t,i|
1214
+ # @log.debug("v=#{v[0][i]} expt=#{expt} t=#{t} #{expt >= t}")
1215
+ del << v[0][i] if expt >= t
1216
+ }
1217
+ del.each{|dat|
1218
+ i = v[0].index(dat)
1219
+ if i
1220
+ v[0].delete_at(i)
1221
+ v[1].delete_at(i)
1222
+ end
1223
+ }
1224
+ v
1225
+ end
1226
+
1227
+ def expired_str_to_i(s)
1228
+ if s.upcase =~ /(\d+)([H|D])?/
1229
+ t = $1.to_i
1230
+ if $2 == 'D'
1231
+ t *= 86400
1232
+ elsif $2 == 'H'
1233
+ t *= 3600
1234
+ end
1235
+ t
1236
+ else
1237
+ nil
1238
+ end
1239
+ end
1240
+
1241
+ def to_alist_value_for_write(hname, vn, k, d)
1242
+ ddata = @storages[hname].get(vn, k, d)
1243
+ unless ddata
1244
+ v = [[],[]]
1245
+ else
1246
+ v = to_alist_value(ddata)
1247
+ end
1248
+ end
1249
+
1250
+ def to_alist_value(v)
1251
+ # Marshal.dump([[],[]])[0..3].unpack("cc a c")
1252
+ # => [4, 8, "[", 7]
1253
+ # marshal format version 4.8
1254
+ # array object "["
1255
+ # array.length fixednum format 7 (7-5=2)
1256
+ return nil if v == nil || v[0..3] != "\x04\b[\a"
1257
+ val = Marshal.load(v)
1258
+ if val[0].instance_of?(Array) && val[1].instance_of?(Array)
1259
+ return val
1260
+ else
1261
+ return nil
1262
+ end
1263
+ rescue
1264
+ nil
1265
+ end
1266
+
1267
+ def merge_list(hname, vn, last, clk, expt, k, v, val)
1268
+ ddata = @storages[hname].get(vn, k, 0)
1269
+ if ddata
1270
+ lv = Marshal.load(ddata)
1271
+ lv[0].each{|buf|
1272
+ idx = val[0].index(buf)
1273
+ if idx
1274
+ val[0].delete_at(idx)
1275
+ val[1].delete_at(idx)
1276
+ end
1277
+ }
1278
+ lv[0] += val[0]
1279
+ lv[1] += val[1]
1280
+ @storages[hname].set(vn, k, 0, expt ,Marshal.dump(lv))
1281
+ else
1282
+ @storages[hname].load_stream_dump(vn, last, clk, expt, k, v)
1283
+ end
1284
+ end
1285
+
1286
+ def calc_hash(key)
1287
+ k,hname = key.split("\e")
1288
+ hname ||= @defhash
1289
+ d = Digest::SHA1.hexdigest(k).hex % @rttable.hbits
1290
+ vn = @rttable.get_vnode_id(d)
1291
+ nodes = @rttable.search_nodes_for_write(vn)
1292
+ [hname, k, d, vn, nodes]
1293
+ end
1294
+
1295
+ # for a several lines received command
1296
+ def forward1(nid, rs, data=nil)
1297
+ if rs.last == "forward"
1298
+ return send_data("SERVER_ERROR Routing table is inconsistent.\r\n")
1299
+ end
1300
+
1301
+ buf = ''
1302
+ rs.each{|ss| buf << "#{ss} " }
1303
+ buf << "forward\r\n"
1304
+ if data
1305
+ buf << data
1306
+ buf << "\r\n"
1307
+ end
1308
+
1309
+ con = get_connection(nid)
1310
+ con.send(buf)
1311
+
1312
+ res = ''
1313
+ while (buf = con.gets)!="END\r\n"
1314
+ res << buf
1315
+ s = buf.split(/ /)
1316
+ if s[0] != 'VALUE'
1317
+ return send_data(buf)
1318
+ end
1319
+ res << con.read_bytes(s[3].to_i + 2)
1320
+ end
1321
+ res << "END\r\n"
1322
+
1323
+ return_connection(nid, con)
1324
+ @rttable.proc_succeed(nid)
1325
+ if res
1326
+ send_data(res)
1327
+ else
1328
+ send_data("SERVER_ERROR Message forward failed.\r\n")
1329
+ end
1330
+ rescue => e
1331
+ @rttable.proc_failed(nid)
1332
+ @log.error("forward get failed:nid=#{nid} rs=#{rs} #{e} #{$@}")
1333
+ send_data("SERVER_ERROR Message forward failed.\r\n")
1334
+ end
1335
+
1336
+ # for a one line reveived command
1337
+ def forward2(nid, rs, data=nil)
1338
+ if rs.last == "forward"
1339
+ return send_data("SERVER_ERROR Routing table is inconsistent.\r\n")
1340
+ end
1341
+
1342
+ buf = ''
1343
+ rs.each{|ss| buf << "#{ss} " }
1344
+ buf << "forward\r\n"
1345
+ if data
1346
+ buf << data
1347
+ buf << "\r\n"
1348
+ end
1349
+
1350
+ res = send_cmd(nid, buf)
1351
+ return send_data("#{res}\r\n") if res
1352
+ return send_data("SERVER_ERROR Message forward failed.\r\n")
1353
+ end
1354
+
1355
+ end # PluginAshiatoList
1356
+ end # CommandPlugin
1357
+
1358
+
1359
+ module ClientPlugin
1360
+
1361
+ module PluginAshiatoList
1362
+
1363
+ def alist_at(key, index)
1364
+ ret = sender(:value_list_receiver, key, nil, "alist_at %s #{index}")
1365
+ return nil if ret.length == 0
1366
+ ret[0]
1367
+ end
1368
+
1369
+ def alist_clear(key)
1370
+ sender(:oneline_receiver, key, nil, "alist_clear %s")
1371
+ end
1372
+
1373
+ def alist_delete(key, value)
1374
+ value_validator(value)
1375
+ sender(:oneline_receiver, key, value, "alist_delete %s #{value.length}")
1376
+ end
1377
+
1378
+ def alist_delete_at(key, index)
1379
+ sender(:oneline_receiver, key, nil, "alist_delete_at %s #{index}")
1380
+ end
1381
+
1382
+ def alist_empty?(key)
1383
+ sender(:oneline_receiver, key, nil, "alist_empty? %s")
1384
+ end
1385
+
1386
+ def alist_first(key)
1387
+ ret = sender(:value_list_receiver, key, nil, "alist_first %s")
1388
+ return nil if ret.length == 0
1389
+ ret[0]
1390
+ end
1391
+
1392
+ def alist_gets(key, range=nil)
1393
+ if range
1394
+ ret = sender(:value_list_receiver, key, nil, "alist_gets %s #{range}")
1395
+ else
1396
+ ret = sender(:value_list_receiver, key, nil, "alist_gets %s")
1397
+ end
1398
+ return nil if ret.length == 0
1399
+ ret[0] = ret[0].to_i
1400
+ ret
1401
+ end
1402
+
1403
+ def alist_gets_with_time(key, range=nil)
1404
+ if range
1405
+ ret = sender(:value_list_receiver, key, nil, "alist_gets_with_time %s #{range}")
1406
+ else
1407
+ ret = sender(:value_list_receiver, key, nil, "alist_gets_with_time %s")
1408
+ end
1409
+ return nil if ret.length == 0
1410
+ ret[0] = ret[0].to_i
1411
+ ret
1412
+ end
1413
+
1414
+ def alist_include?(key, value)
1415
+ sender(:oneline_receiver, key, value, "alist_include? %s #{value.length}")
1416
+ end
1417
+
1418
+ def alist_index(key, value)
1419
+ value_validator(value)
1420
+ ret = sender(:oneline_receiver, key, value, "alist_index %s #{value.length}")
1421
+ return ret.to_i if ret =~ /\d+/
1422
+ return nil if ret=='nil'
1423
+ ret
1424
+ end
1425
+
1426
+ def alist_insert(key, index, value)
1427
+ value_validator(value)
1428
+ sender(:oneline_receiver, key, value, "alist_insert %s #{index} #{value.length}")
1429
+ end
1430
+
1431
+ def alist_sized_insert(key, array_size, value)
1432
+ sender(:oneline_receiver, key, value, "alist_sized_insert %s #{array_size} #{value.length}")
1433
+ end
1434
+
1435
+ def alist_swap_and_insert(key, value)
1436
+ sender(:oneline_receiver, key, value, "alist_swap_and_insert %s #{value.length}")
1437
+ end
1438
+
1439
+ def alist_swap_and_sized_insert(key, array_size, value)
1440
+ value_validator(value)
1441
+ sender(:oneline_receiver, key, value, "alist_swap_and_sized_insert %s #{array_size} #{value.length}")
1442
+ end
1443
+
1444
+ def alist_expired_swap_and_insert(key, expt, value)
1445
+ value_validator(value)
1446
+ sender(:oneline_receiver, key, value,
1447
+ "alist_expired_swap_and_insert %s #{expt} #{value.length}")
1448
+ end
1449
+
1450
+ def alist_expired_swap_and_sized_insert(key, expt, array_size, value)
1451
+ value_validator(value)
1452
+ sender(:oneline_receiver, key, value,
1453
+ "alist_expired_swap_and_sized_insert %s #{expt} #{array_size} #{value.length}")
1454
+ end
1455
+
1456
+ def alist_join(key, sep, range=nil)
1457
+ if range
1458
+ ret = sender(:value_list_receiver, key, sep, "alist_join %s #{sep.length} #{range}")
1459
+ else
1460
+ ret = sender(:value_list_receiver, key, sep, "alist_join %s #{sep.length}")
1461
+ end
1462
+ return nil if ret.length == 0
1463
+ ret[0] = ret[0].to_i
1464
+ ret
1465
+ end
1466
+
1467
+ def alist_join_with_time(key, sep, range=nil)
1468
+ if range
1469
+ ret = sender(:value_list_receiver, key, sep,
1470
+ "alist_join_with_time %s #{sep.length} #{range}")
1471
+ else
1472
+ ret = sender(:value_list_receiver, key, sep,
1473
+ "alist_join_with_time %s #{sep.length}")
1474
+ end
1475
+ return nil if ret.length == 0
1476
+ ret[0] = ret[0].to_i
1477
+ ret
1478
+ end
1479
+
1480
+ def alist_to_json(key, range=nil)
1481
+ if range
1482
+ ret = sender(:value_list_receiver, key, nil, "alist_to_json %s #{range}")
1483
+ else
1484
+ ret = sender(:value_list_receiver, key, nil, "alist_to_json %s")
1485
+ end
1486
+ return nil if ret.length == 0
1487
+ ret[0]
1488
+ end
1489
+
1490
+ def alist_last(key)
1491
+ ret = sender(:value_list_receiver, key, nil, "alist_last %s")
1492
+ return nil if ret.length == 0
1493
+ ret[0]
1494
+ end
1495
+
1496
+ def alist_length(key)
1497
+ ret = sender(:oneline_receiver, key, nil, "alist_length %s")
1498
+ return ret.to_i if ret =~ /\d+/
1499
+ ret
1500
+ end
1501
+
1502
+ def alist_pop(key)
1503
+ ret = sender(:value_list_receiver, key, nil, "alist_pop %s")
1504
+ return nil if ret.length == 0
1505
+ ret[0]
1506
+ end
1507
+
1508
+ def alist_push(key, value)
1509
+ value_validator(value)
1510
+ sender(:oneline_receiver, key, value, "alist_push %s #{value.length}")
1511
+ end
1512
+
1513
+ def alist_sized_push(key, array_size, value)
1514
+ value_validator(value)
1515
+ sender(:oneline_receiver, key, value,
1516
+ "alist_sized_push %s #{array_size} #{value.length}")
1517
+ end
1518
+
1519
+ def alist_swap_and_push(key, value)
1520
+ value_validator(value)
1521
+ sender(:oneline_receiver, key, value, "alist_swap_and_push %s #{value.length}")
1522
+ end
1523
+
1524
+ def alist_swap_and_sized_push(key, array_size, value)
1525
+ value_validator(value)
1526
+ sender(:oneline_receiver, key, value,
1527
+ "alist_swap_and_sized_push %s #{array_size} #{value.length}")
1528
+ end
1529
+
1530
+ def alist_expired_swap_and_push(key, expt, value)
1531
+ value_validator(value)
1532
+ sender(:oneline_receiver, key, value,
1533
+ "alist_expired_swap_and_push %s #{expt} #{value.length}")
1534
+ end
1535
+
1536
+ def alist_expired_swap_and_sized_push(key, expt, array_size, value)
1537
+ value_validator(value)
1538
+ sender(:oneline_receiver, key, value,
1539
+ "alist_expired_swap_and_sized_push %s #{expt} #{array_size} #{value.length}")
1540
+ end
1541
+
1542
+ def alist_shift(key)
1543
+ ret = sender(:value_list_receiver, key, nil, "alist_shift %s")
1544
+ return nil if ret.length == 0
1545
+ ret[0]
1546
+ end
1547
+
1548
+ def alist_to_s(key, range=nil)
1549
+ if range
1550
+ ret = sender(:value_list_receiver, key, nil, "alist_to_s %s #{range}")
1551
+ else
1552
+ ret = sender(:value_list_receiver, key, nil, "alist_to_s %s")
1553
+ end
1554
+ return ret if ret.instance_of?(String)
1555
+ return nil if ret.length == 0
1556
+ ret[0] = ret[0].to_i
1557
+ ret[1] = eval(ret[1])
1558
+ ret
1559
+ end
1560
+
1561
+ private
1562
+
1563
+ def value_validator(value)
1564
+ if value == nil || !value.instance_of?(String)
1565
+ raise "value must be a String object."
1566
+ end
1567
+ end
1568
+
1569
+ end # PluginAshiatoList
1570
+ end # ClientPlugin
1571
+
1572
+ end # Roma