oklahoma_mixer 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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