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
@@ -0,0 +1,47 @@
1
+ require 'tarantool/em_db'
2
+
3
+ module Tarantool
4
+ class CallbackDB < EMDB
5
+ class SpaceArray < ::Tarantool::SpaceArray
6
+ alias by_pk by_pk_blk
7
+ alias all_by_key all_by_key_blk
8
+ alias first_by_key first_by_key_blk
9
+ alias all_by_keys all_by_keys_blk
10
+ alias select select_blk
11
+ alias insert insert_blk
12
+ alias replace replace_blk
13
+ alias update update_blk
14
+ alias delete delete_blk
15
+ alias invoke invoke_blk
16
+ alias call call_blk
17
+ alias ping ping_blk
18
+ end
19
+
20
+ class SpaceHash < ::Tarantool::SpaceHash
21
+ alias by_pk by_pk_blk
22
+ alias all all_blk
23
+ alias first first_blk
24
+ alias select select_blk
25
+ alias insert insert_blk
26
+ alias replace replace_blk
27
+ alias update update_blk
28
+ alias delete delete_blk
29
+ alias invoke invoke_blk
30
+ alias call call_blk
31
+ alias ping ping_blk
32
+ end
33
+
34
+ class Query < ::Tarantool::Query
35
+ alias select select_blk
36
+ alias all all_blk
37
+ alias first first_blk
38
+ alias insert insert_blk
39
+ alias replace replace_blk
40
+ alias update update_blk
41
+ alias delete delete_blk
42
+ alias invoke invoke_blk
43
+ alias call call_blk
44
+ alias ping ping_blk
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,12 @@
1
+ require 'fiber'
2
+
3
+ class Fiber
4
+ alias call resume
5
+ end
6
+
7
+ module Kernel
8
+ def fiber_yield
9
+ Fiber.yield
10
+ end
11
+ alias fyield fiber_yield
12
+ end
@@ -0,0 +1,37 @@
1
+ module Tarantool
2
+ class EMDB < DB
3
+ def establish_connection
4
+ @connection_waiters = []
5
+ EM.schedule do
6
+ unless @closed
7
+ @connection = IProto.get_connection(@host, @port, :em_callback)
8
+ while waiter = @connection_waiters.shift
9
+ _send_request(*waiter)
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ def close_connection
16
+ EM.schedule do
17
+ if @connection
18
+ @connection.close
19
+ @connection = nil
20
+ end
21
+ unless @connection_waiters.empty?
22
+ while waiter = @connection_waiters.shift
23
+ waiter.last.call(::IProto::Disconnected)
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ def _send_request(request_type, body, cb)
30
+ if @connection
31
+ @connection.send_request(request_type, body, cb)
32
+ else
33
+ @connection_waiters << [request_type, body, cb]
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,9 +1,54 @@
1
- class Tarantool
1
+ module Tarantool
2
+ class ArgumentError < ::ArgumentError; end
3
+ class StringTooLong < ArgumentError; end
4
+
2
5
  class TarantoolError < StandardError; end
3
- class UndefinedRequestType < TarantoolError; end
4
- class BadReturnCode < TarantoolError; end
5
- class StringTooLong < TarantoolError; end
6
- class ArgumentError < TarantoolError; end
7
- class UndefinedSpace < TarantoolError; end
8
6
  class ValueError < TarantoolError; end
9
- end
7
+ class StatusCode < TarantoolError
8
+ attr_reader :code
9
+ def initialize(code, msg)
10
+ super(msg)
11
+ @code = code
12
+ end
13
+ def to_s
14
+ "#{super} [#{code}]"
15
+ end
16
+ end
17
+ # try again return codes
18
+ class TryAgain < StatusCode; end
19
+ class TupleReadOnly < TryAgain; end
20
+ class TupleIsLocked < TryAgain; end
21
+ class MemoryIssue < TryAgain; end
22
+ # general error return codes
23
+ class BadReturnCode < StatusCode; end
24
+ class NonMaster < BadReturnCode; end
25
+ class IllegalParams < BadReturnCode; end
26
+ class UnsupportedCommand < BadReturnCode; end
27
+ class WrongField < BadReturnCode; end
28
+ class WrongNumber < BadReturnCode; end
29
+ class Duplicate < BadReturnCode; end # it is rather useful
30
+ class WrongVersion < BadReturnCode; end
31
+ class WalIO < BadReturnCode; end
32
+ class LuaError < BadReturnCode; end
33
+ class StoredProcedureNotDefined < BadReturnCode; end
34
+ class TupleExists < BadReturnCode; end
35
+ class TupleDoesntExists < BadReturnCode; end
36
+ CODE_TO_EXCEPTION = {
37
+ 0x0401 => TupleReadOnly,
38
+ 0x0601 => TupleIsLocked,
39
+ 0x0701 => MemoryIssue,
40
+ 0x0102 => NonMaster,
41
+ 0x0202 => IllegalParams,
42
+ 0x0a02 => UnsupportedCommand,
43
+ 0x1e02 => WrongField,
44
+ 0x1f02 => WrongNumber,
45
+ 0x2002 => Duplicate,
46
+ 0x2602 => WrongVersion,
47
+ 0x2702 => WalIO,
48
+ 0x3102 => TupleDoesntExists,
49
+ 0x3202 => StoredProcedureNotDefined,
50
+ 0x3302 => LuaError,
51
+ 0x3702 => TupleExists,
52
+ }
53
+ CODE_TO_EXCEPTION.default = BadReturnCode
54
+ end
@@ -0,0 +1,152 @@
1
+ require 'iproto/core-ext'
2
+ require 'tarantool/em_db'
3
+
4
+ module Tarantool
5
+ class FiberDB < EMDB
6
+ module CommonSpaceFiberMethods
7
+ def all_by_pks(pks, opts={})
8
+ all_by_pks_cb(pks, ::Fiber.current, opts)
9
+ _raise_or_return ::Fiber.yield
10
+ end
11
+
12
+ def by_pk(pk)
13
+ by_pk_cb(pk, ::Fiber.current)
14
+ _raise_or_return ::Fiber.yield
15
+ end
16
+
17
+ def insert(tuple, opts={})
18
+ insert_cb(tuple, ::Fiber.current, opts)
19
+ _raise_or_return ::Fiber.yield
20
+ end
21
+
22
+ def replace(tuple, opts={})
23
+ replace_cb(tuple, ::Fiber.current, opts)
24
+ _raise_or_return ::Fiber.yield
25
+ end
26
+
27
+ def update(pk, operations, opts={})
28
+ update_cb(pk, operations, ::Fiber.current, opts)
29
+ _raise_or_return ::Fiber.yield
30
+ end
31
+
32
+ def delete(pk, opts={})
33
+ delete_cb(pk, ::Fiber.current, opts)
34
+ _raise_or_return ::Fiber.yield
35
+ end
36
+
37
+ def invoke(func_name, values = [], opts = {})
38
+ invoke_cb(func_name, values, ::Fiber.current, opts)
39
+ _raise_or_return ::Fiber.yield
40
+ end
41
+
42
+ def call(func_name, values = [], opts = {})
43
+ call_cb(func_name, values, ::Fiber.current, opts)
44
+ _raise_or_return ::Fiber.yield
45
+ end
46
+
47
+ def ping
48
+ ping_cb(::Fiber.current)
49
+ _raise_or_return ::Fiber.yield
50
+ end
51
+ end
52
+
53
+ class SpaceArray < ::Tarantool::SpaceArray
54
+ include CommonSpaceFiberMethods
55
+ def all_by_key(index_no, key, opts={})
56
+ all_by_key_cb(index_no, key, ::Fiber.current, opts)
57
+ _raise_or_return ::Fiber.yield
58
+ end
59
+
60
+ def first_by_key(index_no, key)
61
+ first_by_key_cb(index_no, key, ::Fiber.current)
62
+ _raise_or_return ::Fiber.yield
63
+ end
64
+
65
+ def all_by_keys(index_no, key, opts={})
66
+ all_by_keys_cb(index_no, key, ::Fiber.current, opts)
67
+ _raise_or_return ::Fiber.yield
68
+ end
69
+
70
+ def select(index_no, keys, offset=0, limit=-1)
71
+ select_cb(index_no, keys, offset, limit, ::Fiber.current)
72
+ _raise_or_return ::Fiber.yield
73
+ end
74
+ end
75
+
76
+ class SpaceHash < ::Tarantool::SpaceHash
77
+ include CommonSpaceFiberMethods
78
+
79
+ def by_pk(key_array)
80
+ by_pk_cb(key_array, ::Fiber.current)
81
+ _raise_or_return ::Fiber.yield
82
+ end
83
+
84
+ def all(keys, opts = {})
85
+ all_cb(keys, ::Fiber.current, opts)
86
+ _raise_or_return ::Fiber.yield
87
+ end
88
+
89
+ def first(key)
90
+ first_cb(key, ::Fiber.current)
91
+ _raise_or_return ::Fiber.yield
92
+ end
93
+
94
+ def select(keys, offset=0, limit=-1)
95
+ select_cb(keys, offset, limit, ::Fiber.current)
96
+ _raise_or_return ::Fiber.yield
97
+ end
98
+ end
99
+
100
+ class Query < ::Tarantool::Query
101
+ def select(space_no, index_no, keys, offset, limit, opts={})
102
+ select_cb(space_no, index_no, keys, offset, limit, ::Fiber.current, opts)
103
+ _raise_or_return ::Fiber.yield
104
+ end
105
+
106
+ def all(space_no, index_no, keys, opts={})
107
+ all_cb(space_no, index_no, keys, ::Fiber.current, opts)
108
+ _raise_or_return ::Fiber.yield
109
+ end
110
+
111
+ def first(space_no, index_no, key, opts={})
112
+ first_cb(space_no, index_no, key, ::Fiber.current, opts)
113
+ _raise_or_return ::Fiber.yield
114
+ end
115
+
116
+ def insert(space_no, tuple, opts={})
117
+ insert_cb(space_no, tuple, ::Fiber.current, opts)
118
+ _raise_or_return ::Fiber.yield
119
+ end
120
+
121
+ def replace(space_no, tuple, opts={})
122
+ replace_cb(space_no, tuple, ::Fiber.current, opts)
123
+ _raise_or_return ::Fiber.yield
124
+ end
125
+
126
+ def update(space_no, pk, operation, opts={})
127
+ update_cb(space_no, pk, operation, ::Fiber.current, opts)
128
+ _raise_or_return ::Fiber.yield
129
+ end
130
+
131
+ def delete(space_no, pk, opts={})
132
+ delete_cb(space_no, pk, ::Fiber.current, opts)
133
+ _raise_or_return ::Fiber.yield
134
+ end
135
+
136
+ def invoke(func_name, values, opts={})
137
+ invoke_cb(func_name, values, ::Fiber.current, opts)
138
+ _raise_or_return ::Fiber.yield
139
+ end
140
+
141
+ def call(func_name, values, opts={})
142
+ call_cb(func_name, values, ::Fiber.current, opts)
143
+ _raise_or_return ::Fiber.yield
144
+ end
145
+
146
+ def ping
147
+ ping_cb(::Fiber.current)
148
+ _raise_or_return ::Fiber.yield
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,68 @@
1
+ require 'tarantool/base_record'
2
+
3
+ module Tarantool
4
+ class LightRecord < BaseRecord
5
+ def initialize(attributes = nil)
6
+ @__new_record = true
7
+ @attributes = self.class.default_values.dup
8
+ set_attributes(attributes) if attributes
9
+ after_init
10
+ end
11
+
12
+ def __fetched(attributes)
13
+ @__new_record = false
14
+ @attributes = attributes
15
+ after_init
16
+ self
17
+ end
18
+
19
+ # callback which runs both after initialization and after
20
+ # fetching from database
21
+ def after_init
22
+ end
23
+
24
+ def save
25
+ if @__new_record
26
+ self.class.insert(@attributes)
27
+ @__new_record = false
28
+ else
29
+ self.class.replace(@attributes)
30
+ end
31
+ self
32
+ end
33
+
34
+ def destroy
35
+ self.class.delete id
36
+ true
37
+ end
38
+
39
+ class << self
40
+ def generated_attribute_methods
41
+ @generated_attribute_methods ||= begin
42
+ include (mod = Module.new)
43
+ mod
44
+ end
45
+ end
46
+
47
+ def define_field_accessor(name, type)
48
+ generated_attribute_methods.class_eval <<-"EOF", __FILE__, __LINE__ - 1
49
+ def #{name}
50
+ @attributes[:"#{name}"]
51
+ end
52
+
53
+ def #{name}=(v)
54
+ @attributes[:"#{name}"] = v
55
+ end
56
+ EOF
57
+ end
58
+
59
+ def create(attrs)
60
+ new(attrs).save
61
+ end
62
+
63
+ def from_fetched(attributes)
64
+ attributes && allocate.__fetched(attributes)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,127 @@
1
+ require 'tarantool/request'
2
+ require 'tarantool/response'
3
+
4
+ module Tarantool
5
+ class Query
6
+ include Request
7
+ def initialize(tarantool)
8
+ @tarantool = tarantool
9
+ end
10
+
11
+ def _send_request(type, body, cb)
12
+ @tarantool._send_request(type, body, cb)
13
+ end
14
+
15
+ def select_cb(space_no, index_no, keys, offset, limit, cb, opts={})
16
+ keys = [*keys]
17
+ types = opts[:types] || _detect_types(keys)
18
+ returns = opts[:returns] || TYPES_AUTO
19
+ if Hash === returns
20
+ returns, *translators = _parse_hash_definition(returns)
21
+ end
22
+ _select(space_no, index_no, offset, limit, keys, cb, returns,
23
+ types, translators)
24
+ end
25
+
26
+ def all_cb(space_no, index_no, keys, cb, opts={})
27
+ select_cb(space_no, index_no, keys,
28
+ opts[:offset] || 0, opts[:limit] || -1,
29
+ cb, opts)
30
+ end
31
+
32
+ def first_cb(space_no, index_no, key, cb, opts={})
33
+ select_cb(space_no, index_no, [key], 0, :first, cb, opts)
34
+ end
35
+
36
+ def insert_cb(space_no, tuple, cb, opts={})
37
+ types = opts[:types] || _detect_types(tuple)
38
+ _insert(space_no, BOX_ADD, tuple, types, cb, opts[:return_tuple])
39
+ end
40
+
41
+ def replace_cb(space_no, tuple, cb, opts={})
42
+ types = opts[:types] || _detect_types(tuple)
43
+ _insert(space_no, BOX_REPLACE, tuple, types, cb, opts[:return_tuple])
44
+ end
45
+
46
+ def update_cb(space_no, pk, operations, cb, opts={})
47
+ pk = [*pk]
48
+ pk_types = opts[:pk_types] || _detect_types(pk)
49
+ returns = opts[:returns] || TYPES_AUTO
50
+ if Hash === returns && opts[:return_tuple]
51
+ returns, *translators = _parse_hash_definition(returns)
52
+ end
53
+ _update(space_no, pk, operations, returns, pk_types, cb,
54
+ opts[:return_tuple], translators)
55
+ end
56
+
57
+ def delete_cb(space_no, pk, cb, opts={})
58
+ pk = [*pk]
59
+ pk_types = opts[:pk_types] || _detect_types(pk)
60
+ returns = opts[:returns] || TYPES_AUTO
61
+ if Hash === returns && opts[:return_tuple]
62
+ returns, *translators = _parse_hash_definition(returns)
63
+ end
64
+ _delete(space_no, pk, returns, pk_types, cb,
65
+ opts[:return_tuple], translators)
66
+ end
67
+
68
+ def invoke_cb(func_name, values, cb, opts={})
69
+ opts = opts.dup
70
+ values = [*values]
71
+ opts[:types] ||= _detect_types(values)
72
+ _call(func_name, values, cb, opts)
73
+ end
74
+
75
+ def call_cb(func_name, values, cb, opts={})
76
+ opts = opts.dup
77
+ values = [*values]
78
+ opts[:return_tuple] = true if opts[:return_tuple].nil?
79
+ opts[:types] ||= _detect_types(values)
80
+ opts[:returns] ||= TYPES_AUTO
81
+ if Hash === opts[:returns] && opts[:return_tuple]
82
+ opts[:returns], *opts[:translators] = _parse_hash_definition(opts[:returns])
83
+ end
84
+ _call(func_name, values, cb, opts)
85
+ end
86
+
87
+ def select_blk(space_no, index_no, keys, offset, limit, opts={}, &block)
88
+ select_cb(space_no, index_no, keys, offset, limit, block, opts)
89
+ end
90
+
91
+ def all_blk(space_no, index_no, keys, opts={}, &block)
92
+ all_cb(space_no, index_no, keys, block, opts)
93
+ end
94
+
95
+ def first_blk(space_no, index_no, key, opts={}, &block)
96
+ first_cb(space_no, index_no, key, block, opts)
97
+ end
98
+
99
+ def insert_blk(space_no, tuple, opts={}, &block)
100
+ insert_cb(space_no, tuple, block, opts)
101
+ end
102
+
103
+ def replace_blk(space_no, tuple, opts={}, &block)
104
+ replace_cb(space_no, tuple, block, opts)
105
+ end
106
+
107
+ def update_blk(space_no, pk, operation, opts={}, &block)
108
+ update_cb(space_no, pk, operation, block, opts={})
109
+ end
110
+
111
+ def delete_blk(space_no, pk, opts={}, &block)
112
+ delete_cb(space_no, pk, block, opts)
113
+ end
114
+
115
+ def invoke_blk(func_name, values, opts={}, &block)
116
+ invoke_cb(func_name, values, block, opts)
117
+ end
118
+
119
+ def call_blk(func_name, values, opts={}, &block)
120
+ call_cb(func_name, values, block, opts)
121
+ end
122
+
123
+ def ping_blk(&block)
124
+ ping_cb(block)
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,59 @@
1
+ module Tarantool
2
+ class BaseRecord
3
+ class Select
4
+ include Enumerable
5
+
6
+ attr_reader :record, :params
7
+ def initialize(record, params={})
8
+ @record = record
9
+ @params = params
10
+ end
11
+
12
+ def space_no
13
+ @record.space_no
14
+ end
15
+
16
+ def results
17
+ @results ||= begin
18
+ raise "Condition is not set" unless @params[:where]
19
+ @record.auto_space.select(
20
+ @params[:where],
21
+ @params[:offset] || 0,
22
+ @params[:limit] || -1
23
+ )
24
+ end
25
+ end
26
+
27
+ def each
28
+ return to_enum unless block_given?
29
+ results.each{|a| yield a}
30
+ end
31
+
32
+ def call(*args)
33
+ @record.call(*args)
34
+ end
35
+
36
+ def limit(limit)
37
+ self.class.new(@record, @params.merge(limit: limit))
38
+ end
39
+
40
+ def offset(offset)
41
+ self.class.new(@record, @params.merge(offset: offset))
42
+ end
43
+
44
+ def where(params)
45
+ self.class.new(@record, @params.merge(where: params))
46
+ end
47
+
48
+ def all
49
+ results.dup
50
+ end
51
+
52
+ def first
53
+ @record.auto_space.
54
+ select(@params[:where], @params[:offset] || 0, 1).
55
+ first
56
+ end
57
+ end
58
+ end
59
+ end