rufus-tokyo 0.1.0

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