jackowayed-rufus-tokyo 0.1.13.1 → 0.1.13.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+
2
+ Copyright (c) 2009, John Mettraux, jmettraux@gmail.com
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
data/TODO.txt ADDED
@@ -0,0 +1,20 @@
1
+
2
+ [x] table : bench find(1) after set_index
3
+ [x] table : bench insert(1) after set_index
4
+
5
+ [x] align edo#new on tokyo#new
6
+ [ ] horizontal (bdb hdb fdb) tests for tokyo and edo
7
+
8
+ [x] rdoc unix socket for tyrant
9
+ [x] edo : tran
10
+ [ ] bench ux socket
11
+
12
+ [ ] TT (TC) call [lua] function
13
+ [ ] queryout
14
+
15
+ [ ] impl lget/lput/ldelete in Rufus::Edo::Cabinet
16
+
17
+ [ ] maybe supported different libs for migrations...
18
+
19
+ [ ] document ENV['TOKYO_TYRANT_LIB'] & _CABINET_
20
+
data/lib/rufus-edo.rb ADDED
@@ -0,0 +1,3 @@
1
+
2
+ require 'rufus/edo'
3
+
@@ -0,0 +1,3 @@
1
+
2
+ require 'rufus/tokyo'
3
+
data/lib/rufus/edo.rb ADDED
@@ -0,0 +1,39 @@
1
+ #--
2
+ # Copyright (c) 2009, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+
26
+ begin
27
+
28
+ require 'tokyocabinet'
29
+
30
+ rescue LoadError
31
+
32
+ raise LoadError.new(
33
+ "tokyocabinet 'native' C bindings not present on your system, " +
34
+ "see http://github.com/jmettraux/rufus-tokyo/tree/master/lib/rufus/edo")
35
+ end
36
+
37
+ require 'rufus/edo/cabinet/abstract'
38
+ require 'rufus/edo/cabinet/table'
39
+
@@ -0,0 +1,306 @@
1
+ #--
2
+ # Copyright (c) 2009, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+
26
+ require 'rufus/tokyo/hmethods'
27
+ require 'rufus/tokyo/transactions'
28
+
29
+
30
+ module Rufus::Edo
31
+
32
+ #
33
+ # The base cabinet methods are gathered here. They focus on wrapping
34
+ # Hirabayashi-san's methods.
35
+ #
36
+ # This module is included by Edo::Cabinet and Edo::NTyrant. Placing the
37
+ # methods in this module avoids having to load 'TokyoCabinet' when using
38
+ # only rufus/edo/ntyrant.
39
+ #
40
+ module CabinetCore
41
+
42
+ include Rufus::Tokyo::HashMethods
43
+ include Rufus::Tokyo::Transactions
44
+
45
+ def self.included (target_module)
46
+
47
+ target_module.module_eval do
48
+ #
49
+ # Same args as initialize, but can take a block form that will
50
+ # close the db when done. Similar to File.open (via Zev)
51
+ #
52
+ def self.open (name, params={})
53
+ db = self.new(name, params)
54
+ if block_given?
55
+ yield db
56
+ nil
57
+ else
58
+ db
59
+ end
60
+ ensure
61
+ db.close if block_given? && db
62
+ end
63
+ end
64
+ end
65
+
66
+ # Returns the path to this database.
67
+ #
68
+ def path
69
+
70
+ @path
71
+ end
72
+
73
+ # No comment
74
+ #
75
+ def []= (k, v)
76
+ @db.put(k, v) || raise_error
77
+ end
78
+
79
+ # (The actual #[] method is provided by HashMethods)
80
+ #
81
+ def get (k)
82
+ @db.get(k)
83
+ end
84
+ protected :get
85
+
86
+ # Removes a record from the cabinet, returns the value if successful
87
+ # else nil.
88
+ #
89
+ def delete (k)
90
+ v = self[k]
91
+ @db.out(k) ? v : nil
92
+ end
93
+
94
+ # Returns the number of records in the 'cabinet'
95
+ #
96
+ def size
97
+ @db.rnum
98
+ end
99
+
100
+ # Removes all the records in the cabinet (use with care)
101
+ #
102
+ # Returns self (like Ruby's Hash does).
103
+ #
104
+ def clear
105
+ @db.vanish || raise_error
106
+ self
107
+ end
108
+
109
+ # Returns the 'weight' of the db (in bytes)
110
+ #
111
+ def weight
112
+ @db.fsiz
113
+ end
114
+
115
+ # Closes the cabinet (and frees the datastructure allocated for it),
116
+ # returns true in case of success.
117
+ #
118
+ def close
119
+ @db.close || raise_error
120
+ end
121
+
122
+ # Copies the current cabinet to a new file.
123
+ #
124
+ # Returns true if it was successful.
125
+ #
126
+ def copy (target_path)
127
+ @db.copy(target_path)
128
+ end
129
+
130
+ # Copies the current cabinet to a new file.
131
+ #
132
+ # Does it by copying each entry afresh to the target file. Spares some
133
+ # space, hence the 'compact' label...
134
+ #
135
+ def compact_copy (target_path)
136
+ @other_db = self.class.new(target_path)
137
+ self.each { |k, v| @other_db[k] = v }
138
+ @other_db.close
139
+ end
140
+
141
+ # "synchronize updated contents of an abstract database object with
142
+ # the file and the device"
143
+ #
144
+ def sync
145
+ @db.sync || raise_error
146
+ end
147
+
148
+ # Returns an array of all the primary keys in the db.
149
+ #
150
+ # With no options given, this method will return all the keys (strings)
151
+ # in a Ruby array.
152
+ #
153
+ # :prefix --> returns only the keys who match a given string prefix
154
+ #
155
+ # :limit --> returns a limited number of keys
156
+ #
157
+ def keys (options={})
158
+
159
+ if pref = options[:prefix]
160
+
161
+ @db.fwmkeys(pref, options[:limit] || -1)
162
+
163
+ else
164
+
165
+ limit = options[:limit] || -1
166
+ limit = nil if limit < 1
167
+
168
+ l = []
169
+
170
+ @db.iterinit
171
+
172
+ while (k = @db.iternext)
173
+ break if limit and l.size >= limit
174
+ l << k
175
+ end
176
+
177
+ l
178
+ end
179
+ end
180
+
181
+ # Deletes all the entries whose keys begin with the given prefix
182
+ #
183
+ def delete_keys_with_prefix (prefix)
184
+
185
+ #call_misc('outlist', lib.abs_fwmkeys2(@db, prefix, -1))
186
+ # # -1 for no limits
187
+ @db.fwmkeys(prefix, -1).each { |k| self.delete(k) }
188
+ nil
189
+ end
190
+
191
+ # Given a list of keys, returns a Hash { key => value } of the
192
+ # matching entries (in one sweep).
193
+ #
194
+ # Warning : this is a naive (slow) implementation.
195
+ #
196
+ def lget (keys)
197
+
198
+ #Hash[*call_misc('getlist', Rufus::Tokyo::List.new(keys))]
199
+ keys.inject({}) { |h, k| v = self[k]; h[k] = v if v; h }
200
+ end
201
+
202
+ #--
203
+ # default impl provided by HashMethods
204
+ #
205
+ #def merge! (hash)
206
+ # call_misc(
207
+ # 'putlist',
208
+ # hash.inject(Rufus::Tokyo::List.new) { |l, (k, v)| l << k; l << v; l })
209
+ # self
210
+ #end
211
+ #++
212
+ alias :lput :merge!
213
+
214
+ # Given a list of keys, deletes all the matching entries (in one sweep).
215
+ #
216
+ # Warning : this is a naive (slow) implementation.
217
+ #
218
+ def ldelete (keys)
219
+
220
+ #call_misc('outlist', Rufus::Tokyo::List.new(keys))
221
+ keys.each { |k| self.delete(k) }
222
+ nil
223
+ end
224
+
225
+ # Increments the (integer) value behind a key with the given val
226
+ #
227
+ def addint (key, val)
228
+
229
+ i = @db.addint(key, val)
230
+
231
+ raise(EdoError.new(
232
+ "incr failed, there is probably already a string value set " +
233
+ "for the key '#{key}'"
234
+ )) unless i
235
+
236
+ i
237
+ end
238
+ alias :int_incr :addint
239
+
240
+ # Increments the (double) value behind a key with the given val
241
+ #
242
+ def adddouble (key, val)
243
+
244
+ d = @db.adddouble(key, val)
245
+
246
+ raise(EdoError.new(
247
+ "incr failed, there is probably already a string value set " +
248
+ "for the key '#{key}'"
249
+ )) unless d
250
+
251
+ d
252
+ end
253
+ alias :double_incr :adddouble
254
+
255
+ # Returns the underlying 'native' Ruby object (of the class devised by
256
+ # Hirabayashi-san)
257
+ #
258
+ def original
259
+ @db
260
+ end
261
+
262
+ # This is rather low-level, you'd better use #transaction like in
263
+ #
264
+ # db.transaction do
265
+ # db['a'] = 'alpha'
266
+ # db['b'] = 'bravo'
267
+ # db.abort if something_went_wrong?
268
+ # end
269
+ #
270
+ # Note that fixed-length dbs do not support transactions. It will result
271
+ # in a NoMethodError.
272
+ #
273
+ def tranbegin
274
+ @db.tranbegin
275
+ end
276
+
277
+ # This is rather low-level use #transaction and a block for a higher-level
278
+ # technique.
279
+ #
280
+ # Note that fixed-length dbs do not support transactions. It will result
281
+ # in a NoMethodError.
282
+ #
283
+ def trancommit
284
+ @db.trancommit
285
+ end
286
+
287
+ # This is rather low-level use #transaction and a block for a higher-level
288
+ # technique.
289
+ #
290
+ # Note that fixed-length dbs do not support transactions. It will result
291
+ # in a NoMethodError.
292
+ #
293
+ def tranabort
294
+ @db.tranabort
295
+ end
296
+
297
+ protected
298
+
299
+ def raise_error
300
+ code = @db.ecode
301
+ message = @db.errmsg(code)
302
+ raise EdoError.new("(err #{code}) #{message}")
303
+ end
304
+ end
305
+ end
306
+
@@ -0,0 +1,207 @@
1
+ #--
2
+ # Copyright (c) 2009, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+
26
+ require 'tokyocabinet' # gem install careo-tokyocabinet
27
+
28
+ require 'rufus/edo/cabcore'
29
+ require 'rufus/tokyo/config'
30
+
31
+
32
+ module Rufus::Edo
33
+
34
+ #
35
+ # A cabinet wired 'natively' to the libtokyocabinet.dynlib (approximatevely
36
+ # 2 times faster than the wiring over FFI).
37
+ #
38
+ # This class has the exact same methods as Rufus::Tokyo::Cabinet. It's faster
39
+ # though. The advantage of Rufus::Tokyo::Cabinet lies in that in runs on
40
+ # Ruby 1.8, 1.9 and JRuby.
41
+ #
42
+ # You need to have Hirabayashi-san's binding installed to use this
43
+ # Rufus::Edo::Cabinet :
44
+ #
45
+ # http://github.com/jmettraux/rufus-tokyo/tree/master/lib/rufus/edo
46
+ #
47
+ # You can then write code like :
48
+ #
49
+ # require 'rubygems'
50
+ # require 'rufus/edo' # sudo gem install rufus-tokyo
51
+ #
52
+ # db = Rufus::Edo::Cabinet.new('data.tch')
53
+ #
54
+ # db['hello'] = 'world'
55
+ #
56
+ # puts db['hello']
57
+ # # -> 'world'
58
+ #
59
+ # db.close
60
+ #
61
+ # This cabinet wraps hashes, b+ trees and fixed length databases. For tables,
62
+ # see Rufus::Edo::Table
63
+ #
64
+ class Cabinet
65
+
66
+ include Rufus::Edo::CabinetCore
67
+ include Rufus::Tokyo::CabinetConfig
68
+
69
+ # Initializes and open a cabinet (hash, b+ tree or fixed-size)
70
+ #
71
+ # db = Rufus::Edo::Cabinet.new('data.tch')
72
+ # # or
73
+ # db = Rufus::Edo::Cabinet.new('data', :type => :hash)
74
+ #
75
+ # 3 types are recognized :hash (.tch), :btree (.tcb) and :fixed (.tcf). For
76
+ # tables, see Rufus::Edo::Table
77
+ #
78
+ # == parameters
79
+ #
80
+ # There are two ways to pass parameters at the opening of a db :
81
+ #
82
+ # db = Rufus::Edo::Cabinet.new('data.tch#opts=ld#mode=w') # or
83
+ # db = Rufus::Edo::Cabinet.new('data.tch', :opts => 'ld', :mode => 'w')
84
+ #
85
+ # most verbose :
86
+ #
87
+ # db = Rufus::Edo::Cabinet.new(
88
+ # 'data', :type => :hash, :opts => 'ld', :mode => 'w')
89
+ #
90
+ # === mode
91
+ #
92
+ # * :mode a set of chars ('r'ead, 'w'rite, 'c'reate, 't'runcate,
93
+ # 'e' non locking, 'f' non blocking lock), default is 'wc'
94
+ #
95
+ # === other parameters
96
+ #
97
+ # 'On-memory hash database supports "bnum", "capnum", and "capsiz".
98
+ # On-memory tree database supports "capnum" and "capsiz".
99
+ # Hash database supports "mode", "bnum", "apow", "fpow", "opts",
100
+ # "rcnum", and "xmsiz".
101
+ # B+ tree database supports "mode", "lmemb", "nmemb", "bnum", "apow",
102
+ # "fpow", "opts", "lcnum", "ncnum", and "xmsiz".
103
+ # Fixed-length database supports "mode", "width", and "limsiz"'
104
+ #
105
+ # * :opts a set of chars ('l'arge, 'd'eflate, 'b'zip2, 't'cbs)
106
+ # (usually empty or something like 'ld' or 'lb')
107
+ #
108
+ # * :bnum number of elements of the bucket array
109
+ # * :apow size of record alignment by power of 2 (defaults to 4)
110
+ # * :fpow maximum number of elements of the free block pool by
111
+ # power of 2 (defaults to 10)
112
+ # * :mutex when set to true, makes sure only 1 thread at a time
113
+ # accesses the table (well, Ruby, global thread lock, ...)
114
+ #
115
+ # * :rcnum specifies the maximum number of records to be cached.
116
+ # If it is not more than 0, the record cache is disabled.
117
+ # It is disabled by default.
118
+ # * :lcnum specifies the maximum number of leaf nodes to be cached.
119
+ # If it is not more than 0, the default value is specified.
120
+ # The default value is 2048.
121
+ # * :ncnum specifies the maximum number of non-leaf nodes to be
122
+ # cached. If it is not more than 0, the default value is
123
+ # specified. The default value is 512.
124
+ #
125
+ # * :lmemb number of members in each leaf page (defaults to 128) (btree)
126
+ # * :nmemb number of members in each non-leaf page (default 256) (btree)
127
+ #
128
+ # * :width width of the value of each record (default 255) (fixed)
129
+ # * :limsiz limit size of the database file (default 268_435_456) (fixed)
130
+ #
131
+ # * :xmsiz specifies the size of the extra mapped memory. If it is
132
+ # not more than 0, the extra mapped memory is disabled.
133
+ # The default size is 67108864.
134
+ #
135
+ # * :capnum specifies the capacity number of records.
136
+ # * :capsiz specifies the capacity size of using memory.
137
+ #
138
+ # * :dfunit unit step number. If it is not more than 0,
139
+ # the auto defragmentation is disabled. (Since TC 1.4.21)
140
+ #
141
+ #
142
+ # = NOTE :
143
+ #
144
+ # On reopening a file, Cabinet will tend to stick to the parameters as
145
+ # set when the file was opened. To change that, have a look at the
146
+ # man pages of the various command line tools coming with Tokyo Cabinet.
147
+ #
148
+ def initialize (path, params={})
149
+
150
+ conf = determine_conf(path, params)
151
+
152
+ klass = {
153
+ :hash => TokyoCabinet::HDB,
154
+ :btree => TokyoCabinet::BDB,
155
+ :fixed => TokyoCabinet::FDB
156
+ }[conf[:type]]
157
+
158
+ @db = klass.new
159
+
160
+ #
161
+ # tune
162
+
163
+ tuning_parameters = case conf[:type]
164
+ when :hash then [ :bnum, :apow, :fpow, :opts ]
165
+ when :btree then [ :lmemb, :nmemb, :bnum, :apow, :fpow, :opts ]
166
+ when :fixed then [ :bnum, :width, :limsiz ]
167
+ end
168
+
169
+ @db.tune(*tuning_parameters.collect { |o| conf[o] })
170
+
171
+ #
172
+ # set cache
173
+
174
+ cache_values = case conf[:type]
175
+ when :hash then [ :rcnum ]
176
+ when :btree then [ :lcnum, :ncnum ]
177
+ when :fixed then nil
178
+ end
179
+
180
+ @db.setcache(*cache_values.collect { |o| conf[o] }) if cache_values
181
+
182
+ #
183
+ # set xmsiz
184
+
185
+ @db.setxmsiz(conf[:xmsiz]) unless conf[:type] == :fixed
186
+
187
+ #
188
+ # set dfunit (TC > 1.4.21)
189
+
190
+ @db.setdfunit(conf[:dfunit]) if @db.respond_to?(:setdfunit)
191
+
192
+ #
193
+ # open
194
+
195
+ @path = conf[:path]
196
+
197
+ @db.open(@path, conf[:mode]) || raise_error
198
+
199
+ #
200
+ # default
201
+
202
+ self.default = params[:default]
203
+ @default_proc ||= params[:default_proc]
204
+ end
205
+ end
206
+ end
207
+