ls4 0.9.0

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 (100) hide show
  1. data/AUTHORS +1 -0
  2. data/COPYING +661 -0
  3. data/ChangeLog +9 -0
  4. data/NOTICE +8 -0
  5. data/README.rdoc +61 -0
  6. data/bin/ls4-cs +3 -0
  7. data/bin/ls4-ds +3 -0
  8. data/bin/ls4-gw +3 -0
  9. data/bin/ls4-standalone +3 -0
  10. data/bin/ls4cmd +3 -0
  11. data/bin/ls4ctl +3 -0
  12. data/bin/ls4rpc +3 -0
  13. data/bin/ls4stat +3 -0
  14. data/bin/ls4top +3 -0
  15. data/lib/ls4/command/cmd.rb +241 -0
  16. data/lib/ls4/command/cs.rb +190 -0
  17. data/lib/ls4/command/ctl.rb +278 -0
  18. data/lib/ls4/command/ds.rb +335 -0
  19. data/lib/ls4/command/gw.rb +256 -0
  20. data/lib/ls4/command/rpc.rb +172 -0
  21. data/lib/ls4/command/standalone.rb +318 -0
  22. data/lib/ls4/command/stat.rb +244 -0
  23. data/lib/ls4/command/top.rb +291 -0
  24. data/lib/ls4/default.rb +26 -0
  25. data/lib/ls4/lib/cclog.rb +220 -0
  26. data/lib/ls4/lib/ebus.rb +553 -0
  27. data/lib/ls4/lib/vbcode.rb +228 -0
  28. data/lib/ls4/logic/fault_detector.rb +212 -0
  29. data/lib/ls4/logic/membership.rb +253 -0
  30. data/lib/ls4/logic/node.rb +66 -0
  31. data/lib/ls4/logic/okey.rb +45 -0
  32. data/lib/ls4/logic/tsv_data.rb +81 -0
  33. data/lib/ls4/logic/weight.rb +166 -0
  34. data/lib/ls4/service/balance.rb +62 -0
  35. data/lib/ls4/service/base.rb +29 -0
  36. data/lib/ls4/service/bus.rb +37 -0
  37. data/lib/ls4/service/config.rb +63 -0
  38. data/lib/ls4/service/config_cs.rb +33 -0
  39. data/lib/ls4/service/config_ds.rb +56 -0
  40. data/lib/ls4/service/config_gw.rb +42 -0
  41. data/lib/ls4/service/data_client.rb +122 -0
  42. data/lib/ls4/service/data_server.rb +168 -0
  43. data/lib/ls4/service/data_server_url.rb +83 -0
  44. data/lib/ls4/service/gateway.rb +375 -0
  45. data/lib/ls4/service/gateway_ro.rb +91 -0
  46. data/lib/ls4/service/gw_http.rb +821 -0
  47. data/lib/ls4/service/heartbeat.rb +182 -0
  48. data/lib/ls4/service/log.rb +81 -0
  49. data/lib/ls4/service/master_select.rb +148 -0
  50. data/lib/ls4/service/mds.rb +292 -0
  51. data/lib/ls4/service/mds_cache.rb +294 -0
  52. data/lib/ls4/service/mds_cache_mem.rb +63 -0
  53. data/lib/ls4/service/mds_cache_memcached.rb +65 -0
  54. data/lib/ls4/service/mds_ha.rb +176 -0
  55. data/lib/ls4/service/mds_memcache.rb +209 -0
  56. data/lib/ls4/service/mds_tc.rb +508 -0
  57. data/lib/ls4/service/mds_tt.rb +472 -0
  58. data/lib/ls4/service/membership.rb +331 -0
  59. data/lib/ls4/service/process.rb +90 -0
  60. data/lib/ls4/service/rpc.rb +50 -0
  61. data/lib/ls4/service/rpc_cs.rb +101 -0
  62. data/lib/ls4/service/rpc_ds.rb +96 -0
  63. data/lib/ls4/service/rpc_gw.rb +255 -0
  64. data/lib/ls4/service/rts.rb +94 -0
  65. data/lib/ls4/service/rts_file.rb +76 -0
  66. data/lib/ls4/service/rts_memory.rb +55 -0
  67. data/lib/ls4/service/slave.rb +132 -0
  68. data/lib/ls4/service/stat.rb +91 -0
  69. data/lib/ls4/service/stat_cs.rb +25 -0
  70. data/lib/ls4/service/stat_ds.rb +40 -0
  71. data/lib/ls4/service/stat_gw.rb +25 -0
  72. data/lib/ls4/service/storage.rb +116 -0
  73. data/lib/ls4/service/storage_dir.rb +201 -0
  74. data/lib/ls4/service/sync.rb +206 -0
  75. data/lib/ls4/service/time_check.rb +80 -0
  76. data/lib/ls4/service/ulog.rb +159 -0
  77. data/lib/ls4/service/ulog_file.rb +398 -0
  78. data/lib/ls4/service/ulog_memory.rb +53 -0
  79. data/lib/ls4/service/weight.rb +134 -0
  80. data/lib/ls4/version.rb +5 -0
  81. data/test/01_add_get_remove.rt +84 -0
  82. data/test/02_read.rt +61 -0
  83. data/test/03_getd_readd.rt +69 -0
  84. data/test/04_version_time.rt +170 -0
  85. data/test/05_version_name.rt +161 -0
  86. data/test/06_http_get_set_remove_1.rt +119 -0
  87. data/test/07_http_get_set_remove_2.rt +116 -0
  88. data/test/08_read_only_time.rt +177 -0
  89. data/test/09_read_only_name.rt +173 -0
  90. data/test/10_http_get_set_remove_3.rt +73 -0
  91. data/test/11_mds_cache_memcached.rt +88 -0
  92. data/test/12_mds_cache_local_memory.rt +86 -0
  93. data/test/13_memcache_mds.rt +84 -0
  94. data/test/14_delete.rt +63 -0
  95. data/test/15_standalone.rt +71 -0
  96. data/test/chukan.rb +516 -0
  97. data/test/common.rb +250 -0
  98. data/test/load_test.rb +79 -0
  99. data/test/load_test_offload.rb +86 -0
  100. metadata +295 -0
@@ -0,0 +1,472 @@
1
+ #
2
+ # LS4
3
+ # Copyright (C) 2010-2011 FURUHASHI Sadayuki
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+ module LS4
19
+
20
+
21
+ class TokyoTyrantMDS < MDS
22
+ MDSSelector.register(:tt, self)
23
+
24
+ COL_PK = ''
25
+ COL_KEY = '_key'
26
+ COL_VTIME = '_time'
27
+ COL_RSID = '_rsid'
28
+ COL_VNAME = '_vname'
29
+ COL_REMOVED = '_removed'
30
+
31
+ COLS_RESERVED = [COL_PK, COL_KEY, COL_VTIME, COL_RSID, COL_VNAME, COL_REMOVED]
32
+ COLS_REQUIRED = [COL_PK, COL_KEY, COL_VTIME, COL_RSID]
33
+
34
+ def self.define_consts
35
+ unless const_defined?(:QRY)
36
+ require 'tokyotyrant'
37
+ const_set(:QRY, TokyoTyrant::RDBQRY)
38
+ HADB.const_set(:TBL, TokyoTyrant::RDBTBL)
39
+ HADB.const_set(:FATAL_ERROR, [
40
+ TokyoTyrant::RDB::EINVALID,
41
+ TokyoTyrant::RDB::ENOHOST,
42
+ TokyoTyrant::RDB::EREFUSED,
43
+ TokyoTyrant::RDB::ESEND,
44
+ TokyoTyrant::RDB::ERECV,
45
+ TokyoTyrant::RDB::EMISC
46
+ ])
47
+ end
48
+ end
49
+
50
+ class HADB < BasicHADB
51
+ DEFAULT_PORT = 1978
52
+
53
+ def open_db(addr)
54
+ db = TBL.new
55
+ db.instance_eval("@enc = 'ASCII-8BIT'") # FIXME
56
+ unless db.open(*addr)
57
+ $log.warn "failed to connect TokyoTyrant MDS: #{addr}"
58
+ end
59
+ db.setindex(COL_KEY, TBL::ITLEXICAL)
60
+ db
61
+ end
62
+
63
+ def ensure_db(db, addr)
64
+ if FATAL_ERROR.include?(db.ecode)
65
+ db.close rescue nil
66
+ db.instance_eval("@ecode = ESUCCESS") # FIXME
67
+ db.open(*addr)
68
+ end
69
+ return db
70
+ rescue
71
+ return nil
72
+ end
73
+
74
+ def error_result?(db, result)
75
+ if FATAL_ERROR.include?(db.ecode)
76
+ return db.errmsg(db.ecode)
77
+ end
78
+ return nil
79
+ end
80
+ end
81
+
82
+ if defined?(Random)
83
+ def initialize
84
+ self.class.define_consts
85
+ @random = Random.new
86
+ @pid = Process.pid
87
+ end
88
+ else
89
+ # Ruby 1.8
90
+ class PseudoRandom
91
+ def rand(n)
92
+ Kernel::rand(n)
93
+ end
94
+ end
95
+ def initialize
96
+ self.class.define_consts
97
+ @random = PseudoRandom.new
98
+ @pid = Process.pid
99
+ end
100
+ end
101
+
102
+ def open(expr)
103
+ @hadb = HADB.new(expr)
104
+ end
105
+
106
+ def close
107
+ @hadb.close
108
+ end
109
+
110
+ def get_okey(key, version=nil, &cb)
111
+ map = get_impl(key, version, COLS_RESERVED)
112
+ if map && !is_removed(map)
113
+ okey = to_okey(map)
114
+ cb.call(okey, nil) rescue nil
115
+ else
116
+ cb.call(nil, nil) rescue nil
117
+ end
118
+ rescue
119
+ cb.call(nil, $!) rescue nil
120
+ end
121
+
122
+ def get_attrs(key, version=nil, &cb)
123
+ map = get_impl(key, version)
124
+ if map && !is_removed(map)
125
+ attrs = to_attrs(map)
126
+ cb.call(attrs, nil) rescue nil
127
+ else
128
+ cb.call(nil, nil) rescue nil
129
+ end
130
+ rescue
131
+ cb.call(nil, $!) rescue nil
132
+ end
133
+
134
+ def get_okey_attrs(key, version=nil, &cb)
135
+ map = get_impl(key, version)
136
+ if map && !is_removed(map)
137
+ okey = to_okey(map)
138
+ attrs = to_attrs(map)
139
+ cb.call([okey, attrs], nil) rescue nil
140
+ else
141
+ cb.call(nil, nil) rescue nil
142
+ end
143
+ rescue
144
+ cb.call(nil, $!) rescue nil
145
+ end
146
+
147
+ def add(key, attrs={}, vname=nil, &cb)
148
+ okey = add_impl(key, attrs, vname)
149
+ cb.call(okey, nil) rescue nil
150
+ rescue
151
+ cb.call(nil, $!) rescue nil
152
+ end
153
+
154
+ def update_attrs(key, attrs, &cb)
155
+ okey = update_impl(key) {|old_attrs|
156
+ attrs
157
+ }
158
+ cb.call(okey, nil) rescue nil
159
+ rescue
160
+ cb.call(nil, $!) rescue nil
161
+ end
162
+
163
+ #def merge_attrs(key, attrs, &cb)
164
+ # okey = update_impl(key) {|old_attrs|
165
+ # old_attrs.merge(attrs)
166
+ # }
167
+ # cb.call(okey, nil) rescue nil
168
+ #rescue
169
+ # cb.call(nil, $!) rescue nil
170
+ #end
171
+
172
+ def remove(key, &cb)
173
+ map = get_impl_head(key, COLS_REQUIRED)
174
+ if map && !is_removed(map)
175
+ okey = to_okey(map)
176
+
177
+ # optional: inherit rsid
178
+ rsid = map[COL_RSID].to_i
179
+
180
+ # get current vtime later than old vtime
181
+ vtime = get_current_vtime(map[COL_VTIME].to_i)
182
+
183
+ remove_okey = new_okey(key, vtime, rsid)
184
+
185
+ # insert
186
+ pk = new_pk(map[COL_PK])
187
+ map = to_map({}, remove_okey, nil, true)
188
+ @hadb.write(key) {|rdb| rdb.put(pk, map) }
189
+
190
+ cb.call(okey, nil) rescue nil
191
+
192
+ else
193
+ cb.call(nil, nil) rescue nil
194
+ end
195
+
196
+ rescue
197
+ cb.call(nil, $!) rescue nil
198
+ end
199
+
200
+ def delete(key, version=nil, &cb)
201
+ map = get_impl(key, version, COLS_RESERVED)
202
+ if map && !is_removed(map)
203
+ okey = to_okey(map)
204
+
205
+ pk = map[COL_PK]
206
+ @hadb.write(key) {|rdb| rdb.delete(pk) }
207
+
208
+ cb.call(okey, nil) rescue nil
209
+
210
+ else
211
+ cb.call(nil, nil) rescue nil
212
+ end
213
+ rescue
214
+ cb.call(nil, $!) rescue nil
215
+ end
216
+
217
+ def util_locate(key, &cb)
218
+ array = @hadb.read(key) {|rdb|
219
+ qry = QRY.new(rdb)
220
+ qry.addcond(COL_KEY, QRY::QCSTREQ, key)
221
+ qry.searchget(COLS_RESERVED)
222
+ }
223
+
224
+ array.reject! {|map|
225
+ !is_valid_map(map) || is_removed(map)
226
+ }
227
+
228
+ array.map! {|map|
229
+ [to_okey(map), map[COL_VNAME]]
230
+ }
231
+
232
+ cb.call(array, nil) rescue nil
233
+
234
+ rescue
235
+ cb.call(nil, $!) rescue nil
236
+ end
237
+
238
+ private
239
+ def to_okey(map)
240
+ key = map[COL_KEY]
241
+ rsid = map[COL_RSID].to_i
242
+ vtime = map[COL_VTIME].to_i
243
+ new_okey(key, vtime, rsid)
244
+ end
245
+
246
+ def to_attrs(map)
247
+ map.reject {|k,v| COLS_RESERVED.include?(k) }
248
+ end
249
+
250
+ def to_map(attrs, okey, vname=nil, removed=false)
251
+ map = attrs.dup
252
+ map.delete(COL_PK)
253
+ map[COL_KEY] = okey.key
254
+ map[COL_RSID] = okey.rsid.to_s
255
+ map[COL_VTIME] = okey.vtime.to_s
256
+ if vname
257
+ map[COL_VNAME] = vname.to_s
258
+ end
259
+ if removed
260
+ map[COL_REMOVED] = "1"
261
+ end
262
+ map
263
+ end
264
+
265
+ def get_impl(key, version=nil, cols=nil)
266
+ if version == nil
267
+ get_impl_head(key, cols)
268
+ elsif version.is_a?(String)
269
+ get_impl_vname(key, version, cols)
270
+ else
271
+ get_impl_vtime(key, version, cols)
272
+ end
273
+ end
274
+
275
+ def get_impl_head(key, cols=nil)
276
+ map = @hadb.read(key) {|rdb|
277
+ qry = QRY.new(rdb)
278
+ qry.addcond(COL_KEY, QRY::QCSTREQ, key)
279
+ qry.setorder(COL_VTIME, QRY::QONUMDESC)
280
+ qry.setlimit(1)
281
+ array = qry.searchget(cols)
282
+ array[0]
283
+ }
284
+
285
+ if map == nil
286
+ return nil
287
+ elsif !is_valid_map(map)
288
+ return nil
289
+ else
290
+ return map
291
+ end
292
+ end
293
+
294
+ def get_impl_vname(key, vname, cols=nil)
295
+ map = @hadb.read(key) {|rdb|
296
+ qry = QRY.new(rdb)
297
+ qry.addcond(COL_KEY, QRY::QCSTREQ, key)
298
+ qry.addcond(COL_VNAME, QRY::QCSTREQ, vname)
299
+ qry.setorder(COL_VTIME, QRY::QONUMDESC)
300
+ qry.setlimit(1)
301
+ array = qry.searchget(cols)
302
+ array[0]
303
+ }
304
+
305
+ if map == nil
306
+ return nil
307
+ elsif !is_valid_map(map)
308
+ return nil
309
+ else
310
+ return map
311
+ end
312
+ end
313
+
314
+ def get_impl_vtime(key, vtime, cols)
315
+ map = @hadb.read(key) {|rdb|
316
+ qry = QRY.new(rdb)
317
+ qry.addcond(COL_KEY, QRY::QCSTREQ, key)
318
+ qry.addcond(COL_VTIME, QRY::QCNUMLE, vtime.to_s)
319
+ qry.setorder(COL_VTIME, QRY::QONUMDESC)
320
+ qry.setlimit(1)
321
+ array = qry.searchget(cols)
322
+ array[0]
323
+ }
324
+
325
+ if map == nil
326
+ return nil
327
+ elsif !is_valid_map(map)
328
+ return nil
329
+ else
330
+ return map
331
+ end
332
+ end
333
+
334
+ #def select_latest_valid(array)
335
+ # latest = select_latest(array)
336
+ # if is_valid_map(latest)
337
+ # return latest
338
+ # else
339
+ # return nil
340
+ # end
341
+ #end
342
+
343
+ #def select_latest(array)
344
+ # if array.size == 1
345
+ # return array[0]
346
+ # end
347
+ #
348
+ # max_vtime = 0
349
+ # marray = []
350
+ #
351
+ # array.each {|map|
352
+ # vtime = map[COL_VTIME].to_i
353
+ # if max_vtime < vtime
354
+ # marray.clear
355
+ # marray << map
356
+ # max_vtime = vtime
357
+ # elsif max_vtime == vtime
358
+ # marray << map
359
+ # end
360
+ # }
361
+ #
362
+ # if marray.size == 1
363
+ # return marray[0]
364
+ # else
365
+ # return marray.sort_by {|map| map[COL_PK] }.last
366
+ # end
367
+ #end
368
+
369
+ def is_valid_map(map)
370
+ COLS_REQUIRED.all? {|col| map.has_key?(col) }
371
+ end
372
+
373
+ def is_removed(map)
374
+ map.has_key?(COL_REMOVED)
375
+ end
376
+
377
+ def add_impl(key, attrs, vname=nil)
378
+ map = get_impl_head(key, COLS_REQUIRED)
379
+
380
+ if map
381
+ # optional: inherit rsid
382
+ rsid = map[COL_RSID].to_i
383
+
384
+ # get current vtime later than old vtime
385
+ vtime = get_current_vtime(map[COL_VTIME].to_i)
386
+
387
+ okey = new_okey(key, vtime, rsid)
388
+
389
+ # insert
390
+ pk = new_pk(map[COL_PK])
391
+ map = to_map(attrs, okey, vname)
392
+ @hadb.write(key) {|rdb| rdb.put(pk, map) }
393
+
394
+ else
395
+ attrs ||= {}
396
+
397
+ okey = new_okey(key)
398
+
399
+ # insert
400
+ pk = new_pk()
401
+ map = to_map(attrs, okey, vname)
402
+ @hadb.write(key) {|rdb| rdb.put(pk, map) }
403
+ end
404
+
405
+ return okey
406
+ end
407
+
408
+ def update_impl(key, &modifier)
409
+ map = get_impl_head(key, nil)
410
+
411
+ if map && !is_removed(map)
412
+ okey = to_okey(map)
413
+
414
+ # create new attrs
415
+ attrs = modifier.call( to_attrs(map) )
416
+
417
+ # reject old attributes
418
+ map.reject! {|k,v| !COLS_RESERVED.include?(k) }
419
+
420
+ # merge new attributes
421
+ map = attrs.merge(map)
422
+
423
+ # update
424
+ pk = map.delete(COL_PK)
425
+ @hadb.write(key) {|rdb| rdb.put(pk, map) }
426
+
427
+ return okey
428
+
429
+ else
430
+ return nil
431
+ end
432
+ end
433
+
434
+ # +----------+----+------+---+
435
+ # | 30 | 10 | 16 | 8 |
436
+ # +----------+----+------+---+
437
+ # UNIX time
438
+ # millisec
439
+ # rand
440
+ # generator-id
441
+ # +--------------------------+
442
+ # 64 bits
443
+ #
444
+ def new_pk(at_least=nil)
445
+ nowtime = Time.now.utc
446
+ sec = nowtime.sec
447
+ msec = nowtime.usec / 1000
448
+
449
+ if at_least && at_least.size == 8
450
+ time_u, time_d = at_least.unpack('NC')
451
+ asec = time_u>>2
452
+ amsec = (time_u&0x3)<<2 & time_d
453
+ if sec < asec || (sec == asec && msec <= amsec)
454
+ sec = asec + 1
455
+ msec = amsec
456
+ end
457
+ end
458
+
459
+ gid = @pid
460
+
461
+ r = @random.rand(2**16)
462
+ raw = [sec<<2|msec>>8, msec&0xff, r, gid].pack('NCnC')
463
+
464
+ # FIXME base64
465
+ raw = [raw].pack('m')
466
+ raw.gsub!(/[\n\=]+/,'')
467
+ raw
468
+ end
469
+ end
470
+
471
+
472
+ end