jackowayed-rufus-tokyo 0.1.13.1 → 0.1.13.2

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/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
+