ruby-tokyotyrant 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,9 +6,7 @@ This is a c extension for Ruby to access TokyoTyrant databases. It currently su
6
6
 
7
7
  # install tokyocabinet (1.4.34) and tokyotyrant (requires 1.1.35)
8
8
  # after installing tc and tt on linux I had to /sbin/ldconfig (as root)
9
- sudo gem install gemcutter
10
- sudo gem tumble
11
- sudo gem install ruby-tokyotyrant
9
+ sudo gem install ruby-tokyotyrant --source=http://gemcutter.org
12
10
 
13
11
  == Performance
14
12
 
@@ -39,6 +37,28 @@ This is not in production but the initial benchmarks are very interesting. Resul
39
37
  db.mput("1"=>"number_1", "2"=>"number_2", "3"=>"number_3", "4"=>"number_4", "5"=>"number_5")
40
38
  db.mget(1..3) # => {"1"=>"number_1", "2"=>"number_2", "3"=>"number_3"}
41
39
 
40
+ === B+ Tree DB
41
+
42
+ # start tyrant like so:
43
+ # ttserver example.tcb
44
+
45
+ require 'tokyo_tyrant'
46
+ bdb = TokyoTyrant::BDB.new('127.0.0.1', 1978)
47
+
48
+ bdb.putdup('foo', 'bar')
49
+ # => true
50
+
51
+ bdb.putlist({ 'foo' => ['baz', 'bat']})
52
+ # => []
53
+
54
+ bdb.getlist('foo')
55
+ # => {"foo"=>["bar", "baz", "bat"]}
56
+
57
+ bdb.each{ |k,v| puts [k, v].inspect }
58
+ # ["foo", "bar"]
59
+ # ["foo", "baz"]
60
+ # ["foo", "bat"]
61
+
42
62
  === Table DB
43
63
 
44
64
  # start tyrant like so:
data/Rakefile CHANGED
@@ -20,7 +20,7 @@ CLEAN.include('pkg', 'tmp')
20
20
 
21
21
  gemspec = Gem::Specification.new do |s|
22
22
  s.name = 'ruby-tokyotyrant'
23
- s.version = '0.4'
23
+ s.version = '0.5'
24
24
  s.authors = [ 'Flinn' ]
25
25
  s.email = 'flinn@actsasflinn.com'
26
26
  s.homepage = 'http://github.com/actsasflinn/ruby-tokyotyrant/'
@@ -35,12 +35,10 @@ gemspec = Gem::Specification.new do |s|
35
35
  'Rakefile',
36
36
  'README.rdoc'] +
37
37
  Dir['ext/**/*.[rb|c|h]'] +
38
- Dir['lib/**/*.rb'] +
38
+ Dir['ext/tokyo_tyrant/**/*.rb'] +
39
39
  Dir['spec/**/*'] +
40
40
  Dir['benchmarks/**/*']
41
41
  s.extensions << "ext/extconf.rb"
42
-
43
- s.add_runtime_dependency('fast_hash_ring', '>= 0.1.1')
44
42
  end
45
43
 
46
44
  task :gemspec do
@@ -53,7 +51,7 @@ Rake::GemPackageTask.new(gemspec) do |pkg|
53
51
  pkg.need_tar = true
54
52
  end
55
53
 
56
- Rake::PackageTask.new('ruby-tokyotyrant', '0.4') do |pkg|
54
+ Rake::PackageTask.new('ruby-tokyotyrant', '0.5') do |pkg|
57
55
  pkg.need_zip = true
58
56
  pkg.package_files = FileList[
59
57
  'COPYING',
@@ -1,3 +1,26 @@
1
+ =begin
2
+ Tokyo Tyrant Bulk Operations Benchmark
3
+
4
+
5
+ TokyoTyrant::RDB (Ruby) mget
6
+ user system total real
7
+ inserting data 7.770000 1.870000 9.640000 ( 12.598373)
8
+ reading data 1.540000 0.250000 1.790000 ( 2.290628)
9
+
10
+
11
+ TokyoTyrant (c) mput/mget
12
+ user system total real
13
+ inserting data 0.020000 0.000000 0.020000 ( 0.037996)
14
+ reading data 0.060000 0.010000 0.070000 ( 0.120651)
15
+
16
+
17
+ Memcached (C) set/get_multi
18
+ user system total real
19
+ inserting data* 0.160000 0.140000 0.300000 ( 0.884097)
20
+ reading data 0.090000 0.000000 0.090000 ( 0.140217)
21
+ * bulk operation not supported
22
+ =end
23
+
1
24
  require 'benchmark'
2
25
  require 'rubygems'
3
26
  require 'faker'
@@ -1,3 +1,31 @@
1
+ =begin
2
+ Tokyo Tyrant Bulk Table Operations Benchmark
3
+
4
+
5
+ TokyoTyrant (C)
6
+ user system total real
7
+ bulk writing data 0.180000 0.000000 0.180000 ( 0.292081)
8
+ bulk reading data 0.120000 0.020000 0.140000 ( 0.216074)
9
+
10
+
11
+ TokyoTyrant::RDB (Ruby)
12
+ user system total real
13
+ bulk inserting data* 42.410000 4.130000 46.540000 ( 63.657929)
14
+ bulk reading data 2.360000 0.280000 2.640000 ( 3.709915)
15
+
16
+
17
+ Mongo
18
+ user system total real
19
+ bulk writing data 27.860000 0.470000 28.330000 ( 37.619586)
20
+ bulk reading data 0.650000 0.100000 0.750000 ( 1.371567)
21
+
22
+ Notes:
23
+ * To supply a hash for bulk operations TokyoTyrant::RDB creates an array and join hash columns.
24
+ * This operation is included in the benchmark because the same code exists within the c-ext.
25
+ Rufus::Tokyo::TyrantTable does not support the misc method, therefor cannot handle a putlist/getlist
26
+ Memcached does not support bulk writing
27
+ =end
28
+
1
29
  require 'benchmark'
2
30
  require 'rubygems'
3
31
  require 'faker'
@@ -10,7 +38,7 @@ $month = (1..12).to_a
10
38
  $day = (1..28).to_a # not bothering with month diffs
11
39
 
12
40
  def rbdate
13
- DateTime.new($year[rand($year.size)], $month[rand($month.size)], $day[rand($day.size)])
41
+ Date.new($year[rand($year.size)], $month[rand($month.size)], $day[rand($day.size)])
14
42
  end
15
43
 
16
44
  def rdiv
@@ -30,9 +58,12 @@ end
30
58
 
31
59
  data = {}
32
60
  10_000.times do |i|
33
- data[i] = { :name => Faker::Name.name, :sex => rgen, :birthday => rbdate.to_s, :divisions => rdiv }
61
+ data[i.to_s] = { :_id => i.to_s, :name => Faker::Name.name, :sex => rgen, :birthday => rbdate.to_s, :divisions => rdiv }
34
62
  end
35
63
 
64
+ data_keys = data.keys
65
+ data_values = data.values
66
+
36
67
  require 'tokyo_tyrant'
37
68
  t = TokyoTyrant::Table.new('127.0.0.1', 45001)
38
69
  t.clear
@@ -46,7 +77,7 @@ Benchmark.benchmark(' ' * 20 + Benchmark::Tms::CAPTION, 20) do |b|
46
77
  end
47
78
 
48
79
  b.report('bulk reading data') do
49
- nothing = t.mget(0..9999)
80
+ nothing = t.mget(data_keys)
50
81
  end
51
82
  end
52
83
 
@@ -80,6 +111,23 @@ Benchmark.benchmark(' ' * 20 + Benchmark::Tms::CAPTION, 20) do |b|
80
111
  end
81
112
  end
82
113
 
114
+ require 'mongo'
115
+ db = Mongo::Connection.new.db("benchmark")
116
+ 2.times { puts }
117
+ puts 'Mongo'
118
+ mdb = db["data"]
119
+ mdb.remove
120
+
121
+ Benchmark.benchmark(' ' * 20 + Benchmark::Tms::CAPTION, 20) do |b|
122
+ b.report('bulk writing data') do
123
+ nothing = mdb.insert(data_values)
124
+ end
125
+
126
+ b.report('bulk reading data') do
127
+ nothing = mdb.find(:_id => {'$in' => data_keys}).to_a
128
+ end
129
+ end
130
+
83
131
  puts "\nNotes:"
84
132
  puts "* To supply a hash for bulk operations TokyoTyrant::RDB creates an array and join hash columns."
85
133
  puts "* This operation is included in the benchmark because the same code exists within the c-ext."
@@ -1,14 +1,56 @@
1
+ =begin
2
+ Tokyo::Tyrant (Ruby FFI)
3
+ user system total real
4
+ inserting data 0.140000 0.180000 0.320000 ( 1.208150)
5
+ reading data 0.240000 0.170000 0.410000 ( 1.467640)
6
+
7
+
8
+ TokyoTyrant::RDB (Ruby)
9
+ user system total real
10
+ inserting data 0.300000 0.170000 0.470000 ( 1.481900)
11
+ reading data 0.410000 0.210000 0.620000 ( 1.705723)
12
+
13
+
14
+ TokyoTyrant (C)
15
+ user system total real
16
+ inserting data 0.130000 0.170000 0.300000 ( 1.251842)
17
+ reading data 0.120000 0.160000 0.280000 ( 1.539256)
18
+
19
+
20
+ Memcached (C) to Tyrant
21
+ user system total real
22
+ inserting data 0.200000 0.150000 0.350000 ( 1.814691)
23
+ reading data 0.180000 0.160000 0.340000 ( 1.358712)
24
+
25
+
26
+ Memcached (C) to Memcached
27
+ user system total real
28
+ inserting data 0.190000 0.140000 0.330000 ( 1.022183)
29
+ reading data 0.160000 0.140000 0.300000 ( 0.908084)
30
+
31
+
32
+ MemCache (Ruby)
33
+ user system total real
34
+ inserting data 1.200000 0.210000 1.410000 ( 2.329328)
35
+ reading data 1.510000 0.220000 1.730000 ( 2.721509)
36
+
37
+
38
+ Voldemort (Ruby)
39
+ user system total real
40
+ inserting data 18.290000 1.050000 19.340000 ( 37.562370)
41
+ reading data 9.040000 0.530000 9.570000 ( 15.145843)
42
+ =end
43
+
1
44
  require 'benchmark'
2
45
  require 'rubygems'
3
46
  require 'faker'
4
47
 
5
48
  data = []
6
49
 
7
- 100_000.times do |i|
50
+ 10_000.times do |i|
8
51
  data << Faker::Name.name
9
52
  end
10
53
 
11
- =begin
12
54
  require 'rufus/tokyo/tyrant'
13
55
 
14
56
  r = Rufus::Tokyo::Tyrant.new('127.0.0.1', 45000)
@@ -45,10 +87,9 @@ Benchmark.benchmark(' ' * 20 + Benchmark::Tms::CAPTION, 20) do |b|
45
87
  data.each_with_index { |e, i| nothing = rdb.get(i.to_s) }
46
88
  end
47
89
  end
48
- =end
49
90
 
50
91
  require 'tokyo_tyrant'
51
- t = TokyoTyrant::DB.new('127.0.0.1', 1978)
92
+ t = TokyoTyrant::DB.new('127.0.0.1', 45000)
52
93
  t.clear
53
94
 
54
95
  2.times { puts }
@@ -64,23 +105,6 @@ Benchmark.benchmark(' ' * 20 + Benchmark::Tms::CAPTION, 20) do |b|
64
105
  end
65
106
  end
66
107
 
67
- m = TokyoTyrant::MDB.new
68
- m.clear
69
-
70
- 2.times { puts }
71
- puts 'MDB'
72
-
73
- Benchmark.benchmark(' ' * 20 + Benchmark::Tms::CAPTION, 20) do |b|
74
- b.report('inserting data') do
75
- data.each_with_index { |e, i| m[i] = e }
76
- end
77
-
78
- b.report('reading data') do
79
- data.each_with_index { |e, i| nothing = m[i] }
80
- end
81
- end
82
-
83
- =begin
84
108
  require 'memcached'
85
109
  m = Memcached.new('127.0.0.1:45000')
86
110
  m.flush
@@ -131,4 +155,19 @@ Benchmark.benchmark(' ' * 20 + Benchmark::Tms::CAPTION, 20) do |b|
131
155
  data.each_with_index { |e, i| nothing = mc.get(i.to_s) }
132
156
  end
133
157
  end
134
- =end
158
+
159
+ require 'voldemort-rb'
160
+ vdb = VoldemortClient.new("test", "localhost:6666")
161
+ 2.times { puts }
162
+ puts 'Voldemort (Ruby)'
163
+
164
+ Benchmark.benchmark(' ' * 20 + Benchmark::Tms::CAPTION, 20) do |b|
165
+ b.report('inserting data') do
166
+ data.each_with_index { |e, i| vdb.put(i.to_s, e) }
167
+ end
168
+
169
+ b.report('reading data') do
170
+ data.each_with_index { |e, i| nothing = vdb.get(i.to_s) }
171
+ end
172
+ end
173
+
@@ -1,3 +1,40 @@
1
+ =begin
2
+ Tokyo::TyrantTable (Ruby FFI)
3
+ user system total real
4
+ inserting data 0.840000 0.190000 1.030000 ( 3.214565)
5
+ reading data 1.310000 0.210000 1.520000 ( 3.024142)
6
+
7
+
8
+ TokyoTyrant::RDB (Ruby)
9
+ user system total real
10
+ inserting data 1.170000 0.240000 1.410000 ( 2.859321)
11
+ reading data 2.250000 0.660000 2.910000 ( 4.752291)
12
+
13
+
14
+ TokyoTyrant (C)
15
+ user system total real
16
+ inserting data 0.260000 0.180000 0.440000 ( 1.637843)
17
+ reading data 0.300000 0.170000 0.470000 ( 1.631104)
18
+
19
+
20
+ Memcached (C)
21
+ user system total real
22
+ inserting data 0.300000 0.160000 0.460000 ( 1.230830)
23
+ reading data 0.310000 0.140000 0.450000 ( 1.171531)
24
+
25
+
26
+ MemCache (Ruby)
27
+ user system total real
28
+ inserting data 2.080000 0.220000 2.300000 ( 3.379047)
29
+ reading data 2.220000 0.200000 2.420000 ( 4.018160)
30
+
31
+
32
+ Mongo
33
+ user system total real
34
+ inserting data 1.590000 0.130000 1.720000 ( 2.310027)
35
+ reading data 4.220000 0.380000 4.600000 ( 7.178335)
36
+ =end
37
+
1
38
  require 'benchmark'
2
39
  require 'rubygems'
3
40
  require 'faker'
@@ -7,14 +44,14 @@ require 'date'
7
44
  # the data
8
45
  #
9
46
 
10
- colnames = %w{ name sex birthday divisions }
47
+ colnames = %w{ _id name sex birthday divisions }
11
48
 
12
49
  $year = (1909 .. 2009).to_a
13
50
  $month = (1..12).to_a
14
51
  $day = (1..28).to_a # not bothering with month diffs
15
52
 
16
53
  def rbdate
17
- DateTime.new($year[rand($year.size)], $month[rand($month.size)], $day[rand($day.size)])
54
+ Date.new($year[rand($year.size)], $month[rand($month.size)], $day[rand($day.size)])
18
55
  end
19
56
 
20
57
  def rdiv
@@ -31,16 +68,16 @@ end
31
68
  def rgen
32
69
  (rand(2) == 1 ? 'male' : 'female')
33
70
  end
34
-
71
+
35
72
  data = [
36
- [ 'Alphonse Armalite', 'male', DateTime.new(1972, 10, 14), 'brd,dev' ],
37
- [ 'Brutus Beromunster', 'male', DateTime.new(1964, 07, 14), 'dev' ],
38
- [ 'Crystel Chucknorris', 'female', DateTime.new(1980, 07, 12), 'brd' ],
39
- [ 'Desree Dylan', 'female', DateTime.new(1954, 07, 13), 'brd,dev' ]
73
+ ['alphonse-armalite', 'Alphonse Armalite', 'male', Date.new(1972, 10, 14).to_s, 'brd,dev'],
74
+ ['brutus-beromunster', 'Brutus Beromunster', 'male', Date.new(1964, 07, 14).to_s, 'dev'],
75
+ ['crystel-chucknorris', 'Crystel Chucknorris', 'female', Date.new(1980, 07, 12).to_s, 'brd'],
76
+ ['desree-dylan', 'Desree Dylan', 'female', Date.new(1954, 07, 13).to_s, 'brd,dev']
40
77
  ]
41
78
 
42
79
  10_000.times do |i|
43
- data << [ Faker::Name.name, rgen, rbdate, rdiv]
80
+ data << [i.to_s, Faker::Name.name, rgen, rbdate.to_s, rdiv]
44
81
  end
45
82
 
46
83
  $find_name_list = []
@@ -112,14 +149,6 @@ Benchmark.benchmark(' ' * 20 + Benchmark::Tms::CAPTION, 20) do |b|
112
149
  b.report('reading data') do
113
150
  data1.each_with_index { |e, i| nothing = t[i] }
114
151
  end
115
-
116
- b.report('bulk writing data') do
117
- nothing = t.mput(data_h)
118
- end
119
-
120
- b.report('bulk reading data') do
121
- nothing = t.mget(0..9999)
122
- end
123
152
  end
124
153
 
125
154
  require 'memcached'
@@ -137,10 +166,6 @@ Benchmark.benchmark(' ' * 20 + Benchmark::Tms::CAPTION, 20) do |b|
137
166
  b.report('reading data') do
138
167
  data1.each_with_index { |e, i| nothing = m.get(i.to_s) }
139
168
  end
140
-
141
- b.report('bulk reading data') do
142
- nothing = m.get((0..9999).to_a.collect{|i| i.to_s})
143
- end
144
169
  end
145
170
 
146
171
  require 'memcache'
@@ -159,3 +184,20 @@ Benchmark.benchmark(' ' * 20 + Benchmark::Tms::CAPTION, 20) do |b|
159
184
  data1.each_with_index { |e, i| nothing = mc.get(i.to_s) }
160
185
  end
161
186
  end
187
+
188
+ require 'mongo'
189
+ db = Mongo::Connection.new.db("benchmark")
190
+ 2.times { puts }
191
+ puts 'Mongo'
192
+ mdb = db["data"]
193
+ mdb.remove
194
+
195
+ Benchmark.benchmark(' ' * 20 + Benchmark::Tms::CAPTION, 20) do |b|
196
+ b.report('inserting data') do
197
+ data1.each_with_index { |e, i| mdb.insert(e) }
198
+ end
199
+
200
+ b.report('reading data') do
201
+ data1.each_with_index { |e, i| nothing = mdb.find_one({ "_id" => i.to_s }) }
202
+ end
203
+ end
@@ -123,22 +123,94 @@ extern TCLIST *vhashtolist(VALUE vhash){
123
123
  return list;
124
124
  }
125
125
 
126
+ extern TCLIST *vhashtoputlist(VALUE vhash){
127
+ VALUE vkey, vval, vkeys, vvals;
128
+ TCLIST *list;
129
+ int i, j;
130
+ vkeys = rb_funcall(vhash, rb_intern("keys"), 0);
131
+ list = tclistnew();
132
+ for(i = 0; i < RARRAY_LEN(vkeys); i++){
133
+ vkey = rb_ary_entry(vkeys, i);
134
+ vkey = StringValueEx(vkey);
135
+
136
+ vvals = rb_hash_aref(vhash, vkey);
137
+ if (TYPE(vvals) == T_ARRAY){
138
+ for(j = 0; j < RARRAY_LEN(vvals); j++){
139
+ vval = rb_ary_entry(vvals, j);
140
+ vval = StringValueEx(vval);
141
+ tclistpush(list, RSTRING_PTR(vkey), RSTRING_LEN(vkey));
142
+ tclistpush(list, RSTRING_PTR(vval), RSTRING_LEN(vval));
143
+ }
144
+ } else {
145
+ vval = StringValueEx(vvals);
146
+ tclistpush(list, RSTRING_PTR(vkey), RSTRING_LEN(vkey));
147
+ tclistpush(list, RSTRING_PTR(vval), RSTRING_LEN(vval));
148
+ }
149
+ }
150
+ return list;
151
+ }
152
+
153
+ extern VALUE listtovhash(TCLIST *list){
154
+ VALUE vhash, vkey, vval, vvals;
155
+ const char *key, *val;
156
+ int i, num, ksiz, vsiz;
157
+ vhash = rb_hash_new();
158
+
159
+ num = tclistnum(list);
160
+ for(i = 0; i < num; i += 2){
161
+ key = tclistval(list, i, &ksiz);
162
+ val = tclistval(list, i + 1, &vsiz);
163
+ vkey = rb_str_new(key, ksiz);
164
+ vval = rb_str_new(val, vsiz);
165
+
166
+ vvals = rb_hash_aref(vhash, vkey);
167
+ if (TYPE(vvals) != T_ARRAY) vvals = rb_ary_new();
168
+ vvals = rb_ary_push(vvals, vval);
169
+ rb_hash_aset(vhash, vkey, vvals);
170
+ }
171
+ return vhash;
172
+ }
173
+
126
174
  VALUE mTokyoTyrant;
175
+
127
176
  VALUE eTokyoTyrantError;
177
+ VALUE eTokyoTyrantErrorInvalid;
178
+ VALUE eTokyoTyrantErrorNoHost;
179
+ VALUE eTokyoTyrantErrorRefused;
180
+ VALUE eTokyoTyrantErrorSend;
181
+ VALUE eTokyoTyrantErrorReceive;
182
+ VALUE eTokyoTyrantErrorKeep;
183
+ VALUE eTokyoTyrantErrorNoRecord;
184
+ VALUE eTokyoTyrantErrorMisc;
185
+
128
186
  VALUE cDB;
187
+ VALUE cBDB;
129
188
  VALUE cTable;
130
189
  VALUE cQuery;
131
- VALUE cMDB;
190
+ VALUE cConstistentHash;
132
191
 
133
192
  void Init_tokyo_tyrant(){
134
193
  mTokyoTyrant = rb_define_module("TokyoTyrant");
194
+
135
195
  eTokyoTyrantError = rb_define_class("TokyoTyrantError", rb_eStandardError);
196
+ eTokyoTyrantErrorInvalid = rb_define_class("TokyoTyrantErrorInvalid", eTokyoTyrantError);
197
+ eTokyoTyrantErrorNoHost = rb_define_class("TokyoTyrantErrorNoHost", eTokyoTyrantError);
198
+ eTokyoTyrantErrorRefused = rb_define_class("TokyoTyrantErrorRefused", eTokyoTyrantError);
199
+ eTokyoTyrantErrorSend = rb_define_class("TokyoTyrantErrorSend", eTokyoTyrantError);
200
+ eTokyoTyrantErrorReceive = rb_define_class("TokyoTyrantErrorReceive", eTokyoTyrantError);
201
+ eTokyoTyrantErrorKeep = rb_define_class("TokyoTyrantErrorKeep", eTokyoTyrantError);
202
+ eTokyoTyrantErrorNoRecord = rb_define_class("TokyoTyrantErrorNoRecord", eTokyoTyrantError);
203
+ eTokyoTyrantErrorMisc = rb_define_class("TokyoTyrantErrorMisc", eTokyoTyrantError);
204
+
136
205
  init_mod();
137
206
 
138
207
  cDB = rb_define_class_under(mTokyoTyrant, "DB", rb_cObject);
139
208
  rb_include_module(cDB, mTokyoTyrant);
140
209
  init_db();
141
210
 
211
+ cBDB = rb_define_class_under(mTokyoTyrant, "BDB", cDB);
212
+ init_bdb();
213
+
142
214
  cTable = rb_define_class_under(mTokyoTyrant, "Table", rb_cObject);
143
215
  rb_include_module(cTable, mTokyoTyrant);
144
216
  init_table();
@@ -146,6 +218,6 @@ void Init_tokyo_tyrant(){
146
218
  cQuery = rb_define_class_under(mTokyoTyrant, "Query", rb_cObject);
147
219
  init_query();
148
220
 
149
- cMDB = rb_define_class_under(mTokyoTyrant, "MDB", rb_cObject);
150
- init_utils();
221
+ cConstistentHash = rb_define_class_under(mTokyoTyrant, "ConstistentHash", rb_cObject);
222
+ init_consistent_hash();
151
223
  }