oklahoma_mixer 0.1.0 → 0.2.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.
@@ -0,0 +1,62 @@
1
+ module OklahomaMixer
2
+ class FixedLengthDatabase < HashDatabase
3
+ module C # :nodoc:
4
+ extend OklahomaMixer::Utilities::FFIDSL
5
+
6
+ IDS = enum :FDBIDMIN, -1,
7
+ :FDBIDPREV, -2,
8
+ :FDBIDMAX, -3,
9
+ :FDBIDNEXT, -4
10
+
11
+ prefix :tcfdb
12
+
13
+ def_core_database_consts_and_funcs
14
+
15
+ func :name => :tune,
16
+ :args => [:pointer, :int32, :int64],
17
+ :returns => :bool
18
+ func :name => :optimize,
19
+ :args => [:pointer, :int32, :int64],
20
+ :returns => :bool
21
+
22
+ func :name => :put,
23
+ :args => [:pointer, :int64, :pointer, :int],
24
+ :returns => :bool
25
+ func :name => :putkeep,
26
+ :args => [:pointer, :int64, :pointer, :int],
27
+ :returns => :bool
28
+ func :name => :putcat,
29
+ :args => [:pointer, :int64, :pointer, :int],
30
+ :returns => :bool
31
+ call :name => :TCPDPROC,
32
+ :args => [:pointer, :int, :pointer, :pointer],
33
+ :returns => :pointer
34
+ func :name => :putproc,
35
+ :args => [:pointer, :int64, :pointer, :int, :TCPDPROC, :pointer],
36
+ :returns => :bool
37
+ func :name => :addint,
38
+ :args => [:pointer, :int64, :int],
39
+ :returns => :int
40
+ func :name => :adddouble,
41
+ :args => [:pointer, :int64, :double],
42
+ :returns => :double
43
+ func :name => :out,
44
+ :args => [:pointer, :int64],
45
+ :returns => :bool
46
+ func :name => :get,
47
+ :args => [:pointer, :int64, :pointer],
48
+ :returns => :pointer
49
+
50
+ func :name => :iterinit,
51
+ :args => :pointer,
52
+ :returns => :bool
53
+ func :name => :iternext,
54
+ :args => :pointer,
55
+ :returns => :uint64
56
+
57
+ func :name => :range,
58
+ :args => [:pointer, :int64, :int64, :int, :pointer],
59
+ :returns => :pointer
60
+ end
61
+ end
62
+ end
@@ -4,17 +4,17 @@ module OklahomaMixer
4
4
  ### Constants ###
5
5
  #################
6
6
 
7
- MODES = { "r" => :HDBOREADER,
8
- "w" => :HDBOWRITER,
9
- "c" => :HDBOCREAT,
10
- "t" => :HDBOTRUNC,
11
- "e" => :HDBONOLCK,
12
- "f" => :HDBOLCKNB,
13
- "s" => :HDBOTSYNC }
14
- OPTS = { "l" => :HDBTLARGE,
15
- "d" => :HDBTDEFLATE,
16
- "b" => :HDBTBZIP,
17
- "t" => :HDBTTCBS }
7
+ MODES = { "r" => :OREADER,
8
+ "w" => :OWRITER,
9
+ "c" => :OCREAT,
10
+ "t" => :OTRUNC,
11
+ "e" => :ONOLCK,
12
+ "f" => :OLCKNB,
13
+ "s" => :OTSYNC }
14
+ OPTS = { "l" => :TLARGE,
15
+ "d" => :TDEFLATE,
16
+ "b" => :TBZIP,
17
+ "t" => :TTCBS }
18
18
 
19
19
  ###################
20
20
  ### File System ###
@@ -24,24 +24,20 @@ module OklahomaMixer
24
24
  options = args.last.is_a?(Hash) ? args.last : { }
25
25
  mode = !args.first.is_a?(Hash) ? args.first : nil
26
26
  @path = path
27
- @db = C.new
27
+ @db = lib.new
28
28
  self.default = options[:default]
29
29
  @in_transaction = false
30
30
  @abort = false
31
31
  @nested_transactions = options[:nested_transactions]
32
32
 
33
33
  try(:setmutex) if options[:mutex]
34
- if options.values_at(:bnum, :apow, :fpow, :opts).any?
35
- optimize(options.merge(:tune => true))
36
- end
37
- {:rcnum => :cache, :xmsiz => nil, :dfunit => nil}.each do |option, func|
38
- if i = options[option]
39
- try("set#{func || option}", i.to_i)
40
- end
41
- end
34
+ tune(options)
42
35
 
43
36
  warn "mode option supersedes mode argument" if mode and options[:mode]
44
37
  try(:open, path, to_enum_int(options.fetch(:mode, mode || "wc"), :mode))
38
+ rescue Exception
39
+ close if defined?(@db) and @db
40
+ raise
45
41
  end
46
42
 
47
43
  def optimize(options)
@@ -55,7 +51,7 @@ module OklahomaMixer
55
51
  attr_reader :path
56
52
 
57
53
  def file_size
58
- C.fsiz(@db)
54
+ lib.fsiz(@db)
59
55
  end
60
56
 
61
57
  def flush
@@ -94,35 +90,37 @@ module OklahomaMixer
94
90
  end
95
91
 
96
92
  def store(key, value, mode = nil)
97
- k, v = key.to_s, value.to_s
93
+ k = cast_key_in(key)
94
+ v = cast_value_in(value) unless mode == :add and not block_given?
98
95
  result = value
99
96
  if block_given?
100
97
  warn "block supersedes mode argument" unless mode.nil?
101
98
  callback = lambda { |old_value_pointer, old_size, returned_size, _|
102
- old_value = old_value_pointer.get_bytes(0, old_size)
103
- replacement = yield(key, old_value, value).to_s
104
- returned_size.put_int(0, replacement.size)
105
- FFI::MemoryPointer.from_string(replacement)
99
+ old_value = old_value_pointer.get_bytes(0, old_size)
100
+ replacement, size = cast_value_in(yield(key, old_value, value))
101
+ returned_size.put_int(0, size)
102
+ pointer = Utilities.malloc(size)
103
+ pointer.put_bytes(0, replacement) unless pointer.address.zero?
104
+ pointer
106
105
  }
107
- try(:putproc, k, k.size, v, v.size, callback, nil)
106
+ try(:putproc, k, v, callback, nil)
108
107
  else
109
- case mode
110
- when :keep
111
- result = try( :putkeep, k, k.size, v, v.size,
112
- :no_error => {21 => false} )
113
- when :cat
114
- try(:putcat, k, k.size, v, v.size)
115
- when :async
116
- try(:putasync, k, k.size, v, v.size)
117
- when :add
108
+ if mode == :keep
109
+ result = try(:putkeep, k, v, :no_error => {21 => false})
110
+ elsif mode == :cat
111
+ try(:putcat, k, v)
112
+ elsif mode == :async and self.class == HashDatabase
113
+ try(:putasync, k, v)
114
+ elsif mode == :add
118
115
  result = case value
119
- when Float then try( :adddouble, k, k.size, value,
116
+ when Float then try( :adddouble, k, value,
120
117
  :failure => lambda { |n| n.nan? } )
121
- else try( :addint, k, k.size, value.to_i,
118
+ else try( :addint, k, value.to_i,
122
119
  :failure => Utilities::INT_MIN )
123
120
  end
124
121
  else
125
- try(:put, k, k.size, v, v.size)
122
+ warn "unsupported mode for database type" if mode
123
+ try(:put, k, v)
126
124
  end
127
125
  end
128
126
  result
@@ -130,8 +128,7 @@ module OklahomaMixer
130
128
  alias_method :[]=, :store
131
129
 
132
130
  def fetch(key, *default)
133
- k = key.to_s
134
- if value = try( :read_from_func, :get, k, k.size,
131
+ if value = try( :read_from_func, :get, cast_key_in(key),
135
132
  :failure => nil, :no_error => {22 => nil} )
136
133
  value
137
134
  else
@@ -166,7 +163,7 @@ module OklahomaMixer
166
163
  def keys(options = { })
167
164
  prefix = options.fetch(:prefix, "").to_s
168
165
  limit = options.fetch(:limit, -1)
169
- list = ArrayList.new(C.fwmkeys(@db, prefix, prefix.size, limit))
166
+ list = ArrayList.new(lib.fwmkeys(@db, prefix, prefix.size, limit))
170
167
  list.to_a
171
168
  ensure
172
169
  list.free if list
@@ -182,8 +179,7 @@ module OklahomaMixer
182
179
 
183
180
  def delete(key, &missing_handler)
184
181
  value = fetch(key, &missing_handler)
185
- k = key.to_s
186
- try(:out, k, k.size, :no_error => {22 => nil})
182
+ try(:out, cast_key_in(key), :no_error => {22 => nil})
187
183
  value
188
184
  rescue IndexError
189
185
  nil
@@ -205,7 +201,7 @@ module OklahomaMixer
205
201
  alias_method :member?, :include?
206
202
 
207
203
  def size
208
- C.rnum(@db)
204
+ lib.rnum(@db)
209
205
  end
210
206
  alias_method :length, :size
211
207
 
@@ -251,6 +247,15 @@ module OklahomaMixer
251
247
  end
252
248
  end
253
249
 
250
+ def to_hash(set_default = true)
251
+ default = @default && lambda { |hash, key| @default[key] } if set_default
252
+ hash = Hash.new(&default)
253
+ each do |key, value|
254
+ hash[key] ||= value
255
+ end
256
+ hash
257
+ end
258
+
254
259
  ####################
255
260
  ### Transactions ###
256
261
  ####################
@@ -296,21 +301,26 @@ module OklahomaMixer
296
301
  #######
297
302
  private
298
303
  #######
304
+
305
+ def lib
306
+ @c ||= self.class.const_get(:C)
307
+ end
299
308
 
300
309
  def try(func, *args)
301
310
  options = args.last.is_a?(Hash) ? args.pop : { }
302
311
  failure = options.fetch(:failure, false)
303
312
  no_error = options.fetch(:no_error, { })
304
- result = func == :read_from_func ?
305
- C.read_from_func(args[0], @db, *args[1..-1]) :
306
- C.send(func, @db, *args)
307
- if (failure.is_a?(Proc) and failure[result]) or result == failure
308
- error_code = C.ecode(@db)
313
+ result = func == :read_from_func ?
314
+ lib.read_from_func(args[0], @db, *args[1..-1].flatten) :
315
+ lib.send(func, @db, *args.flatten)
316
+ if failure.is_a?(Proc) ? failure[result] : result == failure
317
+ error_code = lib.ecode(@db)
309
318
  if no_error.include? error_code
310
319
  no_error[error_code]
311
320
  else
312
- error_message = C.errmsg(error_code)
313
- fail Error::CabinetError, "#{error_message} (#{error_code})"
321
+ error_message = lib.errmsg(error_code)
322
+ fail Error::CabinetError,
323
+ "#{error_message} (error code #{error_code})"
314
324
  end
315
325
  else
316
326
  result
@@ -321,15 +331,35 @@ module OklahomaMixer
321
331
  return str_or_int if str_or_int.is_a? Integer
322
332
  const = "#{name.to_s.upcase}S"
323
333
  names = self.class.const_get(const)
324
- enum = C.const_get(const)
334
+ enum = lib.const_get(const)
325
335
  str_or_int.to_s.downcase.scan(/./m).inject(0) do |int, c|
326
336
  if n = names[c]
327
- int | enum[n]
337
+ int | enum["#{self.class.to_s[/([HBFT])\w+\z/, 1]}DB#{n}".to_sym]
328
338
  else
329
339
  warn "skipping unrecognized #{name}"
330
340
  int
331
341
  end
332
342
  end
333
343
  end
344
+
345
+ def tune(options)
346
+ if self.class == HashDatabase and
347
+ options.values_at(:bnum, :apow, :fpow, :opts).any?
348
+ optimize(options.merge(:tune => true))
349
+ end
350
+ {:rcnum => :cache, :xmsiz => nil, :dfunit => nil}.each do |option, func|
351
+ next if func == :cache and self.class != HashDatabase
352
+ if i = options[option]
353
+ try("set#{func || option}", i.to_i)
354
+ end
355
+ end
356
+ end
357
+
358
+ def cast_to_bytes_and_length(object)
359
+ bytes = object.to_s
360
+ [bytes, bytes.length]
361
+ end
362
+ alias_method :cast_key_in, :cast_to_bytes_and_length
363
+ alias_method :cast_value_in, :cast_to_bytes_and_length
334
364
  end
335
365
  end
@@ -3,109 +3,26 @@ module OklahomaMixer
3
3
  module C # :nodoc:
4
4
  extend OklahomaMixer::Utilities::FFIDSL
5
5
 
6
- MODES = enum :HDBOREADER, 1 << 0,
7
- :HDBOWRITER, 1 << 1,
8
- :HDBOCREAT, 1 << 2,
9
- :HDBOTRUNC, 1 << 3,
10
- :HDBONOLCK, 1 << 4,
11
- :HDBOLCKNB, 1 << 5,
12
- :HDBOTSYNC, 1 << 6
13
- OPTS = enum :HDBTLARGE, 1 << 0,
14
- :HDBTDEFLATE, 1 << 1,
15
- :HDBTBZIP, 1 << 2,
16
- :HDBTTCBS, 1 << 3
17
-
18
6
  prefix :tchdb
19
7
 
20
- def_new_and_del_funcs
21
- func :name => :open,
22
- :args => [:pointer, :string, MODES],
23
- :returns => :bool
24
- func :name => :sync,
25
- :args => :pointer,
26
- :returns => :bool
27
- func :name => :fsiz,
28
- :args => :pointer,
29
- :returns => :uint64
30
- func :name => :copy,
31
- :args => [:pointer, :string],
32
- :returns => :bool
33
- func :name => :defrag,
34
- :args => [:pointer, :int64],
35
- :returns => :bool
8
+ def_hash_database_consts_and_funcs
36
9
 
37
- func :name => :ecode,
38
- :args => :pointer,
39
- :returns => :int
40
- func :name => :errmsg,
41
- :args => :int,
42
- :returns => :string
43
-
44
- func :name => :setmutex,
45
- :args => :pointer,
46
- :returns => :bool
47
10
  func :name => :tune,
48
11
  :args => [:pointer, :int64, :int8, :int8, OPTS],
49
12
  :returns => :bool
50
13
  func :name => :setcache,
51
14
  :args => [:pointer, :int32],
52
15
  :returns => :bool
53
- func :name => :setxmsiz,
54
- :args => [:pointer, :int64],
55
- :returns => :bool
56
- func :name => :setdfunit,
57
- :args => [:pointer, :int32],
58
- :returns => :bool
59
16
  func :name => :optimize,
60
17
  :args => [:pointer, :int64, :int8, :int8, OPTS],
61
18
  :returns => :bool
62
-
63
- func :name => :put,
64
- :args => [:pointer, :pointer, :int, :pointer, :int],
65
- :returns => :bool
66
- func :name => :putkeep,
67
- :args => [:pointer, :pointer, :int, :pointer, :int],
68
- :returns => :bool
69
- func :name => :putcat,
70
- :args => [:pointer, :pointer, :int, :pointer, :int],
71
- :returns => :bool
19
+
72
20
  func :name => :putasync,
73
21
  :args => [:pointer, :pointer, :int, :pointer, :int],
74
22
  :returns => :bool
75
- call :name => :TCPDPROC,
76
- :args => [:pointer, :int, :pointer, :pointer],
77
- :returns => :pointer
78
- func :name => :putproc,
79
- :args => [:pointer, :pointer, :int, :pointer, :int, :TCPDPROC,
80
- :pointer],
81
- :returns => :bool
82
- func :name => :addint,
83
- :args => [:pointer, :pointer, :int, :int],
84
- :returns => :int
85
- func :name => :adddouble,
86
- :args => [:pointer, :pointer, :int, :double],
87
- :returns => :double
88
- func :name => :out,
89
- :args => [:pointer, :pointer, :int],
90
- :returns => :bool
91
- func :name => :get,
92
- :args => [:pointer, :pointer, :int, :pointer],
93
- :returns => :pointer
94
- func :name => :vanish,
95
- :args => :pointer,
96
- :returns => :bool
97
- func :name => :vanish,
98
- :args => :pointer,
99
- :returns => :bool
100
- func :name => :fwmkeys,
101
- :args => [:pointer, :pointer, :int, :int],
102
- :returns => :pointer
103
- func :name => :rnum,
104
- :args => :pointer,
105
- :returns => :uint64
106
23
 
107
24
  func :name => :iterinit,
108
- :args => [:pointer],
25
+ :args => :pointer,
109
26
  :returns => :bool
110
27
  func :name => :iternext,
111
28
  :args => [:pointer, :pointer],
@@ -113,16 +30,6 @@ module OklahomaMixer
113
30
  func :name => :iternext3,
114
31
  :args => [:pointer, :pointer, :pointer],
115
32
  :returns => :bool
116
-
117
- func :name => :tranbegin,
118
- :args => :pointer,
119
- :returns => :bool
120
- func :name => :trancommit,
121
- :args => :pointer,
122
- :returns => :bool
123
- func :name => :tranabort,
124
- :args => :pointer,
125
- :returns => :bool
126
33
  end
127
34
  end
128
35
  end
@@ -22,6 +22,12 @@ module OklahomaMixer
22
22
  defined?(@prefix) and @prefix
23
23
  end
24
24
 
25
+ def const(name, values)
26
+ const_set( name, enum( *(0...values.size).map { |i|
27
+ ["#{prefix.to_s[2..-1].upcase}#{values[i]}".to_sym, 1 << i]
28
+ }.flatten ) )
29
+ end
30
+
25
31
  def func(details)
26
32
  args = [ ]
27
33
  args << details.fetch(:alias, details[:name])
@@ -57,12 +63,108 @@ module OklahomaMixer
57
63
  func :name => :del,
58
64
  :args => :pointer
59
65
  end
66
+
67
+ def def_core_database_consts_and_funcs
68
+ const :MODES, %w[OREADER OWRITER OCREAT OTRUNC ONOLCK OLCKNB OTSYNC]
69
+
70
+ def_new_and_del_funcs
71
+
72
+ func :name => :open,
73
+ :args => [:pointer, :string, const_get(:MODES)],
74
+ :returns => :bool
75
+ func :name => :sync,
76
+ :args => :pointer,
77
+ :returns => :bool
78
+ func :name => :fsiz,
79
+ :args => :pointer,
80
+ :returns => :uint64
81
+ func :name => :copy,
82
+ :args => [:pointer, :string],
83
+ :returns => :bool
84
+
85
+ func :name => :ecode,
86
+ :args => :pointer,
87
+ :returns => :int
88
+ func :name => :errmsg,
89
+ :args => :int,
90
+ :returns => :string
91
+
92
+ func :name => :setmutex,
93
+ :args => :pointer,
94
+ :returns => :bool
95
+
96
+ func :name => :vanish,
97
+ :args => :pointer,
98
+ :returns => :bool
99
+ func :name => :rnum,
100
+ :args => :pointer,
101
+ :returns => :uint64
102
+
103
+ func :name => :tranbegin,
104
+ :args => :pointer,
105
+ :returns => :bool
106
+ func :name => :trancommit,
107
+ :args => :pointer,
108
+ :returns => :bool
109
+ func :name => :tranabort,
110
+ :args => :pointer,
111
+ :returns => :bool
112
+ end
113
+
114
+ def def_hash_database_consts_and_funcs
115
+ const :OPTS, %w[TLARGE TDEFLATE TBZIP TTCBS]
116
+
117
+ def_core_database_consts_and_funcs
118
+
119
+ func :name => :defrag,
120
+ :args => [:pointer, :int64],
121
+ :returns => :bool
122
+
123
+ func :name => :setxmsiz,
124
+ :args => [:pointer, :int64],
125
+ :returns => :bool
126
+ func :name => :setdfunit,
127
+ :args => [:pointer, :int32],
128
+ :returns => :bool
129
+
130
+ func :name => :put,
131
+ :args => [:pointer, :pointer, :int, :pointer, :int],
132
+ :returns => :bool
133
+ func :name => :putkeep,
134
+ :args => [:pointer, :pointer, :int, :pointer, :int],
135
+ :returns => :bool
136
+ func :name => :putcat,
137
+ :args => [:pointer, :pointer, :int, :pointer, :int],
138
+ :returns => :bool
139
+ call :name => :TCPDPROC,
140
+ :args => [:pointer, :int, :pointer, :pointer],
141
+ :returns => :pointer
142
+ func :name => :putproc,
143
+ :args => [:pointer, :pointer, :int, :pointer, :int, :TCPDPROC,
144
+ :pointer],
145
+ :returns => :bool
146
+ func :name => :addint,
147
+ :args => [:pointer, :pointer, :int, :int],
148
+ :returns => :int
149
+ func :name => :adddouble,
150
+ :args => [:pointer, :pointer, :int, :double],
151
+ :returns => :double
152
+ func :name => :out,
153
+ :args => [:pointer, :pointer, :int],
154
+ :returns => :bool
155
+ func :name => :get,
156
+ :args => [:pointer, :pointer, :int, :pointer],
157
+ :returns => :pointer
158
+ func :name => :fwmkeys,
159
+ :args => [:pointer, :pointer, :int, :int],
160
+ :returns => :pointer
161
+ end
60
162
  end
61
163
 
62
- int_min = `getconf INT_MIN 2>&1`[/-\d+/]
63
- unless INT_MIN = int_min && int_min.to_i
64
- warn "set OKMixer::Utilities::INT_MIN before using counters"
164
+ unless int_min = `getconf INT_MIN 2>&1`[/-\d+/]
165
+ warn "set OKMixer::Utilities::INT_MIN before using the :add storage mode"
65
166
  end
167
+ INT_MIN = int_min && int_min.to_i
66
168
 
67
169
  def self.temp_int
68
170
  int = FFI::MemoryPointer.new(:int)
@@ -82,7 +184,10 @@ module OklahomaMixer
82
184
 
83
185
  prefix :tc
84
186
 
85
- func :name => :free,
86
- :args => :pointer
187
+ func :name => :malloc,
188
+ :args => :size_t,
189
+ :returns => :pointer
190
+ func :name => :free,
191
+ :args => :pointer
87
192
  end
88
193
  end