rufus-tokyo 0.1.12 → 0.1.13

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rufus/tokyo.rb CHANGED
@@ -29,13 +29,25 @@ require 'ffi' # sudo gem install ffi
29
29
  module Rufus
30
30
  module Tokyo
31
31
 
32
- VERSION = '0.1.12'
32
+ VERSION = '0.1.13'
33
33
 
34
34
  #
35
35
  # A common error class
36
36
  #
37
37
  class TokyoError < RuntimeError; end
38
38
 
39
+ #
40
+ # Grumpf, this is not elegant...
41
+ #
42
+ INT_MIN = -2147483648
43
+
44
+ # Returns 'bytesize' of the string (Ruby 1.9.1 for everyone).
45
+ #
46
+ def self.blen (s)
47
+
48
+ s.respond_to?(:bytesize) ? s.bytesize : s.size
49
+ end
50
+
39
51
  end
40
52
  end
41
53
 
@@ -53,7 +53,6 @@ module Rufus::Tokyo
53
53
  include HashMethods
54
54
  include Transactions
55
55
 
56
- #
57
56
  # Creates/opens the cabinet, raises an exception in case of
58
57
  # creation/opening failure.
59
58
  #
@@ -165,6 +164,9 @@ module Rufus::Tokyo
165
164
  # * :capnum specifies the capacity number of records.
166
165
  # * :capsiz specifies the capacity size of using memory.
167
166
  #
167
+ # * :dfunit unit step number. If it is not more than 0,
168
+ # the auto defragmentation is disabled. (Since TC 1.4.21)
169
+ #
168
170
  #
169
171
  # = NOTE :
170
172
  #
@@ -183,6 +185,8 @@ module Rufus::Tokyo
183
185
  name += { :hash => '.tch', :btree => '.tcb', :fixed => '.tcf' }[type]
184
186
  end
185
187
 
188
+ @path = name
189
+
186
190
  name = name + params.collect { |k, v| "##{k}=#{v}" }.join('')
187
191
 
188
192
  (lib.tcadbopen(@db, name) == 1) ||
@@ -193,130 +197,153 @@ module Rufus::Tokyo
193
197
  end
194
198
 
195
199
  # Same args as initialize, but can take a block form that will
196
- # close the db when done. Similar to File.open
200
+ # close the db when done. Similar to File.open
201
+ #
197
202
  def self.open (name, params={})
203
+
198
204
  db = self.new(name, params)
205
+
199
206
  if block_given?
200
207
  yield db
201
208
  nil
202
209
  else
203
210
  db
204
211
  end
212
+
205
213
  ensure
214
+
206
215
  db.close if block_given? && db
207
216
  end
208
217
 
209
- #
210
218
  # Returns a new in-memory hash. Accepts the same optional params hash
211
219
  # as new().
212
220
  #
213
221
  def self.new_hash (params={})
222
+
214
223
  self.new(:hash, params)
215
224
  end
216
225
 
217
- #
218
226
  # Returns a new in-memory B+ tree. Accepts the same optional params hash
219
227
  # as new().
220
228
  #
221
229
  def self.new_tree (params={})
230
+
222
231
  self.new(:tree, params)
223
232
  end
224
233
 
225
- #
226
- # using the cabinet lib
234
+ # Using the cabinet lib
227
235
  #
228
236
  def lib
237
+
229
238
  CabinetLib
230
239
  end
231
240
 
241
+ # Returns the path to this database.
232
242
  #
243
+ def path
244
+
245
+ @path
246
+ end
247
+
233
248
  # No comment
234
249
  #
235
250
  def []= (k, v)
236
- lib.abs_put2(@db, k, v)
251
+
252
+ lib.abs_put(@db, k, Rufus::Tokyo.blen(k), v, Rufus::Tokyo.blen(v))
237
253
  end
238
254
 
255
+ # Like #put but doesn't overwrite the value if already set. Returns true
256
+ # only if there no previous entry for k.
239
257
  #
258
+ def putkeep (k, v)
259
+
260
+ (lib.abs_putkeep(
261
+ @db, k, Rufus::Tokyo.blen(k), v, Rufus::Tokyo.blen(v)) == 1)
262
+ end
263
+
240
264
  # (The actual #[] method is provided by HashMethods
241
265
  #
242
266
  def get (k)
243
- lib.abs_get2(@db, k) rescue nil
267
+
268
+ outlen_op(:abs_get, k, Rufus::Tokyo.blen(k))
244
269
  end
245
270
  protected :get
246
271
 
247
- #
248
272
  # Removes a record from the cabinet, returns the value if successful
249
273
  # else nil.
250
274
  #
251
275
  def delete (k)
276
+
252
277
  v = self[k]
253
- (lib.abs_out2(@db, k) == 1) ? v : nil
278
+
279
+ (lib.abs_out(@db, k, Rufus::Tokyo.blen(k)) == 1) ? v : nil
254
280
  end
255
281
 
256
- #
257
282
  # Returns the number of records in the 'cabinet'
258
283
  #
259
284
  def size
285
+
260
286
  lib.abs_rnum(@db)
261
287
  end
262
288
 
263
- #
264
289
  # Removes all the records in the cabinet (use with care)
265
290
  #
266
291
  # Returns self (like Ruby's Hash does).
267
292
  #
268
293
  def clear
294
+
269
295
  lib.abs_vanish(@db)
296
+
270
297
  self
271
298
  end
272
299
 
273
- #
274
300
  # Returns the 'weight' of the db (in bytes)
275
301
  #
276
302
  def weight
303
+
277
304
  lib.abs_size(@db)
278
305
  end
279
306
 
280
- #
281
307
  # Closes the cabinet (and frees the datastructure allocated for it),
282
308
  # returns true in case of success.
283
309
  #
284
310
  def close
311
+
285
312
  result = lib.abs_close(@db)
286
313
  lib.abs_del(@db)
314
+
287
315
  (result == 1)
288
316
  end
289
317
 
290
- #
291
318
  # Copies the current cabinet to a new file.
292
319
  #
293
320
  # Returns true if it was successful.
294
321
  #
295
322
  def copy (target_path)
323
+
296
324
  (lib.abs_copy(@db, target_path) == 1)
297
325
  end
298
326
 
299
- #
300
327
  # Copies the current cabinet to a new file.
301
328
  #
302
329
  # Does it by copying each entry afresh to the target file. Spares some
303
330
  # space, hence the 'compact' label...
304
331
  #
305
332
  def compact_copy (target_path)
333
+
306
334
  @other_db = Cabinet.new(target_path)
307
335
  self.each { |k, v| @other_db[k] = v }
308
336
  @other_db.close
309
337
  end
310
338
 
311
- #
312
339
  # "synchronize updated contents of an abstract database object with
313
340
  # the file and the device"
314
341
  #
315
342
  def sync
343
+
316
344
  (lib.abs_sync(@db) == 1)
317
345
  end
318
346
 
319
- #
320
347
  # Returns an array with all the keys in the databse
321
348
  #
322
349
  # With no options given, this method will return all the keys (strings)
@@ -332,10 +359,15 @@ module Rufus::Tokyo
332
359
  #
333
360
  def keys (options={})
334
361
 
335
- if pref = options[:prefix]
362
+ outlen = nil
363
+
364
+ if pre = options[:prefix]
365
+
366
+ l = lib.abs_fwmkeys(
367
+ @db, pre, Rufus::Tokyo.blen(pre), options[:limit] || -1)
336
368
 
337
- l = lib.abs_fwmkeys2(@db, pref, options[:limit] || -1)
338
369
  l = Rufus::Tokyo::List.new(l)
370
+
339
371
  options[:native] ? l : l.release
340
372
 
341
373
  else
@@ -347,26 +379,34 @@ module Rufus::Tokyo
347
379
 
348
380
  lib.abs_iterinit(@db)
349
381
 
350
- while (k = (lib.abs_iternext2(@db) rescue nil))
382
+ outlen = FFI::MemoryPointer.new(:int)
383
+
384
+ loop do
351
385
  break if limit and l.size >= limit
352
- l << k
386
+ out = lib.abs_iternext(@db, outlen)
387
+ break if out.address == 0
388
+ l << out.get_bytes(0, outlen.get_int(0))
353
389
  end
354
390
 
355
391
  l
356
392
  end
393
+
394
+ ensure
395
+
396
+ outlen.free if outlen
357
397
  end
358
398
 
359
- #
360
399
  # Deletes all the entries whose keys begin with the given prefix
361
400
  #
362
401
  def delete_keys_with_prefix (prefix)
363
402
 
364
- call_misc('outlist', lib.abs_fwmkeys2(@db, prefix, -1))
365
- # -1 for no limits
403
+ call_misc(
404
+ 'outlist', lib.abs_fwmkeys(@db, prefix, Rufus::Tokyo.blen(prefix), -1))
405
+ # -1 for no limits
406
+
366
407
  nil
367
408
  end
368
409
 
369
- #
370
410
  # Given a list of keys, returns a Hash { key => value } of the
371
411
  # matching entries (in one sweep).
372
412
  #
@@ -375,7 +415,6 @@ module Rufus::Tokyo
375
415
  Hash[*call_misc('getlist', Rufus::Tokyo::List.new(keys))]
376
416
  end
377
417
 
378
- #
379
418
  # Merges the given hash into this Cabinet (or Tyrant) and returns self.
380
419
  #
381
420
  def merge! (hash)
@@ -387,7 +426,6 @@ module Rufus::Tokyo
387
426
  end
388
427
  alias :lput :merge!
389
428
 
390
- #
391
429
  # Given a list of keys, deletes all the matching entries (in one sweep).
392
430
  #
393
431
  def ldelete (keys)
@@ -395,6 +433,29 @@ module Rufus::Tokyo
395
433
  call_misc('outlist', Rufus::Tokyo::List.new(keys))
396
434
  end
397
435
 
436
+ # Increments the value stored under the given key with the given increment
437
+ # (defaults to 1 (integer)).
438
+ #
439
+ # Accepts an integer or a double value.
440
+ #
441
+ def incr (key, inc=1)
442
+
443
+ v = inc.is_a?(Fixnum) ?
444
+ lib.addint(@db, key, Rufus::Tokyo.blen(key), inc) :
445
+ lib.adddouble(@db, key, Rufus::Tokyo.blen(key), inc)
446
+
447
+ raise(TokyoError.new(
448
+ "incr failed, there is probably already a string value set " +
449
+ "for the key '#{key}'"
450
+ )) if v == Rufus::Tokyo::INT_MIN || (v.respond_to?(:nan?) && v.nan?)
451
+
452
+ v
453
+ end
454
+ alias :addint :incr
455
+ alias :adddouble :incr
456
+ alias :add_int :incr
457
+ alias :add_double :incr
458
+
398
459
  # Warning : this method is low-level, you probably only need
399
460
  # to use #transaction and a block.
400
461
  #
@@ -407,6 +468,18 @@ module Rufus::Tokyo
407
468
  libcall(:tcadbtranbegin)
408
469
  end
409
470
 
471
+ # Triggers a defrag run (TC >= 1.4.21 only)
472
+ #
473
+ def defrag
474
+
475
+ raise(NotImplementedError.new(
476
+ "method defrag is supported since Tokyo Cabinet 1.4.21. " +
477
+ "your TC version doesn't support it"
478
+ )) unless lib.respond_to?(:tctdbsetdfunit)
479
+
480
+ call_misc('defrag', Rufus::Tokyo::List.new)
481
+ end
482
+
410
483
  # Warning : this method is low-level, you probably only need
411
484
  # to use #transaction and a block.
412
485
  #
@@ -441,8 +514,7 @@ module Rufus::Tokyo
441
514
  ) unless lib.respond_to?(:tcadbtranbegin)
442
515
  end
443
516
 
444
- #
445
- # wrapping tcadbmisc or tcrdbmisc
517
+ # Wrapping tcadbmisc or tcrdbmisc
446
518
  # (and taking care of freeing the list_pointer)
447
519
  #
448
520
  def call_misc (function, list_pointer)
@@ -459,7 +531,7 @@ module Rufus::Tokyo
459
531
  end
460
532
  end
461
533
 
462
- # calls the tcadbmisc function
534
+ # Calls the tcadbmisc function
463
535
  #
464
536
  def do_call_misc (function, list_pointer)
465
537
 
@@ -471,6 +543,26 @@ module Rufus::Tokyo
471
543
  (eval(%{ lib.#{lib_method}(@db, *args) }) == 1) or \
472
544
  raise TokyoError.new("call to #{lib_method} failed")
473
545
  end
546
+
547
+ # A wrapper for library returning a string (binary data potentially)
548
+ #
549
+ def outlen_op (method, *args)
550
+
551
+ args.unshift(@db)
552
+
553
+ outlen = FFI::MemoryPointer.new(:int)
554
+ args << outlen
555
+
556
+ out = lib.send(method, *args)
557
+
558
+ return nil if out.address == 0
559
+
560
+ return out.get_bytes(0, outlen.get_int(0))
561
+
562
+ ensure
563
+
564
+ outlen.free
565
+ end
474
566
  end
475
567
  end
476
568
 
@@ -84,22 +84,29 @@ module Rufus::Tokyo
84
84
  attfunc :abs_rnum, :tcadbrnum, [ :pointer ], :uint64
85
85
  attfunc :abs_size, :tcadbsize, [ :pointer ], :uint64
86
86
 
87
- attfunc :abs_put2, :tcadbput2, [ :pointer, :string, :string ], :int
88
- attfunc :abs_get2, :tcadbget2, [ :pointer, :string ], :string
89
- attfunc :abs_out2, :tcadbout2, [ :pointer, :string ], :int
87
+ attfunc :abs_put, :tcadbput, [ :pointer, :pointer, :int, :pointer, :int ], :int
88
+
89
+ attfunc :abs_get, :tcadbget, [ :pointer, :pointer, :int, :pointer ], :pointer
90
+
91
+ attfunc :abs_out, :tcadbout, [ :pointer, :pointer, :int ], :int
92
+
93
+ attfunc :abs_putkeep, :tcadbputkeep, [ :pointer, :pointer, :int, :pointer, :int ], :int
90
94
 
91
95
  attfunc :abs_iterinit, :tcadbiterinit, [ :pointer ], :int
92
- attfunc :abs_iternext2, :tcadbiternext2, [ :pointer ], :string
96
+ attfunc :abs_iternext, :tcadbiternext, [ :pointer, :pointer ], :pointer
93
97
 
94
98
  attfunc :abs_vanish, :tcadbvanish, [ :pointer ], :int
95
99
 
96
100
  attfunc :abs_sync, :tcadbsync, [ :pointer ], :int
97
101
  attfunc :abs_copy, :tcadbcopy, [ :pointer, :string ], :int
98
102
 
99
- attfunc :abs_fwmkeys2, :tcadbfwmkeys2, [ :pointer, :string, :int ], :pointer
103
+ attfunc :abs_fwmkeys, :tcadbfwmkeys, [ :pointer, :pointer, :int, :int ], :pointer
100
104
 
101
105
  attfunc :tcadbmisc, [ :pointer, :string, :pointer ], :pointer
102
106
 
107
+ attfunc :addint, :tcadbaddint, [ :pointer, :string, :int, :int ], :int
108
+ attfunc :adddouble, :tcadbadddouble, [ :pointer, :string, :int, :double ], :double
109
+
103
110
  begin # since TC 1.4.13
104
111
  attfunc :tcadbtranbegin, [ :pointer ], :int
105
112
  attfunc :tcadbtrancommit, [ :pointer ], :int
@@ -118,18 +125,23 @@ module Rufus::Tokyo
118
125
  attfunc :tctdbsetcache, [ :pointer, :uint32, :uint32, :uint32 ], :int
119
126
  attfunc :tctdbsetxmsiz, [ :pointer, :uint64 ], :int
120
127
 
128
+ begin # since TC 1.4.21
129
+ attfunc :tctdbsetdfunit, [ :pointer, :uint32 ], :int
130
+ rescue FFI::NotFoundError => nfe
131
+ end
132
+
121
133
  attfunc :tctdbopen, [ :pointer, :string, :int ], :int
122
134
 
123
135
  attfunc :tab_close, :tctdbclose, [ :pointer ], :int
124
136
 
125
137
  attfunc :tab_genuid, :tctdbgenuid, [ :pointer ], :int64
126
138
 
127
- attfunc :tab_get, :tctdbget, [ :pointer, :string, :int ], :pointer
139
+ attfunc :tab_get, :tctdbget, [ :pointer, :pointer, :int ], :pointer
128
140
 
129
141
  attfunc :tab_iterinit, :tctdbiterinit, [ :pointer ], :int
130
- attfunc :tab_iternext2, :tctdbiternext2, [ :pointer ], :string
142
+ attfunc :tab_iternext, :tctdbiternext, [ :pointer, :pointer ], :pointer
131
143
 
132
- attfunc :tab_put, :tctdbput, [ :pointer, :string, :int, :pointer ], :int
144
+ attfunc :tab_put, :tctdbput, [ :pointer, :pointer, :int, :pointer ], :int
133
145
 
134
146
  #attfunc :tctdbput3, [ :pointer, :string, :string ], :int
135
147
  # not using it anymore, Ruby can turn an array into a hash so easily
@@ -151,7 +163,7 @@ module Rufus::Tokyo
151
163
  attfunc :tctdbtrancommit, [ :pointer ], :int
152
164
  attfunc :tctdbtranabort, [ :pointer ], :int
153
165
 
154
- attfunc :tab_fwmkeys2, :tctdbfwmkeys2, [ :pointer, :string, :int ], :pointer
166
+ attfunc :tab_fwmkeys, :tctdbfwmkeys, [ :pointer, :pointer, :int, :int ], :pointer
155
167
 
156
168
  #
157
169
  # tctdbqry functions
@@ -183,18 +195,13 @@ module Rufus::Tokyo
183
195
  # http://tokyocabinet.sourceforge.net/spex-en.html#tcutilapi
184
196
 
185
197
  attfunc :tcmapnew, [], :pointer
186
-
187
- attfunc :tcmapput2, [ :pointer, :string, :string ], :void
188
- attfunc :tcmapout2, [ :pointer, :string ], :int
198
+ attfunc :tcmapput, [ :pointer, :pointer, :int, :pointer, :int ], :void
199
+ attfunc :tcmapout, [ :pointer, :pointer, :int ], :int
189
200
  attfunc :tcmapclear, [ :pointer ], :void
190
-
191
201
  attfunc :tcmapdel, [ :pointer ], :void
192
-
193
- attfunc :tcmapget2, [ :pointer, :string ], :string
194
-
202
+ attfunc :tcmapget, [ :pointer, :pointer, :int, :pointer ], :pointer
195
203
  attfunc :tcmapiterinit, [ :pointer ], :void
196
- attfunc :tcmapiternext2, [ :pointer ], :string
197
-
204
+ attfunc :tcmapiternext, [ :pointer, :pointer ], :pointer
198
205
  attfunc :tcmaprnum, [ :pointer ], :uint64
199
206
 
200
207
  #
@@ -203,19 +210,14 @@ module Rufus::Tokyo
203
210
  # http://tokyocabinet.sourceforge.net/spex-en.html#tcutilapi
204
211
 
205
212
  attfunc :tclistnew, [], :pointer
206
-
207
213
  attfunc :tclistnum, [ :pointer ], :int
208
- attfunc :tclistval2, [ :pointer, :int ], :string
209
-
210
- attfunc :tclistpush2, [ :pointer, :string ], :void
211
- attfunc :tclistpop2, [ :pointer ], :string
212
- attfunc :tclistshift2, [ :pointer ], :string
213
- attfunc :tclistunshift2, [ :pointer, :string ], :void
214
- attfunc :tclistover2, [ :pointer, :int, :string ], :void
215
-
216
- attfunc :tclistremove2, [ :pointer, :int ], :string
217
- # beware, seems like have to free the return string self
218
-
214
+ attfunc :tclistval, [ :pointer, :int, :pointer ], :pointer
215
+ attfunc :tclistpush, [ :pointer, :pointer, :int ], :void
216
+ attfunc :tclistpop, [ :pointer, :pointer ], :pointer
217
+ attfunc :tclistshift, [ :pointer, :pointer ], :pointer
218
+ attfunc :tclistunshift, [ :pointer, :pointer, :int ], :void
219
+ attfunc :tclistover, [ :pointer, :int, :pointer, :int ], :void
220
+ attfunc :tclistremove, [ :pointer, :int, :pointer ], :pointer
219
221
  attfunc :tclistdel, [ :pointer ], :void
220
222
  end
221
223