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.
- data/CHANGELOG.txt +7 -0
- data/CREDITS.txt +5 -1
- data/README.txt +34 -2
- data/TODO.txt +11 -2
- data/lib/rufus-edo.rb +3 -0
- data/lib/rufus/edo.rb +44 -0
- data/lib/rufus/edo/cabcore.rb +292 -0
- data/lib/rufus/edo/cabinet/abstract.rb +203 -0
- data/lib/rufus/edo/cabinet/table.rb +147 -0
- data/lib/rufus/edo/error.rb +41 -0
- data/lib/rufus/edo/ntyrant.rb +4 -0
- data/lib/rufus/edo/ntyrant/abstract.rb +169 -0
- data/lib/rufus/edo/ntyrant/table.rb +134 -0
- data/lib/rufus/edo/tabcore.rb +506 -0
- data/lib/rufus/tokyo.rb +11 -8
- data/lib/rufus/tokyo/cabinet/abstract.rb +356 -294
- data/lib/rufus/tokyo/cabinet/lib.rb +119 -118
- data/lib/rufus/tokyo/cabinet/table.rb +500 -664
- data/lib/rufus/tokyo/cabinet/util.rb +294 -263
- data/lib/rufus/tokyo/config.rb +163 -0
- data/lib/rufus/tokyo/dystopia.rb +16 -10
- data/lib/rufus/tokyo/dystopia/lib.rb +26 -27
- data/lib/rufus/tokyo/dystopia/words.rb +32 -34
- data/lib/rufus/tokyo/hmethods.rb +63 -62
- data/lib/rufus/tokyo/query.rb +107 -0
- data/lib/rufus/tokyo/stats.rb +54 -0
- data/lib/rufus/tokyo/transactions.rb +79 -0
- data/lib/rufus/tokyo/tyrant.rb +1 -19
- data/lib/rufus/tokyo/tyrant/abstract.rb +78 -31
- data/lib/rufus/tokyo/tyrant/lib.rb +62 -63
- data/lib/rufus/tokyo/tyrant/table.rb +119 -49
- data/lib/tokyotyrant.rb +1273 -0
- data/out.txt +149 -0
- data/out2.txt +150 -0
- metadata +19 -4
- data/lib/rufus/tokyo/cabinet.rb +0 -6
@@ -0,0 +1,163 @@
|
|
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 Tokyo
|
33
|
+
|
34
|
+
#
|
35
|
+
# Methods for setting up / tuning a Cabinet.
|
36
|
+
#
|
37
|
+
module CabinetConfig
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
#
|
42
|
+
# Given a path, a hash of parameters and a suffix,
|
43
|
+
#
|
44
|
+
# a) makes sure that the path has the given suffix or raises an exception
|
45
|
+
# b) gathers params found in the path (#) or in params
|
46
|
+
# c) determines the config as set by the parameters
|
47
|
+
#
|
48
|
+
# Suffix is optional, if present, it will be enforced.
|
49
|
+
#
|
50
|
+
def determine_conf (path, params, required_type=nil)
|
51
|
+
|
52
|
+
if path.index('#')
|
53
|
+
|
54
|
+
ss = path.split('#')
|
55
|
+
path = ss.shift
|
56
|
+
|
57
|
+
ss.each { |p| pp = p.split('='); params[pp[0]] = pp[1] }
|
58
|
+
end
|
59
|
+
|
60
|
+
params = params.inject({}) { |h, (k, v)| h[k.to_sym] = v; h }
|
61
|
+
|
62
|
+
[
|
63
|
+
{
|
64
|
+
:params => params,
|
65
|
+
:mode => determine_open_mode(params),
|
66
|
+
:mutex => (params[:mutex].to_s == 'true'),
|
67
|
+
#:indexes => params[:idx] || params[:indexes],
|
68
|
+
:xmsiz => (params[:xmsiz] || 67108864).to_i,
|
69
|
+
},
|
70
|
+
determine_type_and_path(path, params, required_type),
|
71
|
+
determine_tuning_values(params),
|
72
|
+
determine_cache_values(params)
|
73
|
+
|
74
|
+
].inject({}) { |h, hh| h.merge(hh) }
|
75
|
+
end
|
76
|
+
|
77
|
+
def determine_open_mode (params) #:nodoc#
|
78
|
+
|
79
|
+
mode = params[:mode].to_s
|
80
|
+
mode = 'wc' if mode.size < 1
|
81
|
+
|
82
|
+
{
|
83
|
+
'r' => (1 << 0), # open as a reader
|
84
|
+
'w' => (1 << 1), # open as a writer
|
85
|
+
'c' => (1 << 2), # writer creating
|
86
|
+
't' => (1 << 3), # writer truncating
|
87
|
+
'e' => (1 << 4), # open without locking
|
88
|
+
'f' => (1 << 5), # lock without blocking
|
89
|
+
's' => (1 << 6), # synchronize every transaction (tctdb.h)
|
90
|
+
|
91
|
+
}.inject(0) { |r, (c, v)|
|
92
|
+
|
93
|
+
r = r | v if mode.index(c); r
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
def determine_tuning_values (params) #:nodoc#
|
98
|
+
|
99
|
+
o = params[:opts] || ''
|
100
|
+
o = {
|
101
|
+
'l' => 1 << 0, # large
|
102
|
+
'd' => 1 << 1, # deflate
|
103
|
+
'b' => 1 << 2, # bzip2
|
104
|
+
't' => 1 << 3, # tcbs
|
105
|
+
'x' => 1 << 4
|
106
|
+
}.inject(0) { |i, (k, v)| i = i | v if o.index(k); i }
|
107
|
+
|
108
|
+
{
|
109
|
+
:bnum => (params[:bnum] || 131071).to_i,
|
110
|
+
:apow => (params[:apow] || 4).to_i,
|
111
|
+
:fpow => (params[:fpow] || 10).to_i,
|
112
|
+
:opts => o,
|
113
|
+
|
114
|
+
:lmemb => (params[:lmemb] || 128).to_i,
|
115
|
+
# number of members in each leaf page (:btree)
|
116
|
+
:nmemb => (params[:nmemb] || 256).to_i,
|
117
|
+
# number of members in each non-leaf page (:btree)
|
118
|
+
|
119
|
+
:width => (params[:width] || 255).to_i,
|
120
|
+
# width of the value of each record (:fixed)
|
121
|
+
:limsiz => (params[:limsiz] || 26_8435_456).to_i
|
122
|
+
# limit size of the database file (:fixed)
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
def determine_cache_values (params) #:nodoc#
|
127
|
+
|
128
|
+
{
|
129
|
+
:rcnum => params[:rcnum].to_i,
|
130
|
+
:lcnum => (params[:lcnum] || 2048).to_i,
|
131
|
+
:ncnum => (params[:ncnum] || 512).to_i
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
CABINET_SUFFIXES = {
|
136
|
+
:hash => '.tch', :btree => '.tcb', :fixed => '.tcf', :table => '.tct'
|
137
|
+
}
|
138
|
+
|
139
|
+
CABINET_TYPES = CABINET_SUFFIXES.invert
|
140
|
+
|
141
|
+
def determine_type_and_path (path, params, required_type) #:nodoc#
|
142
|
+
|
143
|
+
type = required_type || params[:type]
|
144
|
+
ext = File.extname(path)
|
145
|
+
|
146
|
+
if ext == ''
|
147
|
+
suffix = CABINET_SUFFIXES[type]
|
148
|
+
path = path + suffix
|
149
|
+
else
|
150
|
+
suffix = ext
|
151
|
+
type ||= CABINET_TYPES[ext]
|
152
|
+
end
|
153
|
+
|
154
|
+
raise "path '#{path}' must be suffixed with #{suffix}" \
|
155
|
+
if suffix and File.extname(path) != suffix
|
156
|
+
|
157
|
+
{ :path => path, :type => type }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
data/lib/rufus/tokyo/dystopia.rb
CHANGED
@@ -22,18 +22,24 @@
|
|
22
22
|
#++
|
23
23
|
#
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
#
|
26
|
+
# "made in Japan"
|
27
|
+
#
|
28
|
+
# jmettraux@gmail.com
|
29
|
+
#
|
27
30
|
|
28
|
-
|
29
|
-
# An error for Dystopia
|
30
|
-
#
|
31
|
-
class DystopianError < RuntimeError
|
32
|
-
def new (error_code)
|
33
|
-
super("tokyo dystopia error #{error_code}")
|
34
|
-
end
|
35
|
-
end
|
31
|
+
require 'rufus/tokyo'
|
36
32
|
|
33
|
+
|
34
|
+
module Rufus::Tokyo
|
35
|
+
|
36
|
+
#
|
37
|
+
# An error for Dystopia
|
38
|
+
#
|
39
|
+
class DystopianError < RuntimeError
|
40
|
+
def new (error_code)
|
41
|
+
super("tokyo dystopia error #{error_code}")
|
42
|
+
end
|
37
43
|
end
|
38
44
|
end
|
39
45
|
|
@@ -28,44 +28,43 @@
|
|
28
28
|
# jmettraux@gmail.com
|
29
29
|
#
|
30
30
|
|
31
|
-
module Rufus
|
32
|
-
module Tokyo
|
31
|
+
module Rufus::Tokyo
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
#
|
34
|
+
# The libtokyodystopia.so methods get bound to this module
|
35
|
+
#
|
36
|
+
module DystopiaLib #:nodoc#
|
38
37
|
|
39
|
-
|
38
|
+
extend FFI::Library
|
40
39
|
|
41
|
-
|
42
|
-
|
40
|
+
#
|
41
|
+
# find Tokyo Dystopia lib
|
43
42
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
43
|
+
paths = Array(ENV['TOKYO_DYSTOPIA_LIB'] || %w{
|
44
|
+
/opt/local/lib/libtokyodystopia.dylib
|
45
|
+
/usr/local/lib/libtokyodystopia.dylib
|
46
|
+
/usr/local/lib/libtokyodystopia.so
|
47
|
+
})
|
49
48
|
|
50
|
-
|
49
|
+
if path = paths.find { |path| File.exist?(path) }
|
51
50
|
|
52
|
-
|
51
|
+
raise "did not find Tokyo Dystopia libs on your system" unless path
|
53
52
|
|
54
|
-
|
53
|
+
ffi_lib(path)
|
55
54
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
#
|
56
|
+
# tcwdb functions
|
57
|
+
#
|
58
|
+
# http://tokyocabinet.sourceforge.net/dystopiadoc/#tcwdbapi
|
60
59
|
|
61
|
-
|
60
|
+
attach_function :tcwdbnew, [], :pointer
|
62
61
|
|
63
|
-
|
64
|
-
|
62
|
+
attach_function :tcwdbopen, [ :pointer, :string, :int ], :int
|
63
|
+
attach_function :tcwdbclose, [ :pointer ], :int
|
65
64
|
|
66
|
-
|
65
|
+
attach_function :tcwdbecode, [ :pointer ], :int
|
67
66
|
|
68
|
-
|
69
|
-
end
|
67
|
+
attach_function :tcwdbput2, [ :pointer, :int64, :string, :string ], :pointer
|
70
68
|
end
|
71
69
|
end
|
70
|
+
|
@@ -28,51 +28,49 @@
|
|
28
28
|
# jmettraux@gmail.com
|
29
29
|
#
|
30
30
|
|
31
|
-
module Rufus
|
32
|
-
|
31
|
+
module Rufus::Tokyo
|
32
|
+
|
33
|
+
#
|
34
|
+
# Tokyo Dystopia words database.
|
35
|
+
#
|
36
|
+
# http://tokyocabinet.sourceforge.net/dystopiadoc/
|
37
|
+
#
|
38
|
+
class Words
|
33
39
|
|
34
40
|
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
# http://tokyocabinet.sourceforge.net/dystopiadoc/
|
41
|
+
# TODO : continue me
|
38
42
|
#
|
39
|
-
class Words
|
40
43
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
+
#
|
45
|
+
# Opens/create a Tokyo Dystopia words database.
|
46
|
+
#
|
47
|
+
def initialize (path, opts={})
|
44
48
|
|
49
|
+
# tcwdb.h :
|
45
50
|
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
|
51
|
+
# enum { /* enumeration for open modes */
|
52
|
+
# WDBOREADER = 1 << 0, /* open as a reader */
|
53
|
+
# WDBOWRITER = 1 << 1, /* open as a writer */
|
54
|
+
# WDBOCREAT = 1 << 2, /* writer creating */
|
55
|
+
# WDBOTRUNC = 1 << 3, /* writer truncating */
|
56
|
+
# WDBONOLCK = 1 << 4, /* open without locking */
|
57
|
+
# WDBOLCKNB = 1 << 5 /* lock without blocking */
|
58
|
+
# };
|
49
59
|
|
50
|
-
|
51
|
-
#
|
52
|
-
# enum { /* enumeration for open modes */
|
53
|
-
# WDBOREADER = 1 << 0, /* open as a reader */
|
54
|
-
# WDBOWRITER = 1 << 1, /* open as a writer */
|
55
|
-
# WDBOCREAT = 1 << 2, /* writer creating */
|
56
|
-
# WDBOTRUNC = 1 << 3, /* writer truncating */
|
57
|
-
# WDBONOLCK = 1 << 4, /* open without locking */
|
58
|
-
# WDBOLCKNB = 1 << 5 /* lock without blocking */
|
59
|
-
# };
|
60
|
+
mode = 0
|
60
61
|
|
61
|
-
|
62
|
+
@db = dlib.tcwdbnew
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
(dlib.tcwdbopen(@db, path, mode) == 1) || raise_error
|
66
|
-
end
|
64
|
+
(dlib.tcwdbopen(@db, path, mode) == 1) || raise_error
|
65
|
+
end
|
67
66
|
|
68
|
-
|
67
|
+
protected
|
69
68
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
69
|
+
#
|
70
|
+
# Raises a dystopian error (asks the db which one)
|
71
|
+
#
|
72
|
+
def raise_error
|
73
|
+
raise DystopianError.new(dlib.tcwdbecode(@db))
|
76
74
|
end
|
77
75
|
end
|
78
76
|
end
|
data/lib/rufus/tokyo/hmethods.rb
CHANGED
@@ -29,80 +29,81 @@
|
|
29
29
|
#
|
30
30
|
|
31
31
|
module Rufus
|
32
|
-
|
32
|
+
module Tokyo
|
33
|
+
|
34
|
+
#
|
35
|
+
# A mixin for Cabinet and Map, gathers all the hash-like methods
|
36
|
+
#
|
37
|
+
module HashMethods
|
38
|
+
include Enumerable
|
33
39
|
|
34
40
|
#
|
35
|
-
#
|
41
|
+
# The [] methods
|
36
42
|
#
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
def [] (k)
|
46
|
-
val = get(k)
|
47
|
-
return val unless val.nil?
|
48
|
-
return nil unless @default_proc
|
49
|
-
@default_proc.call(self, k)
|
50
|
-
end
|
51
|
-
|
52
|
-
#
|
53
|
-
# Returns an array of all the values
|
54
|
-
#
|
55
|
-
def values
|
56
|
-
collect { |k, v| v }
|
57
|
-
end
|
43
|
+
# (assumes there's an underlying get(k) method)
|
44
|
+
#
|
45
|
+
def [] (k)
|
46
|
+
val = get(k)
|
47
|
+
return val unless val.nil?
|
48
|
+
return nil unless @default_proc
|
49
|
+
@default_proc.call(self, k)
|
50
|
+
end
|
58
51
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
52
|
+
#
|
53
|
+
# Returns an array of all the values
|
54
|
+
#
|
55
|
+
def values
|
56
|
+
collect { |k, v| v }
|
57
|
+
end
|
65
58
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
59
|
+
#
|
60
|
+
# Our classical 'each'
|
61
|
+
#
|
62
|
+
def each
|
63
|
+
keys.each { |k| yield(k, self[k]) }
|
64
|
+
end
|
72
65
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
66
|
+
#
|
67
|
+
# Turns this instance into a Ruby hash
|
68
|
+
#
|
69
|
+
def to_h
|
70
|
+
self.inject({}) { |h, (k, v)| h[k] = v; h }
|
71
|
+
end
|
79
72
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
73
|
+
#
|
74
|
+
# Turns this instance into an array of [ key, value ]
|
75
|
+
#
|
76
|
+
def to_a
|
77
|
+
self.collect { |e| e }
|
78
|
+
end
|
86
79
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
80
|
+
#
|
81
|
+
# Returns a new Ruby hash which is a merge of this Map and the given hash
|
82
|
+
#
|
83
|
+
def merge (h)
|
84
|
+
self.to_h.merge(h)
|
85
|
+
end
|
94
86
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
87
|
+
#
|
88
|
+
# Merges the entries in the given hash into this map
|
89
|
+
#
|
90
|
+
def merge! (h)
|
91
|
+
h.each { |k, v| self[k] = v }
|
92
|
+
self
|
93
|
+
end
|
99
94
|
|
100
|
-
|
101
|
-
|
102
|
-
|
95
|
+
def default (key=nil)
|
96
|
+
val = self[key]
|
97
|
+
val.nil? ? @default_proc.call(self, key) : val
|
98
|
+
end
|
103
99
|
|
104
|
-
|
100
|
+
def default= (val)
|
101
|
+
@default_proc = lambda { |h, k| val }
|
105
102
|
end
|
106
103
|
|
104
|
+
attr_reader :default_proc
|
107
105
|
end
|
106
|
+
|
107
|
+
end
|
108
108
|
end
|
109
|
+
|