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.
- data/AUTHORS +1 -0
- data/COPYING +661 -0
- data/ChangeLog +9 -0
- data/NOTICE +8 -0
- data/README.rdoc +61 -0
- data/bin/ls4-cs +3 -0
- data/bin/ls4-ds +3 -0
- data/bin/ls4-gw +3 -0
- data/bin/ls4-standalone +3 -0
- data/bin/ls4cmd +3 -0
- data/bin/ls4ctl +3 -0
- data/bin/ls4rpc +3 -0
- data/bin/ls4stat +3 -0
- data/bin/ls4top +3 -0
- data/lib/ls4/command/cmd.rb +241 -0
- data/lib/ls4/command/cs.rb +190 -0
- data/lib/ls4/command/ctl.rb +278 -0
- data/lib/ls4/command/ds.rb +335 -0
- data/lib/ls4/command/gw.rb +256 -0
- data/lib/ls4/command/rpc.rb +172 -0
- data/lib/ls4/command/standalone.rb +318 -0
- data/lib/ls4/command/stat.rb +244 -0
- data/lib/ls4/command/top.rb +291 -0
- data/lib/ls4/default.rb +26 -0
- data/lib/ls4/lib/cclog.rb +220 -0
- data/lib/ls4/lib/ebus.rb +553 -0
- data/lib/ls4/lib/vbcode.rb +228 -0
- data/lib/ls4/logic/fault_detector.rb +212 -0
- data/lib/ls4/logic/membership.rb +253 -0
- data/lib/ls4/logic/node.rb +66 -0
- data/lib/ls4/logic/okey.rb +45 -0
- data/lib/ls4/logic/tsv_data.rb +81 -0
- data/lib/ls4/logic/weight.rb +166 -0
- data/lib/ls4/service/balance.rb +62 -0
- data/lib/ls4/service/base.rb +29 -0
- data/lib/ls4/service/bus.rb +37 -0
- data/lib/ls4/service/config.rb +63 -0
- data/lib/ls4/service/config_cs.rb +33 -0
- data/lib/ls4/service/config_ds.rb +56 -0
- data/lib/ls4/service/config_gw.rb +42 -0
- data/lib/ls4/service/data_client.rb +122 -0
- data/lib/ls4/service/data_server.rb +168 -0
- data/lib/ls4/service/data_server_url.rb +83 -0
- data/lib/ls4/service/gateway.rb +375 -0
- data/lib/ls4/service/gateway_ro.rb +91 -0
- data/lib/ls4/service/gw_http.rb +821 -0
- data/lib/ls4/service/heartbeat.rb +182 -0
- data/lib/ls4/service/log.rb +81 -0
- data/lib/ls4/service/master_select.rb +148 -0
- data/lib/ls4/service/mds.rb +292 -0
- data/lib/ls4/service/mds_cache.rb +294 -0
- data/lib/ls4/service/mds_cache_mem.rb +63 -0
- data/lib/ls4/service/mds_cache_memcached.rb +65 -0
- data/lib/ls4/service/mds_ha.rb +176 -0
- data/lib/ls4/service/mds_memcache.rb +209 -0
- data/lib/ls4/service/mds_tc.rb +508 -0
- data/lib/ls4/service/mds_tt.rb +472 -0
- data/lib/ls4/service/membership.rb +331 -0
- data/lib/ls4/service/process.rb +90 -0
- data/lib/ls4/service/rpc.rb +50 -0
- data/lib/ls4/service/rpc_cs.rb +101 -0
- data/lib/ls4/service/rpc_ds.rb +96 -0
- data/lib/ls4/service/rpc_gw.rb +255 -0
- data/lib/ls4/service/rts.rb +94 -0
- data/lib/ls4/service/rts_file.rb +76 -0
- data/lib/ls4/service/rts_memory.rb +55 -0
- data/lib/ls4/service/slave.rb +132 -0
- data/lib/ls4/service/stat.rb +91 -0
- data/lib/ls4/service/stat_cs.rb +25 -0
- data/lib/ls4/service/stat_ds.rb +40 -0
- data/lib/ls4/service/stat_gw.rb +25 -0
- data/lib/ls4/service/storage.rb +116 -0
- data/lib/ls4/service/storage_dir.rb +201 -0
- data/lib/ls4/service/sync.rb +206 -0
- data/lib/ls4/service/time_check.rb +80 -0
- data/lib/ls4/service/ulog.rb +159 -0
- data/lib/ls4/service/ulog_file.rb +398 -0
- data/lib/ls4/service/ulog_memory.rb +53 -0
- data/lib/ls4/service/weight.rb +134 -0
- data/lib/ls4/version.rb +5 -0
- data/test/01_add_get_remove.rt +84 -0
- data/test/02_read.rt +61 -0
- data/test/03_getd_readd.rt +69 -0
- data/test/04_version_time.rt +170 -0
- data/test/05_version_name.rt +161 -0
- data/test/06_http_get_set_remove_1.rt +119 -0
- data/test/07_http_get_set_remove_2.rt +116 -0
- data/test/08_read_only_time.rt +177 -0
- data/test/09_read_only_name.rt +173 -0
- data/test/10_http_get_set_remove_3.rt +73 -0
- data/test/11_mds_cache_memcached.rt +88 -0
- data/test/12_mds_cache_local_memory.rt +86 -0
- data/test/13_memcache_mds.rt +84 -0
- data/test/14_delete.rt +63 -0
- data/test/15_standalone.rt +71 -0
- data/test/chukan.rb +516 -0
- data/test/common.rb +250 -0
- data/test/load_test.rb +79 -0
- data/test/load_test_offload.rb +86 -0
- 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
|