rufus-tokyo 0.1.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.
data/CHANGELOG.txt ADDED
@@ -0,0 +1,8 @@
1
+
2
+ = rufus-tokyo CHANGELOG.txt
3
+
4
+
5
+ == rufus-tokyo - 0.1.0 released 2009/01/23
6
+
7
+ - initial release
8
+
data/CREDITS.txt ADDED
@@ -0,0 +1,8 @@
1
+
2
+ = CREDITS.txt rufus-tokyo gem
3
+
4
+ many thanks to the authors of Tokyo Cabinet and ruby-ffi
5
+
6
+ http://tokyocabinet.sourceforge.net
7
+ http://kenai.com/projects/ruby-ffi
8
+
data/README.txt ADDED
@@ -0,0 +1,118 @@
1
+
2
+ = rufus-tokyo
3
+
4
+ ruby-ffi based interface to Tokyo Cabinet.
5
+
6
+ It focuses on the abstract API for now (http://tokyocabinet.sourceforge.net/spex-en.html#tcadbapi)
7
+
8
+
9
+ == installation
10
+
11
+ sudo gem install ffi rufus-tokyo
12
+
13
+ (see after 'usage' for how to install Tokyo Cabinet if required)
14
+
15
+
16
+ == usage
17
+
18
+ to create a hash (file named 'data.tch')
19
+
20
+ require 'rubygems'
21
+ require 'rufus/tokyo'
22
+
23
+ db = Rufus::Tokyo::Cabinet.new('data.tch')
24
+
25
+ db['nada'] = 'surf'
26
+
27
+ p db['nada'] # => 'surf'
28
+ p db['lost'] # => nil
29
+
30
+ 5000.times { |i| db[i.to_s] = "x" }
31
+
32
+ p db.inject { |r, (k, v)| k } # => 4999
33
+
34
+ db.close
35
+
36
+
37
+ more in the rdoc
38
+
39
+ http://rufus.rubyforge.org/rufus-tokyo/
40
+ http://rufus.rubyforge.org/rufus-tokyo/classes/Rufus/Tokyo/Cabinet.html
41
+
42
+ or directly in the source
43
+
44
+ http://github.com/jmettraux/rufus-tokyo/blob/master/lib/rufus/tokyo.rb
45
+
46
+
47
+ == Tokyo Cabinet install
48
+
49
+ On a Mac, you would do
50
+
51
+ sudo port install tokyocabinet
52
+
53
+
54
+ If you don't have Tokyo Cabinet on your system, you can get it and compile it :
55
+
56
+ git clone git://github.com/etrepum/tokyo-cabinet.git
57
+ cd tokyo-cabinet
58
+ git checkout 1.4.1
59
+ ./configure
60
+ make
61
+
62
+ eventually
63
+
64
+ sudo make install
65
+
66
+
67
+ == dependencies
68
+
69
+ the ruby gem ffi
70
+
71
+
72
+ == mailing list
73
+
74
+ On the rufus-ruby list[http://groups.google.com/group/rufus-ruby] :
75
+
76
+ http://groups.google.com/group/rufus-ruby
77
+
78
+
79
+ == issue tracker
80
+
81
+ http://rubyforge.org/tracker/?atid=18584&group_id=4812&func=browse
82
+
83
+
84
+ == irc
85
+
86
+ irc.freenode.net #ruote
87
+
88
+
89
+ == source
90
+
91
+ http://github.com/jmettraux/rufus-tokyo
92
+
93
+ git clone git://github.com/jmettraux/rufus-tokyo.git
94
+
95
+
96
+ == credits
97
+
98
+ many thanks to the authors of Tokyo Cabinet and to the authors of ruby-ffi
99
+
100
+ http://tokyocabinet.sourceforge.net
101
+ http://kenai.com/projects/ruby-ffi
102
+
103
+
104
+ == author
105
+
106
+ John Mettraux, jmettraux@gmail.com
107
+ http://jmettraux.wordpress.com
108
+
109
+
110
+ == the rest of Rufus
111
+
112
+ http://rufus.rubyforge.org
113
+
114
+
115
+ == license
116
+
117
+ MIT
118
+
@@ -0,0 +1,3 @@
1
+
2
+ require 'rufus/tokyo'
3
+
@@ -0,0 +1,243 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2009, John Mettraux, jmettraux@gmail.com
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ #++
23
+ #
24
+
25
+ #
26
+ # "made in Japan"
27
+ #
28
+ # jmettraux@gmail.com
29
+ #
30
+
31
+ require 'rubygems'
32
+ require 'ffi'
33
+
34
+ module Rufus
35
+ module Tokyo
36
+
37
+ VERSION = '0.1.0'
38
+
39
+ module Func #:nodoc#
40
+ extend FFI::Library
41
+
42
+ #
43
+ # find Tokyo Cabinet lib
44
+
45
+ paths = Array(ENV['TOKYO_CABINET_LIB'] || %w{
46
+ /opt/local/lib/libtokyocabinet.dylib
47
+ /usr/local/lib/libtokyocabinet.dylib
48
+ /usr/local/lib/libtokyocabinet.so
49
+ })
50
+
51
+ paths.each do |path|
52
+ if File.exist?(path)
53
+ ffi_lib(path)
54
+ @lib = path
55
+ break
56
+ end
57
+ end
58
+
59
+ attach_function :tcadbnew, [], :pointer
60
+
61
+ attach_function :tcadbopen, [ :pointer, :string ], :int
62
+ attach_function :tcadbclose, [ :pointer ], :int
63
+
64
+ attach_function :tcadbdel, [ :pointer ], :void
65
+
66
+ attach_function :tcadbrnum, [ :pointer ], :uint64
67
+ attach_function :tcadbsize, [ :pointer ], :uint64
68
+
69
+ attach_function :tcadbput2, [ :pointer, :string, :string ], :int
70
+ attach_function :tcadbget2, [ :pointer, :string ], :string
71
+ attach_function :tcadbout2, [ :pointer, :string ], :int
72
+
73
+ attach_function :tcadbiterinit, [ :pointer ], :int
74
+ attach_function :tcadbiternext2, [ :pointer ], :string
75
+
76
+ #def self.method_missing (m, *args)
77
+ # mm = "tcadb#{m}"
78
+ # self.respond_to?(mm) ? self.send(mm, *args) : super
79
+ #end
80
+ #
81
+ # makes JRuby unhappy, forget it.
82
+ end
83
+
84
+ #
85
+ # Returns the path to the Tokyo Cabinet dynamic library currently in use
86
+ #
87
+ def self.lib
88
+ Rufus::Tokyo::Func.instance_variable_get(:@lib)
89
+ end
90
+
91
+ #
92
+ # A 'cabinet', ie a Tokyo Cabinet database.
93
+ #
94
+ # Follows the abstract API described at :
95
+ #
96
+ # http://tokyocabinet.sourceforge.net/spex-en.html#tcadbapi
97
+ #
98
+ # An usage example :
99
+ #
100
+ # db = Rufus::Tokyo::Cabinet.new('test_data.tch')
101
+ # db['pillow'] = 'Shonagon'
102
+ #
103
+ # db.size # => 1
104
+ # db['pillow'] # => 'Shonagon'
105
+ #
106
+ # db.delete('pillow') # => 'Shonagon'
107
+ # db.size # => 0
108
+ #
109
+ # db.close
110
+ #
111
+ class Cabinet
112
+ include Enumerable
113
+
114
+ #
115
+ # Creates/opens the cabinet, raises an exception in case of
116
+ # creation/opening failure.
117
+ #
118
+ # This method accepts a 'name' parameter and an optional 'params' hash
119
+ # parameter.
120
+ #
121
+ # 'name' follows the syntax described at
122
+ #
123
+ # http://tokyocabinet.sourceforge.net/spex-en.html#tcadbapi
124
+ #
125
+ # under tcadbopen(). For example :
126
+ #
127
+ # db = Rufus::Tokyo::Cabinet.new('casket.tch#bnum=100000#opts=ld')
128
+ #
129
+ # will open (eventually create) a hash database backed in the file
130
+ # 'casket.tch' with a bucket number of 100000 and the 'large' and
131
+ # 'deflate' options (opts) turned on.
132
+ #
133
+ # == :hash or :tree
134
+ #
135
+ # Setting the name to :hash or :tree simply will create a in-memory hash
136
+ # or tree respectively (see #new_tree and #new_hash).
137
+ #
138
+ # == tuning parameters
139
+ #
140
+ # It's ok to use the optional params hash to pass tuning parameters and
141
+ # options, thus
142
+ #
143
+ # db = Rufus::Tokyo::Cabinet.new('casket.tch#bnum=100000#opts=ld')
144
+ #
145
+ # and
146
+ #
147
+ # db = Rufus::Tokyo::Cabinet.new(
148
+ # 'casket.tch', :bnum => 100000, :opts => 'ld')
149
+ #
150
+ # are equivalent.
151
+ #
152
+ # == mode
153
+ #
154
+ # To open a db in read-only mode :
155
+ #
156
+ # db = Rufus::Tokyo::Cabinet.new('casket.tch#mode=r')
157
+ # db = Rufus::Tokyo::Cabinet.new('casket.tch', :mode => 'r')
158
+ #
159
+ def initialize (name, params={})
160
+
161
+ @db = Rufus::Tokyo::Func.tcadbnew
162
+
163
+ name = '*' if name == :hash # in memory hash database
164
+ name = '+' if name == :tree # in memory B+ tree database
165
+
166
+ name = name + params.collect { |k, v| "##{k}=#{v}" }.join('')
167
+
168
+ (Rufus::Tokyo::Func.tcadbopen(@db, name) == 1) ||
169
+ raise("failed to open/create db '#{name}'")
170
+ end
171
+
172
+ #
173
+ # Returns a new in-memory hash. Accepts the same optional params hash
174
+ # as new().
175
+ #
176
+ def self.new_hash (params={})
177
+ self.new(:hash, params)
178
+ end
179
+
180
+ #
181
+ # Returns a new in-memory B+ tree. Accepts the same optional params hash
182
+ # as new().
183
+ #
184
+ def self.new_tree (params={})
185
+ self.new(:tree, params)
186
+ end
187
+
188
+ def []= (k, v)
189
+ Rufus::Tokyo::Func.tcadbput2(@db, k, v)
190
+ end
191
+
192
+ def [] (k)
193
+ Rufus::Tokyo::Func.tcadbget2(@db, k) rescue nil
194
+ end
195
+
196
+ #
197
+ # Removes a record from the cabinet, returns the value if successful
198
+ # else nil.
199
+ #
200
+ def delete (k)
201
+ v = self[k]
202
+ (Rufus::Tokyo::Func.tcadbout2(@db, k) == 1) ? v : nil
203
+ end
204
+
205
+ #
206
+ # Returns the number of records in the 'cabinet'
207
+ #
208
+ def size
209
+ Rufus::Tokyo::Func.tcadbrnum(@db)
210
+ end
211
+
212
+ #
213
+ # Returns the 'weight' of the db (in bytes)
214
+ #
215
+ def weight
216
+ Rufus::Tokyo::Func.tcadbsize(@db)
217
+ end
218
+
219
+ #
220
+ # Closes the cabinet (and frees the datastructure allocated for it),
221
+ # returns true in case of success.
222
+ #
223
+ def close
224
+ result = Rufus::Tokyo::Func.tcadbclose(@db)
225
+ Rufus::Tokyo::Func.tcadbdel(@db)
226
+ (result == 1)
227
+ end
228
+
229
+ #
230
+ # The classical Ruby each (unlocks the power of the Enumerable mixin)
231
+ #
232
+ def each
233
+
234
+ Rufus::Tokyo::Func.tcadbiterinit(@db) # concurrent access ??
235
+
236
+ while (k = (Rufus::Tokyo::Func.tcadbiternext2(@db) rescue nil))
237
+ yield(k, self[k])
238
+ end
239
+ end
240
+ end
241
+ end
242
+ end
243
+
@@ -0,0 +1,44 @@
1
+
2
+ #
3
+ # Testing rufus-tokyo
4
+ #
5
+ # Fri Jan 23 08:31:01 JST 2009
6
+ #
7
+
8
+ require File.dirname(__FILE__) + '/test_base'
9
+
10
+ require 'test/unit'
11
+
12
+ require 'rufus/tokyo'
13
+
14
+
15
+ class CabinetZero < Test::Unit::TestCase
16
+
17
+ #def setup
18
+ #end
19
+ #def teardown
20
+ #end
21
+
22
+ def test_lib
23
+
24
+ assert_not_nil Rufus::Tokyo.lib
25
+ end
26
+
27
+ def test_basic_workflow
28
+
29
+ db = Rufus::Tokyo::Cabinet.new('test_data.tch')
30
+ db['pillow'] = 'Shonagon'
31
+
32
+ assert_equal 1, db.size
33
+ assert_equal 'Shonagon', db['pillow']
34
+
35
+ assert_equal 'Shonagon', db.delete('pillow')
36
+ assert_equal 0, db.size
37
+
38
+ assert db.close
39
+ end
40
+
41
+ # TODO : memory tests
42
+
43
+ end
44
+
data/test/mem.rb ADDED
@@ -0,0 +1,49 @@
1
+
2
+ %w{ lib test }.each do |path|
3
+ path = File.expand_path(File.dirname(__FILE__) + '/../' + path)
4
+ $: << path unless $:.include?(path)
5
+ end
6
+
7
+ require 'fileutils'
8
+
9
+
10
+ def self_ps
11
+ ps = `ps -v #{$$}`.split("\n").last.split(' ')
12
+ %w{
13
+ pid stat time sl re pagein vsz rss lim tsiz pcpu pmem command
14
+ }.inject({}) { |h, k|
15
+ h[k.intern] = ps.shift; h
16
+ }
17
+ end
18
+
19
+ def pmem (msg)
20
+ p [ msg, "#{self_ps[:vsz].to_i / 1024}k" ]
21
+ end
22
+
23
+ pmem 'starting'
24
+
25
+ require 'rubygems'
26
+ require 'rufus/tokyo'
27
+
28
+ FileUtils.rm('test_mem.tch')
29
+
30
+ db = Rufus::Tokyo::Cabinet.new('test_mem.tch')
31
+
32
+ pmem 'wired to db'
33
+
34
+ 500_000.times { |i| db[i.to_s] = "value#{i}" }
35
+
36
+ pmem 'loaded 500_000 records'
37
+
38
+ db.each { |k, v| k }
39
+
40
+ pmem 'iterated 500_000 records'
41
+
42
+ a = db.collect { |k, v| k + v }
43
+
44
+ pmem 'collected 500_000 records'
45
+
46
+ db.close
47
+
48
+ pmem 'closed db'
49
+
data/test/test.rb ADDED
@@ -0,0 +1,5 @@
1
+
2
+ require File.dirname(__FILE__) + '/test_base'
3
+
4
+ require 'cabinet_0_test'
5
+
data/test/test_base.rb ADDED
@@ -0,0 +1,6 @@
1
+
2
+ %w{ lib test }.each do |path|
3
+ path = File.expand_path(File.dirname(__FILE__) + '/../' + path)
4
+ $: << path unless $:.include?(path)
5
+ end
6
+
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rufus-tokyo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - John Mettraux
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-23 00:00:00 +09:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ruby-ffi
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: jmettraux@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.txt
33
+ - CHANGELOG.txt
34
+ - CREDITS.txt
35
+ files:
36
+ - lib/rufus
37
+ - lib/rufus/tokyo.rb
38
+ - lib/rufus-tokyo.rb
39
+ - test/cabinet_0_test.rb
40
+ - test/mem.rb
41
+ - test/test.rb
42
+ - test/test_base.rb
43
+ - README.txt
44
+ - CHANGELOG.txt
45
+ - CREDITS.txt
46
+ has_rdoc: true
47
+ homepage: http://rufus.rubyforge.org/
48
+ post_install_message:
49
+ rdoc_options: []
50
+
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ requirements:
66
+ - ruby-ffi
67
+ rubyforge_project: rufus
68
+ rubygems_version: 1.3.1
69
+ signing_key:
70
+ specification_version: 2
71
+ summary: ruby-ffi based lib to access Tokyo Cabinet
72
+ test_files:
73
+ - test/test.rb