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.
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