tarantool 0.2.5 → 0.3.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/Gemfile +14 -12
  2. data/LICENSE +4 -4
  3. data/README.md +15 -9
  4. data/Rakefile +5 -129
  5. data/lib/tarantool/base_record.rb +288 -0
  6. data/lib/tarantool/block_db.rb +135 -0
  7. data/lib/tarantool/callback_db.rb +47 -0
  8. data/lib/tarantool/core-ext.rb +12 -0
  9. data/lib/tarantool/em_db.rb +37 -0
  10. data/lib/tarantool/exceptions.rb +52 -7
  11. data/lib/tarantool/fiber_db.rb +152 -0
  12. data/lib/tarantool/light_record.rb +68 -0
  13. data/lib/tarantool/query.rb +127 -0
  14. data/lib/tarantool/record/select.rb +59 -0
  15. data/lib/tarantool/record.rb +93 -282
  16. data/lib/tarantool/request.rb +351 -52
  17. data/lib/tarantool/response.rb +108 -45
  18. data/lib/tarantool/serializers/bson.rb +2 -2
  19. data/lib/tarantool/serializers.rb +32 -4
  20. data/lib/tarantool/space_array.rb +153 -0
  21. data/lib/tarantool/space_hash.rb +262 -0
  22. data/lib/tarantool/util.rb +182 -0
  23. data/lib/tarantool/version.rb +3 -0
  24. data/lib/tarantool.rb +79 -29
  25. data/test/box.pid +1 -0
  26. data/test/helper.rb +164 -0
  27. data/test/run_all.rb +3 -0
  28. data/test/shared_query.rb +73 -0
  29. data/test/shared_record.rb +474 -0
  30. data/test/shared_space_array.rb +284 -0
  31. data/test/shared_space_hash.rb +239 -0
  32. data/test/tarant/init.lua +22 -0
  33. data/test/tarantool.cfg +62 -0
  34. data/test/tarantool.log +6 -0
  35. data/{spec/tarantool.cfg → test/tarantool_repl.cfg} +11 -5
  36. data/test/test_light_record.rb +48 -0
  37. data/test/test_query_block.rb +6 -0
  38. data/test/test_query_fiber.rb +7 -0
  39. data/test/test_record.rb +88 -0
  40. data/{spec/tarantool/composite_primary_key_spec.rb → test/test_record_composite_pk.rb} +5 -7
  41. data/test/test_space_array_block.rb +6 -0
  42. data/test/test_space_array_callback.rb +255 -0
  43. data/test/test_space_array_callback_nodef.rb +190 -0
  44. data/test/test_space_array_fiber.rb +7 -0
  45. data/test/test_space_hash_block.rb +6 -0
  46. data/test/test_space_hash_fiber.rb +7 -0
  47. metadata +78 -55
  48. data/Gemfile.lock +0 -54
  49. data/examples/em_simple.rb +0 -16
  50. data/examples/record.rb +0 -68
  51. data/examples/simple.rb +0 -13
  52. data/lib/tarantool/requests/call.rb +0 -20
  53. data/lib/tarantool/requests/delete.rb +0 -18
  54. data/lib/tarantool/requests/insert.rb +0 -19
  55. data/lib/tarantool/requests/ping.rb +0 -16
  56. data/lib/tarantool/requests/select.rb +0 -22
  57. data/lib/tarantool/requests/update.rb +0 -35
  58. data/lib/tarantool/requests.rb +0 -19
  59. data/lib/tarantool/serializers/integer.rb +0 -14
  60. data/lib/tarantool/serializers/string.rb +0 -14
  61. data/lib/tarantool/space.rb +0 -39
  62. data/spec/helpers/let.rb +0 -11
  63. data/spec/helpers/truncate.rb +0 -12
  64. data/spec/spec_helper.rb +0 -21
  65. data/spec/tarantool/em_spec.rb +0 -22
  66. data/spec/tarantool/record_spec.rb +0 -316
  67. data/spec/tarantool/request_spec.rb +0 -103
  68. data/tarantool.gemspec +0 -69
data/lib/tarantool.rb CHANGED
@@ -1,36 +1,86 @@
1
- # -*- coding: utf-8 -*-
2
- require 'iproto'
3
-
4
- class Tarantool
5
- VERSION = '0.2.5'
6
-
7
- require 'tarantool/space'
8
- require 'tarantool/requests'
9
- require 'tarantool/response'
10
- require 'tarantool/exceptions'
11
- require 'tarantool/serializers'
12
-
13
- attr_reader :config
14
- def initialize(config = {})
15
- @config = config
16
- end
1
+ require 'eventmachine'
2
+ require "iproto"
3
+ require "tarantool/version"
4
+ require "tarantool/request"
5
+ require "tarantool/response"
6
+ require "tarantool/space_array.rb"
7
+ require "tarantool/space_hash.rb"
8
+ require "tarantool/query.rb"
9
+ require "tarantool/serializers.rb"
17
10
 
18
- def configure(config)
19
- @config.merge! config
20
- end
11
+ module Tarantool
12
+ #autoload :Record, 'tarantool/record'
13
+ #autoload :LightRecord, 'tarantool/light_record'
21
14
 
22
- def connection(c = config)
23
- @connection ||= begin
24
- raise "Tarantool.configure before connect" unless c
25
- IProto.get_connection c[:host], c[:port], c[:type] || :block
15
+ class << self
16
+ def new(conf)
17
+ case conf[:type] || :block
18
+ when :em, :em_fiber
19
+ require 'tarantool/fiber_db'
20
+ FiberDB.new(conf[:host], conf[:port])
21
+ when :em_cb, :em_callback
22
+ require 'tarantool/callback_db'
23
+ CallbackDB.new(conf[:host], conf[:port])
24
+ when :block
25
+ require 'tarantool/block_db'
26
+ BlockDB.new(conf[:host], conf[:port])
27
+ end
26
28
  end
27
29
  end
28
30
 
29
- def space(no, conn = connection)
30
- Space.new conn, no
31
- end
31
+ class DB
32
+ attr_reader :closed, :connection
33
+ alias closed? closed
34
+ def initialize(host, port)
35
+ @host = host
36
+ @port = port
37
+ @closed = false
38
+ establish_connection
39
+ end
40
+
41
+ # returns regular space, where fields are named by position
42
+ #
43
+ # tarantool.space_block(0, [:int, :str, :int, :str], keys: [[0], [1,2]])
44
+ def space_array(space_no, field_types = [], opts = {})
45
+ indexes = opts[:keys] || opts[:indexes]
46
+ self.class::SpaceArray.new(self, space_no, field_types, indexes)
47
+ end
48
+ # alias space_array to space for backward compatibility
49
+ alias space space_array
50
+
51
+ def space_hash(space_no, fields, opts = {})
52
+ indexes = opts[:keys] || opts[:indexes]
53
+ self.class::SpaceHash.new(self, space_no, fields, indexes)
54
+ end
55
+
56
+ def query
57
+ @query ||= self.class::Query.new(self)
58
+ end
59
+
60
+ def method_missing(name, *args)
61
+ if query.respond_to?(name)
62
+ query.send(name, *args)
63
+ else
64
+ super
65
+ end
66
+ end
67
+
68
+ def close
69
+ @closed = true
70
+ close_connection
71
+ end
72
+
73
+ def establish_connection
74
+ raise NoMethodError, "#establish_connection should be redefined"
75
+ end
76
+
77
+ def close_connection
78
+ raise NoMethodError, "#close_connection should be redefined"
79
+ end
80
+
81
+ def _send_request(request_type, body, cb)
82
+ raise NoMethodError, "#_send_request should be redefined"
83
+ end
32
84
 
33
- def self.hexdump(string)
34
- string.unpack('C*').map{ |c| "%02x" % c }.join(' ')
35
85
  end
36
- end
86
+ end
data/test/box.pid ADDED
@@ -0,0 +1 @@
1
+ 2887
data/test/helper.rb ADDED
@@ -0,0 +1,164 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/autorun'
3
+ require 'rr'
4
+
5
+ require 'tarantool'
6
+
7
+ class ArrayPackSerializer
8
+ def encode(arr)
9
+ arr.pack("N*")
10
+ end
11
+
12
+ def decode(str)
13
+ str.unpack("N*")
14
+ end
15
+ end
16
+
17
+ TCONFIG = { host: '127.0.0.1', port: 33013, admin: 33015 }
18
+
19
+ SPACE0 = {
20
+ types: [:str, :str, :str, :int],
21
+ keys: [0, [1,2], 3]
22
+ }
23
+ SPACE1 = {
24
+ types: [:int, :str, :int, 2],
25
+ keys: 0
26
+ }
27
+ SPACE2 = {
28
+ types: [:str, :str, :int],
29
+ keys: [[0,1], 2]
30
+ }
31
+ SPACE3 = {
32
+ types: [:int, ArrayPackSerializer.new],
33
+ keys: [0, 1]
34
+ }
35
+
36
+ HSPACE0 = {
37
+ fields: {name: :str, surname: :str, email: :str, score: :int},
38
+ keys: [:name, %w{surname email}, 'score']
39
+ }
40
+ HSPACE1 = {
41
+ fields: {id: :int, _tail: [:str, :int]},
42
+ keys: :id
43
+ }
44
+ HSPACE2 = {
45
+ fields: {first: :str, second: :str, third: :int},
46
+ keys: [%w{first second}, :third]
47
+ }
48
+ HSPACE3 = {
49
+ fields: {id: :int, scores: ArrayPackSerializer.new},
50
+ keys: [:id, :scores]
51
+ }
52
+
53
+ module Helper
54
+ def tarantool_pipe
55
+ $tarantool_pipe ||= begin
56
+ cnf = TCONFIG
57
+ tarant = %W{tarantool -p #{cnf[:port]} -m #{cnf[:admin]}}
58
+ tarant = [{}, *tarant, :err => [:child, :out]]
59
+ IO.popen(tarant, 'w+').tap{|p| p.sync = true}
60
+ end
61
+ end
62
+
63
+ def exec_tarantool(cmd, lines_to_read)
64
+ cmd = cmd.gsub(/^\s+/, '')
65
+ tarantool_pipe.puts(cmd)
66
+ tarantool_pipe.flush
67
+ lines_to_read.times do
68
+ tarantool_pipe.gets
69
+ end
70
+ end
71
+
72
+ def truncate
73
+ exec_tarantool "
74
+ lua truncate(0)
75
+ lua truncate(1)
76
+ lua truncate(2)
77
+ lua truncate(3)
78
+ ", 12
79
+ end
80
+
81
+ def seed
82
+ exec_tarantool "
83
+ insert into t0 values ('vasya', 'petrov', 'eb@lo.com', 5)
84
+ insert into t0 values ('ilya', 'zimov', 'il@zi.bot', 13)
85
+ insert into t0 values ('fedor', 'kuklin', 'ku@kl.in', 13)
86
+ insert into t1 values (1, 'common', 4)
87
+ insert into t1 values (2, 'medium', 6, 'common', 7)
88
+ insert into t2 values ('hi zo', 'ho zo', 1)
89
+ insert into t2 values ('hi zo', 'pidas', 1, 3, 5)
90
+ insert into t2 values ('coma', 'peredoma', 2)
91
+ ", 16
92
+ end
93
+
94
+ def clear_db
95
+ truncate
96
+ seed
97
+ end
98
+
99
+ def emrun(semaphore = 1)
100
+ @semaphore = semaphore
101
+ EM.run {
102
+ @timeout_timer = EM.add_timer(1) {
103
+ EM.stop
104
+ assert false, "timeout encounted"
105
+ }
106
+ yield
107
+ }
108
+ end
109
+
110
+ def emstop
111
+ @semaphore -= 1
112
+ if @semaphore == 0
113
+ EM.cancel_timer @timeout_timer
114
+ EM.next_tick{ EM.stop }
115
+ end
116
+ end
117
+
118
+ def fibrun
119
+ res = nil
120
+ EM.run {
121
+ f = Fiber.new{
122
+ begin
123
+ res = yield
124
+ ensure
125
+ EM.next_tick{ EM.stop }
126
+ end
127
+ }
128
+ EM.next_tick{ f.resume }
129
+ }
130
+ res
131
+ end
132
+
133
+ def blockrun
134
+ yield
135
+ end
136
+
137
+ def mock(u, meth, &block)
138
+ u.define_singleton_method(meth, &block)
139
+ end
140
+ end
141
+
142
+ class MiniTest::Unit::TestCase
143
+ include ::Helper
144
+ include RR::Adapters::MiniTest
145
+ end
146
+
147
+ class << MiniTest::Spec
148
+ def shared_examples
149
+ @shared_examples ||= {}
150
+ end
151
+ end
152
+
153
+ module MiniTest::Spec::SharedExamples
154
+ def shared_examples_for(desc, &block)
155
+ MiniTest::Spec.shared_examples[desc] = block
156
+ end
157
+
158
+ def it_behaves_like(desc)
159
+ class_eval &MiniTest::Spec.shared_examples.fetch(desc)
160
+ end
161
+ end
162
+
163
+ Object.class_eval { include(MiniTest::Spec::SharedExamples) }
164
+
data/test/run_all.rb ADDED
@@ -0,0 +1,3 @@
1
+ Dir.glob(File.expand_path('../test_*.rb', __FILE__)) do |f|
2
+ require f
3
+ end
@@ -0,0 +1,73 @@
1
+ require File.expand_path('../helper.rb', __FILE__)
2
+
3
+ shared_examples_for :blocking_query do
4
+ before { clear_db }
5
+
6
+ let(:vasya){ ['vasya', 'petrov', 'eb@lo.com', 5] }
7
+ let(:ilya) { ['ilya', 'zimov', 'il@zi.bot', 13] }
8
+ let(:fedor){ ['fedor', 'kuklin', 'ku@kl.in', 13] }
9
+ let(:vasya_h) { {name: 'vasya', surname: 'petrov', email: 'eb@lo.com', score: 5} }
10
+ let(:ilya_h) { {name: 'ilya', surname: 'zimov', email: 'il@zi.bot', score: 13} }
11
+ let(:fedor_h) { {name: 'fedor', surname: 'kuklin', email: 'ku@kl.in', score: 13} }
12
+
13
+ it "should be able to select" do
14
+ results = blockrun {[
15
+ tarantool.select(0, 0, 'vasya', 0, -1),
16
+ tarantool.all(0, 1, ['zimov', 'il@zi.bot'], returns: [:str, :str, :str, :int]),
17
+ tarantool.first(0, 2, 13, returns: {name: :str, surname: :str, email: :str, score: :int}),
18
+ tarantool.all(1, 0, 2, returns: [:int, :str, :int, 2]),
19
+ tarantool.all(1, 0, 2, returns: {id: :int, _tail: [:str, :int]})
20
+ ]}
21
+ vasya_s = vasya.dup
22
+ vasya_s[3] = "\x05\x00\x00\x00"
23
+ results[0].must_equal [vasya_s]
24
+ results[1].must_equal [ilya]
25
+ [ilya_h, fedor_h].must_include results[2]
26
+ results[3].must_equal [[2, 'medium', 6, 'common', 7]]
27
+ results[4].must_equal [{id: 2, _tail: [['medium', 6], ['common', 7]]}]
28
+ end
29
+
30
+ it "should insert" do
31
+ results = blockrun {[
32
+ tarantool.insert(0, ['asdf','qwer','zxcv',10], return_tuple: true),
33
+ tarantool.insert(0, ['wert','sdfg','xcvb',1200], types: [:str, :str, :str, :str], return_tuple: true),
34
+ tarantool.insert(1, [3, 'a', 5, 'b', 6], types: [:int, :str, :int, 2], return_tuple: true),
35
+ tarantool.replace(1, [2, 'e', 1]),
36
+ tarantool.first(1, 0, 2, returns: [:int, :str, :int, 2]),
37
+ ]}
38
+ results[0].must_equal ['asdf','qwer','zxcv',10]
39
+ results[1].must_equal ['wert','sdfg','xcvb',"1200"]
40
+ results[2].must_equal [3, 'a', 5, 'b', 6]
41
+ results[3].must_equal 1
42
+ results[4].must_equal [2, 'e', 1]
43
+ end
44
+
45
+ it "should update" do
46
+ results = blockrun {[
47
+ tarantool.update(1, 2, [["+2", 4]], returns: [:int, :str, :int, 2], return_tuple: true)
48
+ ]}
49
+ results[0].must_equal [2, 'medium', 10, 'common', 7]
50
+ end
51
+
52
+ it "should delete" do
53
+ results = blockrun {[
54
+ tarantool.delete(1, 1, returns: [:int, :str, :int, 2], return_tuple: true),
55
+ tarantool.delete(1, 2, returns: {id: :int, _tail: [:str, :int]}, return_tuple: true)
56
+ ]}
57
+ results[0].must_equal [1, 'common', 4]
58
+ results[1].must_equal({id: 2, _tail: [['medium', 6], ['common', 7]]})
59
+ end
60
+
61
+ it "should call" do
62
+ results = blockrun {[
63
+ tarantool.call('func3', ['hello', '2']),
64
+ tarantool.call('func3', ['hello', 2]),
65
+ tarantool.call('func3', [234, 432], returns: [:str, :int]),
66
+ tarantool.call('func3', [234, 432], returns: {type: :str, val: :int}),
67
+ ]}
68
+ results[0].must_equal [['string', 'hello'], ['string', '2']]
69
+ results[1].must_equal [['string', 'hello'], ['string', "\x02\x00\x00\x00"]]
70
+ results[2].must_equal [['string', 234], ['string', 432]]
71
+ results[3].must_equal [{type:'string', val:234}, {type:'string', val:432}]
72
+ end
73
+ end