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,182 @@
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 HeartbeatResponse
22
+ def initialize(term=nil, sync_needed=nil)
23
+ @term = term
24
+ @sync_needed = sync_needed
25
+ end
26
+
27
+ attr_accessor :term
28
+ attr_accessor :sync_needed
29
+
30
+ public
31
+ def to_msgpack(out = '')
32
+ [@term, @sync_needed].to_msgpack(out)
33
+ end
34
+ def from_msgpack(obj)
35
+ @term = obj[0]
36
+ @sync_needed = obj[1]
37
+ self
38
+ end
39
+ end
40
+
41
+
42
+ class HeartbeatServerService < Service
43
+ def initialize
44
+ super
45
+ @syncs = []
46
+ end
47
+
48
+ def rpc_heartbeat(nid, sync_hash)
49
+ hbres = HeartbeatResponse.new
50
+
51
+ if nid
52
+ hbres.term = MembershipBus.reset_fault_detector(nid)
53
+ end
54
+
55
+ if sync_hash
56
+ if SyncBus.check_hash(sync_hash)
57
+ hbres.sync_needed = false
58
+ else
59
+ hbres.sync_needed = true
60
+ end
61
+ end
62
+
63
+ hbres
64
+ end
65
+
66
+ ebus_connect :CSRPCBus,
67
+ :heartbeat => :rpc_heartbeat
68
+ end
69
+
70
+
71
+ class HeartbeatClientService < Service
72
+ def initialize
73
+ @heartbeat_nid = nil
74
+ end
75
+
76
+ #def get_cs_session
77
+ # ProcessBus.get_session(ConfigBus.get_cs_address)
78
+ #end
79
+ #
80
+ #def on_timer
81
+ # do_heartbeat
82
+ #end
83
+ #
84
+ #def do_heartbeat
85
+ # sync_hash = SyncBus.get_hash
86
+ # get_cs_session.callback(:heartbeat, @heartbeat_nid, sync_hash) do |future|
87
+ # begin
88
+ # hbres = HeartbeatResponse.new.from_msgpack(future.get)
89
+ # ack_heartbeat(hbres)
90
+ # rescue
91
+ # $log.error "heartbeat error: #{$!}"
92
+ # $log.error_backtrace $!.backtrace
93
+ # end
94
+ # end
95
+ #end
96
+ #
97
+ #def ack_heartbeat(hbres)
98
+ # if hbres.sync_needed
99
+ # SyncBus.try_sync
100
+ # end
101
+ #end
102
+ #
103
+ #ebus_connect :ProcessBus,
104
+ # :on_timer
105
+ #
106
+ #def heartbeat_blocking!
107
+ # do_heartbeat.join
108
+ #end
109
+
110
+ def run
111
+ @cs = MessagePack::RPC::Client.new(*ConfigBus.get_cs_address)
112
+ @end = false
113
+ @thread = Thread.new do
114
+ while !@end
115
+ sleep 1
116
+ do_heartbeat_blocking
117
+ end
118
+ end
119
+ end
120
+
121
+ def shutdown
122
+ @end = true
123
+ #@thread.join
124
+ @cs.close
125
+ end
126
+
127
+ def do_heartbeat_blocking
128
+ sync_hash = SyncBus.get_hash
129
+ begin
130
+ res = @cs.call(:heartbeat, @heartbeat_nid, sync_hash)
131
+ hbres = HeartbeatResponse.new.from_msgpack(res)
132
+ if hbres.sync_needed
133
+ ProcessBus.submit {
134
+ SyncBus.try_sync
135
+ }
136
+ end
137
+ rescue
138
+ $log.error "heartbeat error: #{$!}"
139
+ $log.error_backtrace $!.backtrace
140
+ end
141
+ nil
142
+ end
143
+
144
+ def heartbeat_blocking!
145
+ do_heartbeat_blocking
146
+ end
147
+
148
+ ebus_connect :ProcessBus,
149
+ :run,
150
+ :shutdown
151
+ end
152
+
153
+
154
+ class HeartbeatMemberService < HeartbeatClientService
155
+ def initialize
156
+ super
157
+ @heartbeat_nid = ConfigBus.self_nid
158
+ end
159
+
160
+ #def ack_heartbeat(hbres)
161
+ # super
162
+ #
163
+ # if hbres.term
164
+ # # do nothing
165
+ # else
166
+ # # MembershipMemberService
167
+ # #register_self
168
+ # end
169
+ #
170
+ # MembershipBus.try_register_node
171
+ #end
172
+
173
+ def on_timer
174
+ MembershipBus.try_register_node
175
+ end
176
+
177
+ ebus_connect :ProcessBus,
178
+ :on_timer
179
+ end
180
+
181
+
182
+ end
@@ -0,0 +1,81 @@
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
+ $log = CCLog.new(CCLog::LEVEL_INFO)
22
+
23
+
24
+ class LogService < Service
25
+ def initialize
26
+ @out = nil
27
+ end
28
+
29
+ def self.open!
30
+ init.open
31
+ end
32
+
33
+ def open
34
+ if path = ConfigBus.get_log_path
35
+ out = File.open(path, "a")
36
+ @out = $log.out = out
37
+ end
38
+ end
39
+
40
+ def on_sighup
41
+ if path = ConfigBus.get_log_path
42
+ out = File.open(path, "a")
43
+ if @out
44
+ @out.close
45
+ @out = nil
46
+ end
47
+ @out = $log.out = out
48
+ end
49
+ end
50
+
51
+ def shutdown
52
+ if @out
53
+ @out.close
54
+ @out = nil
55
+ end
56
+ end
57
+
58
+ def log_event_bus
59
+ $log.on_trace do
60
+ LS4.constants.each {|const|
61
+ klass = LS4.const_get(const)
62
+ if klass.is_a?(Class) && klass < Bus
63
+ bus = klass
64
+ name = bus.name.gsub('LS4::','')
65
+ $log.trace name
66
+ bus.ebus_all_slots.each {|s|
67
+ s = s.to_s.gsub('LS4::','')
68
+ $log.trace " #{s}"
69
+ }
70
+ end
71
+ }
72
+ end
73
+ end
74
+
75
+ ebus_connect :ProcessBus,
76
+ :shutdown,
77
+ :on_sighup
78
+ end
79
+
80
+
81
+ end
@@ -0,0 +1,148 @@
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 MasterSelectBus < Bus
22
+ call_slot :select_master
23
+ call_slot :select_master_static
24
+ signal_slot :update_nodes
25
+ end
26
+
27
+
28
+ class LocationAwareMasterSelectService < Service
29
+ def initialize
30
+ @map = {} # { rsid => [nids] }
31
+ @self_location = ConfigBus.self_location
32
+ end
33
+
34
+ def update_nodes(nodes=nil)
35
+ nodes ||= MembershipBus.get_all_nodes
36
+
37
+ rsid_nodes = {}
38
+ nodes.each {|node|
39
+ node.rsids.each {|rsid|
40
+ (rsid_nodes[rsid] ||= []) << node
41
+ }
42
+ }
43
+
44
+ rsid_loc_nids = {}
45
+ rsid_nodes.each_pair {|rsid,nodes|
46
+ loc_grouped = nodes.group_by {|node| node.location }
47
+
48
+ sorted = loc_grouped.to_a.sort_by {|loc,nodes| loc }
49
+ if idx = sorted.find_index {|loc,nodes| loc == @self_location }
50
+ sorted = rotate(sorted, idx)
51
+ end
52
+
53
+ loc_nids = sorted.map {|loc,nodes|
54
+ nids = nodes.map {|node| node.nid }
55
+ nids.sort
56
+ }
57
+
58
+ rsid_loc_nids[rsid] = loc_nids
59
+ }
60
+
61
+ @map = rsid_loc_nids
62
+ end
63
+
64
+ def select_master(rsid, key)
65
+ loc_nodes = @map[rsid]
66
+ unless loc_nodes
67
+ raise "no such rsid: #{rsid}"
68
+ end
69
+ digest = Digest::MD5.digest(key)
70
+ i = digest.unpack('C')[0]
71
+ loc_nodes.map {|nodes| rotate(nodes, i) }.flatten
72
+ end
73
+
74
+ def select_master_static(rsid)
75
+ loc_nodes = @map[rsid]
76
+ unless loc_nodes
77
+ raise "no such rsid: #{rsid}"
78
+ end
79
+ loc_nodes.flatten
80
+ end
81
+
82
+ ebus_connect :MasterSelectBus,
83
+ :select_master,
84
+ :select_master_static,
85
+ :update_nodes
86
+
87
+ private
88
+ def rotate(array, i)
89
+ n = i % array.size
90
+ return array[-n,n] + array[0, array.size-n]
91
+ end
92
+ end
93
+
94
+
95
+ class FlatMasterSelectService < Service
96
+ def initialize
97
+ @map = {} # { rsid => nids }
98
+ end
99
+
100
+ def update_nodes(nodes=nil)
101
+ nodes ||= MembershipBus.get_all_nodes
102
+
103
+ rsid_nids = {}
104
+ nodes.each {|node|
105
+ node.rsids.each {|rsid|
106
+ (rsid_nids[rsid] ||= []) << node.nid
107
+ }
108
+ }
109
+
110
+ rsid_nids.values.each {|nids|
111
+ nids.sort!
112
+ }
113
+
114
+ @map = rsid_nids
115
+ end
116
+
117
+ def select_master(rsid, key)
118
+ nids = @map[rsid]
119
+ unless nids
120
+ raise "no such rsid: #{rsid}"
121
+ end
122
+ digest = Digest::MD5.digest(key)
123
+ i = digest.unpack('C')[0]
124
+ rotate(nids, i)
125
+ end
126
+
127
+ def select_master_static(rsid)
128
+ nids = @map[rsid]
129
+ unless nids
130
+ raise "no such rsid: #{rsid}"
131
+ end
132
+ nids.dup
133
+ end
134
+
135
+ ebus_connect :MasterSelectBus,
136
+ :select_master,
137
+ :select_master_static,
138
+ :update_nodes
139
+
140
+ private
141
+ def rotate(array, i)
142
+ n = i % array.size
143
+ return array[-n,n] + array[0, array.size-n]
144
+ end
145
+ end
146
+
147
+
148
+ end
@@ -0,0 +1,292 @@
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 MDSBus < Bus
22
+ # @return
23
+ # found: ObjectKey
24
+ # not found: nil
25
+ call_slot :get_okey
26
+
27
+ # @return
28
+ # found: Hash (may be {})
29
+ # not found: nil
30
+ call_slot :get_attrs
31
+
32
+ # @return
33
+ # found: [ObjectKey, Hash (may be {})]
34
+ # not found: [nil, nil]
35
+ call_slot :get_okey_attrs
36
+
37
+ # @return new ObjectKey
38
+ call_slot :add
39
+
40
+ # @return
41
+ # found: updated ObjectKey
42
+ # not found: nil
43
+ call_slot :update_attrs
44
+
45
+ # @return
46
+ # found: removed ObjectKey
47
+ # not found: nil
48
+ call_slot :remove
49
+
50
+ # @return
51
+ # found: removed ObjectKey
52
+ # not found: nil
53
+ call_slot :delete
54
+
55
+ # @return
56
+ # found: array of [ObjectKey, vtime, vname]
57
+ # not found: []
58
+ call_slot :util_locate
59
+ end
60
+
61
+
62
+ class MDSConfigService < Service
63
+ def run
64
+ @uri = ConfigBus.get_initial_mds_uri
65
+ on_change
66
+ end
67
+
68
+ def rpc_get_mds_uri
69
+ @uri
70
+ end
71
+
72
+ def rpc_set_mds_uri(uri)
73
+ @uri = uri
74
+ on_change
75
+ nil
76
+ end
77
+
78
+ def self.hash_uri(uri)
79
+ Digest::SHA1.digest(uri)
80
+ end
81
+
82
+ def on_change
83
+ SyncBus.update(SYNC_MDS_URI,
84
+ @uri, MDSConfigService.hash_uri(@uri))
85
+ end
86
+
87
+ ebus_connect :ProcessBus,
88
+ :run
89
+
90
+ ebus_connect :CSRPCBus,
91
+ :get_mds_uri => :rpc_get_mds_uri,
92
+ :set_mds_uri => :rpc_set_mds_uri
93
+ end
94
+
95
+
96
+ class MDSService < Service
97
+ def initialize
98
+ @uri = ""
99
+ @mds = NullMDS.new
100
+ end
101
+
102
+ def run
103
+ SyncBus.register_callback(SYNC_MDS_URI,
104
+ MDSConfigService.hash_uri(@uri)) do |obj|
105
+ uri = obj
106
+ reopen(uri)
107
+ @uri = uri
108
+ MDSConfigService.hash_uri(@uri)
109
+ end
110
+ end
111
+
112
+ def shutdown
113
+ if @mds
114
+ @mds.close rescue nil
115
+ end
116
+ end
117
+
118
+ def reopen(uri)
119
+ klass, expr = MDSSelector.select_class(uri)
120
+
121
+ mds = klass.new
122
+ mds.open(expr)
123
+
124
+ old_mds = @mds
125
+ @mds = mds
126
+
127
+ $log.info "using MDS: #{@mds}"
128
+
129
+ begin
130
+ old_mds.close
131
+ rescue
132
+ $log.error "MDS close error: #{$!}"
133
+ $log.error_backtrace $!.backtrace
134
+ end
135
+ end
136
+
137
+ ebus_connect :ProcessBus,
138
+ :run,
139
+ :shutdown
140
+
141
+ ebus_connect :MDSBus,
142
+ :get_okey,
143
+ :get_attrs,
144
+ :get_okey_attrs,
145
+ :add,
146
+ :update_attrs,
147
+ :remove,
148
+ :delete,
149
+ :util_locate
150
+
151
+ extend Forwardable
152
+
153
+ def_delegators :@mds,
154
+ :get_okey,
155
+ :get_attrs,
156
+ :get_okey_attrs,
157
+ :add,
158
+ :update_attrs,
159
+ :remove,
160
+ :delete,
161
+ :util_locate
162
+ end
163
+
164
+
165
+ module MDSSelector
166
+ IMPLS = {}
167
+
168
+ def self.register(name, klass)
169
+ IMPLS[name.to_sym] = klass
170
+ nil
171
+ end
172
+
173
+ def self.select_class(uri)
174
+ if m = /^(\w{1,8})\:(.*)/.match(uri)
175
+ type = m[1].to_sym
176
+ expr = m[2]
177
+ else
178
+ type = :tt
179
+ expr = uri
180
+ end
181
+
182
+ klass = IMPLS[type]
183
+ unless klass
184
+ raise "unknown MDS type: #{type}"
185
+ end
186
+
187
+ return klass, expr
188
+ end
189
+ end
190
+
191
+
192
+ class MDS
193
+ module Query
194
+ QC_EQ = 0
195
+ QC_NOT_EQ = 1
196
+ QC_LESS_THAN = 2
197
+ QC_LESS_THAN_EQ = 3
198
+ QC_GRATER_THAN = 4
199
+ QC_GRATER_THAN_EQ = 5
200
+ QC_NULL = 6
201
+ QC_NOT_NULL = 8
202
+
203
+ ORDER_NONE = 0
204
+ ORDER_STR_ASC = 1
205
+ ORDER_STR_DESC = 2
206
+ ORDER_NUM_ASC = 3
207
+ ORDER_NUM_DESC = 4
208
+ end
209
+
210
+ #def open(expr)
211
+ #end
212
+
213
+ #def close
214
+ #end
215
+
216
+ # @param version vname:String or vtime:Integer
217
+ #def get_okey(key, version=nil, &cb)
218
+ #end
219
+
220
+ # @param version vname:String or vtime:Integer
221
+ #def get_attrs(key, version=nil, &cb)
222
+ #end
223
+
224
+ # @param version vname:String or vtime:Integer
225
+ #def get_okey_attrs(key, version=nil, &cb)
226
+ #end
227
+
228
+ #def add(key, attrs={}, vname=nil, &cb)
229
+ #end
230
+
231
+ #def update_attrs(key, attrs, &cb)
232
+ #end
233
+
234
+ #def remove(key, &cb)
235
+ #end
236
+
237
+ #def delete(key, version=nil, &cb)
238
+ #end
239
+
240
+ def util_locate(key, &cb)
241
+ get_okey(key) {|okey|
242
+ if okey
243
+ cb.call([okey, nil], nil) rescue nil
244
+ else
245
+ cb.call([], nil) rescue nil
246
+ end
247
+ }
248
+ end
249
+
250
+ protected
251
+ def get_current_vtime(at_least=0)
252
+ now = Time.now.utc.to_i
253
+ if now <= at_least
254
+ return at_least + 1
255
+ else
256
+ return now
257
+ end
258
+ end
259
+
260
+ def new_okey(key, vtime=get_current_vtime, rsid=nil)
261
+ rsid ||= BalanceBus.select_next_rsid(key)
262
+ ObjectKey.new(key, vtime, rsid)
263
+ end
264
+ end
265
+
266
+
267
+ class NullMDS < MDS
268
+ extend Forwardable
269
+
270
+ [
271
+ :get_okey,
272
+ :get_attrs,
273
+ :get_okey_attrs,
274
+ :add,
275
+ :remove,
276
+ :delete,
277
+ :util_locate,
278
+ :open
279
+ ].each {|method|
280
+ def_delegator :self, :raise_error, method
281
+ }
282
+
283
+ def raise_error(*args)
284
+ raise "mds is not configured"
285
+ end
286
+
287
+ def close
288
+ end
289
+ end
290
+
291
+
292
+ end