rufus-tokyo 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,203 @@
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 'tokyocabinet' # gem install careo-tokyocabinet
32
+
33
+ require 'rufus/edo/cabcore'
34
+ require 'rufus/tokyo/config'
35
+
36
+
37
+ module Rufus::Edo
38
+
39
+ #
40
+ # A cabinet wired 'natively' to the libtokyocabinet.dynlib (approximatevely
41
+ # 2 times faster than the wiring over FFI).
42
+ #
43
+ # This class has the exact same methods as Rufus::Tokyo::Cabinet. It's faster
44
+ # though. The advantage of Rufus::Tokyo::Cabinet lies in that in runs on
45
+ # Ruby 1.8, 1.9 and JRuby.
46
+ #
47
+ # You need to have Hirabayashi-san's binding installed to use this
48
+ # Rufus::Edo::Cabinet :
49
+ #
50
+ # http://github.com/jmettraux/rufus-tokyo/tree/master/lib/rufus/edo
51
+ #
52
+ # You can then write code like :
53
+ #
54
+ # require 'rubygems'
55
+ # require 'rufus/edo' # sudo gem install rufus-tokyo
56
+ #
57
+ # db = Rufus::Edo::Cabinet.new('data.tch')
58
+ #
59
+ # db['hello'] = 'world'
60
+ #
61
+ # puts db['hello']
62
+ # # -> 'world'
63
+ #
64
+ # db.close
65
+ #
66
+ # This cabinet wraps hashes, b+ trees and fixed length databases. For tables,
67
+ # see Rufus::Edo::Table
68
+ #
69
+ class Cabinet
70
+
71
+ include Rufus::Edo::CabinetCore
72
+ include Rufus::Tokyo::CabinetConfig
73
+
74
+ #
75
+ # Initializes and open a cabinet (hash, b+ tree or fixed-size)
76
+ #
77
+ # db = Rufus::Edo::Cabinet.new('data.tch')
78
+ # # or
79
+ # db = Rufus::Edo::Cabinet.new('data', :type => :hash)
80
+ #
81
+ # 3 types are recognized :hash (.tch), :btree (.tcb) and :fixed (.tcf). For
82
+ # tables, see Rufus::Edo::Table
83
+ #
84
+ # == parameters
85
+ #
86
+ # There are two ways to pass parameters at the opening of a db :
87
+ #
88
+ # db = Rufus::Edo::Cabinet.new('data.tch#opts=ld#mode=w') # or
89
+ # db = Rufus::Edo::Cabinet.new('data.tch', :opts => 'ld', :mode => 'w')
90
+ #
91
+ # most verbose :
92
+ #
93
+ # db = Rufus::Edo::Cabinet.new(
94
+ # 'data', :type => :hash, :opts => 'ld', :mode => 'w')
95
+ #
96
+ # === mode
97
+ #
98
+ # * :mode a set of chars ('r'ead, 'w'rite, 'c'reate, 't'runcate,
99
+ # 'e' non locking, 'f' non blocking lock), default is 'wc'
100
+ #
101
+ # === other parameters
102
+ #
103
+ # 'On-memory hash database supports "bnum", "capnum", and "capsiz".
104
+ # On-memory tree database supports "capnum" and "capsiz".
105
+ # Hash database supports "mode", "bnum", "apow", "fpow", "opts",
106
+ # "rcnum", and "xmsiz".
107
+ # B+ tree database supports "mode", "lmemb", "nmemb", "bnum", "apow",
108
+ # "fpow", "opts", "lcnum", "ncnum", and "xmsiz".
109
+ # Fixed-length database supports "mode", "width", and "limsiz"'
110
+ #
111
+ # * :opts a set of chars ('l'arge, 'd'eflate, 'b'zip2, 't'cbs)
112
+ # (usually empty or something like 'ld' or 'lb')
113
+ #
114
+ # * :bnum number of elements of the bucket array
115
+ # * :apow size of record alignment by power of 2 (defaults to 4)
116
+ # * :fpow maximum number of elements of the free block pool by
117
+ # power of 2 (defaults to 10)
118
+ # * :mutex when set to true, makes sure only 1 thread at a time
119
+ # accesses the table (well, Ruby, global thread lock, ...)
120
+ #
121
+ # * :rcnum specifies the maximum number of records to be cached.
122
+ # If it is not more than 0, the record cache is disabled.
123
+ # It is disabled by default.
124
+ # * :lcnum specifies the maximum number of leaf nodes to be cached.
125
+ # If it is not more than 0, the default value is specified.
126
+ # The default value is 2048.
127
+ # * :ncnum specifies the maximum number of non-leaf nodes to be
128
+ # cached. If it is not more than 0, the default value is
129
+ # specified. The default value is 512.
130
+ #
131
+ # * :lmemb number of members in each leaf page (defaults to 128) (btree)
132
+ # * :nmemb number of members in each non-leaf page (default 256) (btree)
133
+ #
134
+ # * :width width of the value of each record (default 255) (fixed)
135
+ # * :limsiz limit size of the database file (default 268_435_456) (fixed)
136
+ #
137
+ # * :xmsiz specifies the size of the extra mapped memory. If it is
138
+ # not more than 0, the extra mapped memory is disabled.
139
+ # The default size is 67108864.
140
+ #
141
+ # * :capnum specifies the capacity number of records.
142
+ # * :capsiz specifies the capacity size of using memory.
143
+ #
144
+ #
145
+ # = NOTE :
146
+ #
147
+ # On reopening a file, Cabinet will tend to stick to the parameters as
148
+ # set when the file was opened. To change that, have a look at the
149
+ # man pages of the various command line tools coming with Tokyo Cabinet.
150
+ #
151
+ def initialize (path, params={})
152
+
153
+ conf = determine_conf(path, params)
154
+
155
+ klass = {
156
+ :hash => TokyoCabinet::HDB,
157
+ :btree => TokyoCabinet::BDB,
158
+ :fixed => TokyoCabinet::FDB
159
+ }[conf[:type]]
160
+
161
+ @db = klass.new
162
+
163
+ #
164
+ # tune
165
+
166
+ tuning_parameters = case conf[:type]
167
+ when :hash then [ :bnum, :apow, :fpow, :opts ]
168
+ when :btree then [ :lmemb, :nmemb, :bnum, :apow, :fpow, :opts ]
169
+ when :fixed then [ :bnum, :width, :limsiz ]
170
+ end
171
+
172
+ @db.tune(*tuning_parameters.collect { |o| conf[o] })
173
+
174
+ #
175
+ # set cache
176
+
177
+ cache_values = case conf[:type]
178
+ when :hash then [ :rcnum ]
179
+ when :btree then [ :lcnum, :ncnum ]
180
+ when :fixed then nil
181
+ end
182
+
183
+ @db.setcache(*cache_values.collect { |o| conf[o] }) if cache_values
184
+
185
+ #
186
+ # set xmsiz
187
+
188
+ @db.setxmsiz(conf[:xmsiz]) unless conf[:type] == :fixed
189
+
190
+ #
191
+ # open
192
+
193
+ @db.open(conf[:path], conf[:mode]) || raise_error
194
+
195
+ #
196
+ # default
197
+
198
+ self.default = params[:default]
199
+ @default_proc ||= params[:default_proc]
200
+ end
201
+ end
202
+ end
203
+
@@ -0,0 +1,147 @@
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 'tokyocabinet'
32
+
33
+ require 'rufus/edo/error'
34
+ require 'rufus/edo/tabcore'
35
+ require 'rufus/tokyo/config'
36
+
37
+
38
+ module Rufus::Edo
39
+
40
+ #
41
+ # Rufus::Edo::Table wraps Hirabayashi-san's Ruby bindings for Tokyo Cabinet
42
+ # tables.
43
+ #
44
+ # This class has the exact same methods as Rufus::Tokyo::Table. It's faster
45
+ # though. The advantage of Rufus::Tokyo::Table lies in that in runs on
46
+ # Ruby 1.8, 1.9 and JRuby.
47
+ #
48
+ # You need to have Hirabayashi-san's binding installed to use this
49
+ # Rufus::Edo::Table :
50
+ #
51
+ # http://github.com/jmettraux/rufus-tokyo/tree/master/lib/rufus/edo
52
+ #
53
+ # Example usage :
54
+ #
55
+ # require 'rufus/edo'
56
+ # db = Rufus::Edo::Table.new('data.tct')
57
+ # db['customer1'] = { 'name' => 'Taira no Kyomori', 'age' => '55' }
58
+ # # ...
59
+ # db.close
60
+ #
61
+ class Table
62
+
63
+ include Rufus::Tokyo::CabinetConfig
64
+ include Rufus::Edo::TableCore
65
+
66
+ #
67
+ # Initializes and open a table.
68
+ #
69
+ # db = Rufus::Edo::Table.new('data.tct')
70
+ # # or
71
+ # db = Rufus::Edo::Table.new('data', :type => :table)
72
+ # # or
73
+ # db = Rufus::Edo::Table.new('data')
74
+ #
75
+ # == parameters
76
+ #
77
+ # There are two ways to pass parameters at the opening of a db :
78
+ #
79
+ # db = Rufus::Edo::Table.new('data.tct#opts=ld#mode=w') # or
80
+ # db = Rufus::Edo::Table.new('data.tct', :opts => 'ld', :mode => 'w')
81
+ #
82
+ # === mode
83
+ #
84
+ # * :mode a set of chars ('r'ead, 'w'rite, 'c'reate, 't'runcate,
85
+ # 'e' non locking, 'f' non blocking lock), default is 'wc'
86
+ #
87
+ # === other parameters
88
+ #
89
+ # * :opts a set of chars ('l'arge, 'd'eflate, 'b'zip2, 't'cbs)
90
+ # (usually empty or something like 'ld' or 'lb')
91
+ #
92
+ # * :bnum number of elements of the bucket array
93
+ # * :apow size of record alignment by power of 2 (defaults to 4)
94
+ # * :fpow maximum number of elements of the free block pool by
95
+ # power of 2 (defaults to 10)
96
+ #
97
+ # * :rcnum specifies the maximum number of records to be cached.
98
+ # If it is not more than 0, the record cache is disabled.
99
+ # It is disabled by default.
100
+ # * :lcnum specifies the maximum number of leaf nodes to be cached.
101
+ # If it is not more than 0, the default value is specified.
102
+ # The default value is 2048.
103
+ # * :ncnum specifies the maximum number of non-leaf nodes to be
104
+ # cached. If it is not more than 0, the default value is
105
+ # specified. The default value is 512.
106
+ #
107
+ # = NOTE :
108
+ #
109
+ # On reopening a file, Cabinet will tend to stick to the parameters as
110
+ # set when the file was opened. To change that, have a look at the
111
+ # man pages of the various command line tools coming with Tokyo Cabinet.
112
+ #
113
+ def initialize (path, params={})
114
+
115
+ conf = determine_conf(path, params, :table)
116
+
117
+ @db = TokyoCabinet::TDB.new
118
+
119
+ #
120
+ # tune
121
+
122
+ @db.tune(conf[:bnum], conf[:apow], conf[:fpow], conf[:opts])
123
+
124
+ #
125
+ # set cache
126
+
127
+ @db.setcache(conf[:rcnum], conf[:lcnum], conf[:ncnum])
128
+
129
+ #
130
+ # set xmsiz
131
+
132
+ @db.setxmsiz(conf[:xmsiz])
133
+
134
+ #
135
+ # open
136
+
137
+ @db.open(conf[:path], conf[:mode]) || raise_error
138
+ end
139
+
140
+ protected
141
+
142
+ def table_query_class #:nodoc#
143
+ TokyoCabinet::TDBQRY
144
+ end
145
+ end
146
+ end
147
+
@@ -0,0 +1,41 @@
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
+ module Rufus
32
+ module Edo
33
+
34
+ #
35
+ # A common error class
36
+ #
37
+ class EdoError < RuntimeError; end
38
+
39
+ end
40
+ end
41
+
@@ -0,0 +1,4 @@
1
+
2
+ require 'rufus/edo/ntyrant/abstract'
3
+ require 'rufus/edo/ntyrant/table'
4
+
@@ -0,0 +1,169 @@
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 'tokyotyrant' # gem install careo-tokyotyrant
32
+
33
+ require 'rufus/edo/error'
34
+ require 'rufus/edo/cabcore'
35
+ require 'rufus/tokyo/stats'
36
+
37
+
38
+ module Rufus::Edo
39
+
40
+ #
41
+ # Connecting to a 'classic' Tokyo Tyrant server remotely
42
+ #
43
+ # require 'rufus/edo/ntyrant'
44
+ # t = Rufus::Edo::NetTyrant.new('127.0.0.1', 44001)
45
+ # t['toto'] = 'blah blah'
46
+ # t['toto'] # => 'blah blah'
47
+ #
48
+ class NetTyrant
49
+
50
+ include Rufus::Edo::CabinetCore
51
+ include Rufus::Tokyo::TyrantStats
52
+
53
+ attr_reader :host, :port
54
+
55
+ #
56
+ # Connects to a given Tokyo Tyrant server.
57
+ #
58
+ # Note that if the port is not specified, the host parameter is expected
59
+ # to hold the path to a unix socket (not a TCP socket).
60
+ #
61
+ # (You can start a unix socket listening Tyrant with :
62
+ #
63
+ # ttserver -host /tmp/tyrant_socket -port 0 data.tch
64
+ #
65
+ # and then connect to it with rufus-tokyo via :
66
+ #
67
+ # require 'rufus/edo/ntyrant'
68
+ # db = Rufus::Edo::NetTyrant.new('/tmp/tyrant_socket')
69
+ # db['a'] = 'alpha'
70
+ # db.close
71
+ # )
72
+ #
73
+ # To connect to a classic TCP bound Tyrant (port 44001) :
74
+ #
75
+ # t = Rufus::Edo::NetTyrant.new('127.0.0.1', 44001)
76
+ #
77
+ def initialize (host, port=0)
78
+
79
+ @host = host
80
+ @port = port
81
+
82
+ @db = TokyoTyrant::RDB.new
83
+ @db.open(host, port) || raise_error
84
+
85
+ if self.stat['type'] == 'table'
86
+
87
+ @db.close
88
+
89
+ raise ArgumentError.new(
90
+ "tyrant at #{host}:#{port} is a table, " +
91
+ "use Rufus::Edo::NetTyrantTable instead to access it.")
92
+ end
93
+ end
94
+
95
+ #
96
+ # Returns the 'weight' of the db (in bytes)
97
+ #
98
+ def weight
99
+
100
+ self.stat['size']
101
+ end
102
+
103
+ #
104
+ # isn't that a bit dangerous ? it creates a file on the server...
105
+ #
106
+ # DISABLED.
107
+ #
108
+ def copy (target_path)
109
+
110
+ #@db.copy(target_path)
111
+ raise 'not allowed to create files on the server'
112
+ end
113
+
114
+ #
115
+ # Copies the current cabinet to a new file.
116
+ #
117
+ # Does it by copying each entry afresh to the target file. Spares some
118
+ # space, hence the 'compact' label...
119
+ #
120
+ def compact_copy (target_path)
121
+
122
+ raise NotImplementedError.new('not creating files locally')
123
+ end
124
+
125
+ #
126
+ # Deletes all the entries whose keys begin with the given prefix
127
+ #
128
+ def delete_keys_with_prefix (prefix)
129
+
130
+ @db.misc('outlist', @db.fwmkeys(prefix, -1)) # -1 for no limits
131
+ nil
132
+ end
133
+
134
+ #
135
+ # Given a list of keys, returns a Hash { key => value } of the
136
+ # matching entries (in one sweep).
137
+ #
138
+ def lget (keys)
139
+
140
+ Hash[*@db.misc('getlist', keys)]
141
+ end
142
+
143
+ #
144
+ # Merges the given hash into this Tyrant and returns self.
145
+ #
146
+ def merge! (hash)
147
+
148
+ @db.misc('putlist', hash.inject([]) { |l, (k, v)| l << k; l << v; l })
149
+ self
150
+ end
151
+ alias :lput :merge!
152
+
153
+ #
154
+ # Given a list of keys, deletes all the matching entries (in one sweep).
155
+ #
156
+ def ldelete (keys)
157
+
158
+ @db.misc('outlist', keys)
159
+ nil
160
+ end
161
+
162
+ protected
163
+
164
+ def do_stat #:nodoc#
165
+ @db.stat
166
+ end
167
+ end
168
+ end
169
+