orientdb4r 0.2.10 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +1 -3
- data/changelog.txt +8 -9
- data/fstudy/flat_class_perf.rb +1 -1
- data/lib/orientdb4r/client.rb +34 -3
- data/lib/orientdb4r/load_balancing.rb +89 -0
- data/lib/orientdb4r/node.rb +7 -1
- data/lib/orientdb4r/rest/client.rb +48 -49
- data/lib/orientdb4r/rest/excon_node.rb +65 -35
- data/lib/orientdb4r/rest/node.rb +5 -25
- data/lib/orientdb4r/rest/restclient_node.rb +27 -38
- data/lib/orientdb4r/utils.rb +1 -1
- data/lib/orientdb4r/version.rb +1 -0
- data/lib/orientdb4r.rb +20 -0
- data/test/test_database.rb +20 -8
- data/test/test_distributed.rb +105 -0
- data/test/test_utils.rb +8 -0
- metadata +5 -2
data/README.rdoc
CHANGED
@@ -63,9 +63,7 @@ see Wiki page for more sample at https://github.com/veny/orientdb4r/wiki
|
|
63
63
|
|
64
64
|
=== Important Upgrade Notice
|
65
65
|
|
66
|
-
*
|
67
|
-
* 2012-06-17 [v0.2.0]: Client#get_class raises Orientdb4r::NotFoundError instead of ArgumentError
|
68
|
-
|
66
|
+
* see changelog.txt
|
69
67
|
|
70
68
|
|
71
69
|
== FEATURES/PROBLEMS
|
data/changelog.txt
CHANGED
@@ -1,20 +1,19 @@
|
|
1
|
-
0.3.0
|
2
|
-
|
3
|
-
-
|
4
|
-
-
|
1
|
+
0.3.0 2012-08-01
|
2
|
+
- introduced support for cluster of distributed servers
|
3
|
+
- initial strategies for load balancing: sequence, round robin
|
4
|
+
- Keep-Alive feature: Excon HTTP library is fully working
|
5
5
|
|
6
|
-
0.2.10
|
6
|
+
0.2.10 2012-07-21
|
7
7
|
- experimental support for Excon HTTP library with Keep-Alive connection
|
8
8
|
|
9
|
-
0.2.9
|
9
|
+
0.2.9 2012-07-18
|
10
10
|
- introduced class Rid
|
11
11
|
- added feature Client#delete_database
|
12
12
|
|
13
|
-
|
14
|
-
0.2.8 /07/07/16
|
13
|
+
0.2.8 2012-07-16
|
15
14
|
- changed and stabilized exception handling
|
16
15
|
- added feature Client#create_class(:properties)
|
17
16
|
|
18
|
-
0.2.7 07
|
17
|
+
0.2.7 2012-07-07
|
19
18
|
- changed design to support distributed server
|
20
19
|
- added method Client#class_exists?
|
data/fstudy/flat_class_perf.rb
CHANGED
data/lib/orientdb4r/client.rb
CHANGED
@@ -9,7 +9,10 @@ module Orientdb4r
|
|
9
9
|
# # Regexp to validate format of providet version.
|
10
10
|
SERVER_VERSION_PATTERN = /^\d+\.\d+\.\d+/
|
11
11
|
|
12
|
+
attr_reader :user, :password, :database
|
12
13
|
attr_reader :server_version
|
14
|
+
attr_reader :nodes, :connection_library
|
15
|
+
attr_reader :load_balancing, :lb_strategy
|
13
16
|
|
14
17
|
###
|
15
18
|
# Constructor.
|
@@ -181,7 +184,7 @@ module Orientdb4r
|
|
181
184
|
opt_pattern = { :mode => :nil }
|
182
185
|
verify_options(options, opt_pattern)
|
183
186
|
if :strict == options[:mode]
|
184
|
-
response =
|
187
|
+
response = call_server(:method => :get, :uri => "connect/#{@database}") # TODO there cannot be REST
|
185
188
|
connect_info = process_response response
|
186
189
|
children = connect_info['classes'].select { |i| i['superClass'] == name }
|
187
190
|
unless children.empty?
|
@@ -256,8 +259,35 @@ module Orientdb4r
|
|
256
259
|
|
257
260
|
protected
|
258
261
|
|
259
|
-
|
260
|
-
|
262
|
+
###
|
263
|
+
# Calls the server with a specific task.
|
264
|
+
# Returns a response according to communication channel (e.g. HTTP response).
|
265
|
+
def call_server(options)
|
266
|
+
lb_all_bad_msg = 'all nodes failed to communicate with server!'
|
267
|
+
response = nil
|
268
|
+
|
269
|
+
# credentials if not defined explicitly
|
270
|
+
options[:user] = user unless options.include? :user
|
271
|
+
options[:password] = password unless options.include? :password
|
272
|
+
|
273
|
+
idx = lb_strategy.node_index
|
274
|
+
raise OrientdbError, lb_all_bad_msg if idx.nil? # no good node found
|
275
|
+
|
276
|
+
begin
|
277
|
+
node = @nodes[idx]
|
278
|
+
begin
|
279
|
+
response = node.request options
|
280
|
+
lb_strategy.good_one idx
|
281
|
+
return response
|
282
|
+
|
283
|
+
rescue NodeError => e
|
284
|
+
Orientdb4r::logger.error "node error, index=#{idx}, msg=#{e.message}, #{node}"
|
285
|
+
lb_strategy.bad_one idx
|
286
|
+
idx = lb_strategy.node_index
|
287
|
+
end
|
288
|
+
end until idx.nil? and response.nil? # both 'nil' <= we tried all nodes and all with problem
|
289
|
+
|
290
|
+
raise OrientdbError, lb_all_bad_msg
|
261
291
|
end
|
262
292
|
|
263
293
|
|
@@ -267,6 +297,7 @@ module Orientdb4r
|
|
267
297
|
raise ConnectionError, 'not connected' unless @connected
|
268
298
|
end
|
269
299
|
|
300
|
+
|
270
301
|
###
|
271
302
|
# Around advice to meassure and print the method time.
|
272
303
|
def time_around(&block)
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Orientdb4r
|
2
|
+
|
3
|
+
###
|
4
|
+
# Base class for implementation of load balancing strategy.
|
5
|
+
class LBStrategy
|
6
|
+
|
7
|
+
# If occures a new try to communicate from node can be tested.
|
8
|
+
RECOVERY_TIMEOUT = 30
|
9
|
+
|
10
|
+
attr_reader :nodes_count, :bad_nodes
|
11
|
+
|
12
|
+
###
|
13
|
+
# Constructor.
|
14
|
+
def initialize nodes_count
|
15
|
+
@nodes_count = nodes_count
|
16
|
+
@bad_nodes = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
###
|
20
|
+
# Gets index of node to be used for next request
|
21
|
+
# or 'nil' if there is no one next.
|
22
|
+
def node_index
|
23
|
+
raise NotImplementedError, 'this should be overridden in subclass'
|
24
|
+
end
|
25
|
+
|
26
|
+
###
|
27
|
+
# Marks an index as good that means it can be used for next server calls.
|
28
|
+
def good_one(idx)
|
29
|
+
@bad_nodes.delete idx
|
30
|
+
end
|
31
|
+
|
32
|
+
###
|
33
|
+
# Marks an index as bad that means it will be not used until:
|
34
|
+
# * there is other 'good' node
|
35
|
+
# * timeout
|
36
|
+
def bad_one(idx)
|
37
|
+
@bad_nodes[idx] = Time.now
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def search_next_good(bad_idx)
|
43
|
+
Orientdb4r::logger.warn "identified bad node, idx=#{bad_idx}, age=#{Time.now - @bad_nodes[bad_idx]} [s]"
|
44
|
+
1.upto(nodes_count) do |i|
|
45
|
+
candidate = (i + bad_idx) % nodes_count
|
46
|
+
unless @bad_nodes.include? candidate
|
47
|
+
Orientdb4r::logger.debug "found good node, idx=#{candidate}"
|
48
|
+
return candidate
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# TODO implement search based on LRU for next round
|
53
|
+
|
54
|
+
Orientdb4r::logger.error 'no nodes more, all invalid'
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
###
|
61
|
+
# Implementation of Sequence strategy.
|
62
|
+
# Assigns work in the order of nodes defined by the client initialization.
|
63
|
+
class Sequence < LBStrategy
|
64
|
+
|
65
|
+
def node_index #:nodoc:
|
66
|
+
@last_index = 0 if @last_index.nil?
|
67
|
+
|
68
|
+
@last_index = search_next_good(@last_index) if @bad_nodes.include? @last_index
|
69
|
+
@last_index
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
###
|
75
|
+
# Implementation of Round Robin strategy.
|
76
|
+
# Assigns work in round-robin order per nodes defined by the client initialization.
|
77
|
+
class RoundRobin < LBStrategy
|
78
|
+
|
79
|
+
def node_index #:nodoc:
|
80
|
+
@last_index = -1 if @last_index.nil?
|
81
|
+
|
82
|
+
@last_index = (@last_index + 1) % nodes_count
|
83
|
+
@last_index = search_next_good(@last_index) if @bad_nodes.include? @last_index
|
84
|
+
@last_index
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
data/lib/orientdb4r/node.rb
CHANGED
@@ -7,6 +7,7 @@ module Orientdb4r
|
|
7
7
|
include Utils
|
8
8
|
|
9
9
|
attr_reader :host, :port # they are immutable
|
10
|
+
attr_reader :session_id
|
10
11
|
|
11
12
|
###
|
12
13
|
# Constructor.
|
@@ -21,7 +22,7 @@ module Orientdb4r
|
|
21
22
|
###
|
22
23
|
# Cleans up resources used by the node.
|
23
24
|
def cleanup
|
24
|
-
|
25
|
+
@session_id = nil
|
25
26
|
end
|
26
27
|
|
27
28
|
|
@@ -31,6 +32,11 @@ module Orientdb4r
|
|
31
32
|
raise NotImplementedError, 'this should be overridden by subclass'
|
32
33
|
end
|
33
34
|
|
35
|
+
|
36
|
+
def to_s #:nodoc:
|
37
|
+
"Node(host=#{host},port=#{port})"
|
38
|
+
end
|
39
|
+
|
34
40
|
end
|
35
41
|
|
36
42
|
end
|
@@ -9,35 +9,45 @@ module Orientdb4r
|
|
9
9
|
before [:create_document, :get_document, :update_document, :delete_document], :assert_connected
|
10
10
|
around [:query, :command], :time_around
|
11
11
|
|
12
|
-
attr_reader :user, :password, :database, :http_lib
|
13
|
-
|
14
12
|
|
15
13
|
def initialize(options) #:nodoc:
|
16
14
|
super()
|
17
15
|
options_pattern = { :host => 'localhost', :port => 2480, :ssl => false,
|
18
|
-
:nodes => :optional,
|
19
|
-
:connection_library =>
|
16
|
+
:nodes => :optional, :load_balancing => :sequence,
|
17
|
+
:connection_library => Orientdb4r::connection_library}
|
20
18
|
verify_and_sanitize_options(options, options_pattern)
|
21
19
|
|
22
20
|
# fake nodes for single server
|
23
|
-
|
21
|
+
if options[:nodes].nil?
|
24
22
|
options[:nodes] = [{:host => options[:host], :port => options[:port], :ssl => options[:ssl]}]
|
25
23
|
end
|
26
24
|
raise ArgumentError, 'nodes has to be arrray' unless options[:nodes].is_a? Array
|
27
25
|
|
28
|
-
|
26
|
+
# instantiate nodes accroding to HTTP library
|
27
|
+
@connection_library = options[:connection_library]
|
28
|
+
node_clazz = case connection_library
|
29
29
|
when :restclient then Orientdb4r::RestClientNode
|
30
30
|
when :excon then Orientdb4r::ExconNode
|
31
|
-
else raise ArgumentError, "unknown connection library: #{
|
31
|
+
else raise ArgumentError, "unknown connection library: #{connection_library}"
|
32
32
|
end
|
33
|
-
@http_lib = options[:connection_library]
|
34
33
|
|
34
|
+
# nodes
|
35
35
|
options[:nodes].each do |node_options|
|
36
|
-
@nodes << node_clazz.new(options[:host], options[:port], options[:ssl])
|
37
36
|
verify_and_sanitize_options(node_options, options_pattern)
|
37
|
+
@nodes << node_clazz.new(node_options[:host], node_options[:port], node_options[:ssl])
|
38
|
+
end
|
39
|
+
|
40
|
+
# load balancing
|
41
|
+
@load_balancing = options[:load_balancing]
|
42
|
+
@lb_strategy = case load_balancing
|
43
|
+
when :sequence then Orientdb4r::Sequence.new nodes.size
|
44
|
+
when :round_robin then Orientdb4r::RoundRobin.new nodes.size
|
45
|
+
else raise ArgumentError, "unknow load balancing type: #{load_balancing}"
|
38
46
|
end
|
39
47
|
|
40
|
-
|
48
|
+
|
49
|
+
Orientdb4r::logger.info "client initialized with #{@nodes.size} node(s) "
|
50
|
+
Orientdb4r::logger.info "connection_library=#{options[:connection_library]}, load_balancing=#{load_balancing}"
|
41
51
|
end
|
42
52
|
|
43
53
|
|
@@ -50,9 +60,8 @@ module Orientdb4r
|
|
50
60
|
@user = options[:user]
|
51
61
|
@password = options[:password]
|
52
62
|
|
53
|
-
node = a_node
|
54
63
|
begin
|
55
|
-
response =
|
64
|
+
response = call_server(:method => :get, :uri => "connect/#{@database}")
|
56
65
|
rescue
|
57
66
|
@connected = false
|
58
67
|
@server_version = nil
|
@@ -63,7 +72,6 @@ module Orientdb4r
|
|
63
72
|
raise ConnectionError
|
64
73
|
end
|
65
74
|
rslt = process_response response
|
66
|
-
node.post_connect(user, password, response)
|
67
75
|
decorate_classes_with_model(rslt['classes'])
|
68
76
|
|
69
77
|
# try to read server version
|
@@ -77,7 +85,7 @@ module Orientdb4r
|
|
77
85
|
@server_version = DEFAULT_SERVER_VERSION
|
78
86
|
end
|
79
87
|
|
80
|
-
Orientdb4r::logger.debug "successfully connected to server, version=#{server_version}
|
88
|
+
Orientdb4r::logger.debug "successfully connected to server, version=#{server_version}"
|
81
89
|
@connected = true
|
82
90
|
rslt
|
83
91
|
end
|
@@ -87,7 +95,7 @@ module Orientdb4r
|
|
87
95
|
return unless @connected
|
88
96
|
|
89
97
|
begin
|
90
|
-
|
98
|
+
call_server(:method => :get, :uri => 'disconnect')
|
91
99
|
# https://groups.google.com/forum/?fromgroups#!topic/orient-database/5MAMCvFavTc
|
92
100
|
# Disconnect doesn't require you're authenticated.
|
93
101
|
# It always returns 401 because some browsers intercept this and avoid to reuse the same session again.
|
@@ -107,11 +115,8 @@ module Orientdb4r
|
|
107
115
|
options_pattern = { :user => :optional, :password => :optional }
|
108
116
|
verify_options(options, options_pattern)
|
109
117
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
# uses one-off request because of additional authentication to the server
|
114
|
-
response = a_node.oo_request :method => :get, :user => u, :password => p, :uri => 'server'
|
118
|
+
# additional authentication allowed, overriden in 'call_server' if not defined
|
119
|
+
response = call_server :method => :get, :uri => 'server'
|
115
120
|
process_response(response)
|
116
121
|
end
|
117
122
|
|
@@ -125,34 +130,31 @@ module Orientdb4r
|
|
125
130
|
}
|
126
131
|
verify_and_sanitize_options(options, options_pattern)
|
127
132
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
# uses one-off request because of additional authentication to the server
|
132
|
-
response = a_node.oo_request :method => :post, :user => u, :password => p, \
|
133
|
-
:uri => "database/#{options[:database]}/#{options[:type]}"
|
133
|
+
# additional authentication allowed, overriden in 'call_server' if not defined
|
134
|
+
response = call_server_one_off :method => :post, :uri => "database/#{options[:database]}/#{options[:type]}"
|
134
135
|
process_response(response)
|
135
136
|
end
|
136
137
|
|
137
138
|
|
139
|
+
#> curl --user admin:admin http://localhost:2480/database/temp
|
138
140
|
def get_database(options=nil) #:nodoc:
|
139
141
|
raise ArgumentError, 'options have to be a Hash' if !options.nil? and !options.kind_of? Hash
|
140
142
|
|
141
143
|
if options.nil?
|
142
|
-
# use
|
144
|
+
# use database from connect
|
143
145
|
raise ConnectionError, 'client has to be connected if no params' unless connected?
|
144
|
-
options = { :database => database
|
146
|
+
options = { :database => database }
|
145
147
|
end
|
146
148
|
|
147
149
|
options_pattern = { :database => :mandatory, :user => :optional, :password => :optional }
|
148
150
|
verify_options(options, options_pattern)
|
149
151
|
|
150
|
-
|
151
|
-
|
152
|
+
# additional authentication allowed, overriden in 'call_server' if not defined
|
153
|
+
params = {:method => :get, :uri => "database/#{options[:database]}"}
|
154
|
+
params[:user] = options[:user] if options.include? :user
|
155
|
+
params[:password] = options[:password] if options.include? :password
|
152
156
|
|
153
|
-
|
154
|
-
response = a_node.oo_request :method => :get, :user => u, :password => p, \
|
155
|
-
:uri => "database/#{options[:database]}"
|
157
|
+
response = call_server params
|
156
158
|
|
157
159
|
# NotFoundError cannot be raised - no way how to recognize from 401 bad auth
|
158
160
|
process_response(response)
|
@@ -165,12 +167,8 @@ module Orientdb4r
|
|
165
167
|
}
|
166
168
|
verify_and_sanitize_options(options, options_pattern)
|
167
169
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
# uses one-off request because of additional authentication to the server
|
172
|
-
response = a_node.oo_request :method => :delete, :user => u, :password => p, \
|
173
|
-
:uri => "database/#{options[:database]}"
|
170
|
+
# additional authentication allowed, overriden in 'call_server' if not defined
|
171
|
+
response = call_server_one_off :method => :delete, :uri => "database/#{options[:database]}"
|
174
172
|
process_response(response)
|
175
173
|
end
|
176
174
|
|
@@ -186,7 +184,7 @@ module Orientdb4r
|
|
186
184
|
limit = ''
|
187
185
|
limit = "/#{options[:limit]}" if !options.nil? and options.include?(:limit)
|
188
186
|
|
189
|
-
response =
|
187
|
+
response = call_server(:method => :get, :uri => "query/#{@database}/sql/#{CGI::escape(sql)}#{limit}")
|
190
188
|
entries = process_response(response) do
|
191
189
|
raise NotFoundError, 'record not found' if response.body =~ /ORecordNotFoundException/
|
192
190
|
end
|
@@ -200,7 +198,7 @@ module Orientdb4r
|
|
200
198
|
|
201
199
|
def command(sql) #:nodoc:
|
202
200
|
raise ArgumentError, 'command is blank' if blank? sql
|
203
|
-
response =
|
201
|
+
response = call_server(:method => :post, :uri => "command/#{@database}/sql/#{CGI::escape(sql)}")
|
204
202
|
process_response(response)
|
205
203
|
end
|
206
204
|
|
@@ -211,7 +209,7 @@ module Orientdb4r
|
|
211
209
|
raise ArgumentError, "class name is blank" if blank?(name)
|
212
210
|
|
213
211
|
if compare_versions(server_version, '1.1.0') >= 0
|
214
|
-
response =
|
212
|
+
response = call_server(:method => :get, :uri => "class/#{@database}/#{name}")
|
215
213
|
rslt = process_response(response) do
|
216
214
|
raise NotFoundError, 'class not found' if response.body =~ /Invalid class/
|
217
215
|
end
|
@@ -220,7 +218,7 @@ module Orientdb4r
|
|
220
218
|
else
|
221
219
|
# there is bug in REST API [v1.0.0, fixed in r5902], only data are returned
|
222
220
|
# workaround - use metadate delivered by 'connect'
|
223
|
-
response =
|
221
|
+
response = call_server(:method => :get, :uri => "connect/#{@database}")
|
224
222
|
connect_info = process_response(response) do
|
225
223
|
raise NotFoundError, 'class not found' if response.body =~ /Invalid class/
|
226
224
|
end
|
@@ -247,7 +245,7 @@ module Orientdb4r
|
|
247
245
|
# ----------------------------------------------------------------- DOCUMENT
|
248
246
|
|
249
247
|
def create_document(doc) #:nodoc:
|
250
|
-
response =
|
248
|
+
response = call_server(:method => :post, :uri => "document/#{@database}", \
|
251
249
|
:content_type => 'application/json', :data => doc.to_json)
|
252
250
|
srid = process_response(response) do
|
253
251
|
raise DataError, 'validation problem' if response.body =~ /OValidationException/
|
@@ -259,7 +257,7 @@ module Orientdb4r
|
|
259
257
|
|
260
258
|
def get_document(rid) #:nodoc:
|
261
259
|
rid = Rid.new(rid) unless rid.is_a? Rid
|
262
|
-
response =
|
260
|
+
response = call_server(:method => :get, :uri => "document/#{@database}/#{rid.unprefixed}")
|
263
261
|
rslt = process_response(response) do
|
264
262
|
raise NotFoundError, 'record not found' if response.body =~ /ORecordNotFoundException/
|
265
263
|
raise NotFoundError, 'record not found' if response.body =~ /Record with id .* was not found/ # why after delete?
|
@@ -278,7 +276,7 @@ module Orientdb4r
|
|
278
276
|
rid = doc.doc_rid
|
279
277
|
doc.delete '@rid' # will be not updated
|
280
278
|
|
281
|
-
response =
|
279
|
+
response = call_server(:method => :put, :uri => "document/#{@database}/#{rid.unprefixed}", \
|
282
280
|
:content_type => 'application/json', :data => doc.to_json)
|
283
281
|
process_response(response) do
|
284
282
|
raise DataError, 'concurrent modification' if response.body =~ /OConcurrentModificationException/
|
@@ -291,13 +289,14 @@ module Orientdb4r
|
|
291
289
|
def delete_document(rid) #:nodoc:
|
292
290
|
rid = Rid.new(rid) unless rid.is_a? Rid
|
293
291
|
|
294
|
-
response =
|
292
|
+
response = call_server(:method => :delete, :uri => "document/#{@database}/#{rid.unprefixed}")
|
295
293
|
process_response(response) do
|
296
294
|
raise NotFoundError, 'record not found' if response.body =~ /ORecordNotFoundException/
|
297
295
|
end
|
298
296
|
# empty http response
|
299
297
|
end
|
300
298
|
|
299
|
+
|
301
300
|
# ------------------------------------------------------------------ Helpers
|
302
301
|
|
303
302
|
private
|
@@ -321,8 +320,8 @@ module Orientdb4r
|
|
321
320
|
raise OrientdbError, "unexpected return code, code=#{response.code}, body=#{compose_error_message(response)}"
|
322
321
|
end
|
323
322
|
|
324
|
-
content_type = response.headers[:content_type] if
|
325
|
-
content_type = response.headers['Content-Type'] if
|
323
|
+
content_type = response.headers[:content_type] if connection_library == :restclient
|
324
|
+
content_type = response.headers['Content-Type'] if connection_library == :excon
|
326
325
|
content_type ||= 'text/plain'
|
327
326
|
|
328
327
|
rslt = case
|
@@ -7,37 +7,48 @@ module Orientdb4r
|
|
7
7
|
# accessible view REST API and 'excon' library on the client side.
|
8
8
|
class ExconNode < RestNode
|
9
9
|
|
10
|
-
def oo_request(options) #:nodoc:
|
11
|
-
address = "#{url}/#{options[:uri]}"
|
12
|
-
headers = {}
|
13
|
-
headers['Authorization'] = basic_auth_header(options[:user], options[:password]) if options.include?(:user)
|
14
|
-
headers['Cookie'] = "#{SESSION_COOKIE_NAME}=#{session_id}" unless session_id.nil?
|
15
|
-
response = ::Excon.send options[:method].to_sym, address, :headers => headers
|
16
|
-
|
17
|
-
def response.code
|
18
|
-
status
|
19
|
-
end
|
20
|
-
|
21
|
-
response
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
10
|
def request(options) #:nodoc:
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
11
|
+
verify_options(options, {:user => :mandatory, :password => :mandatory, \
|
12
|
+
:uri => :mandatory, :method => :mandatory, :content_type => :optional, :data => :optional})
|
13
|
+
|
14
|
+
opts = options.clone # if not cloned we change original hash map that cannot be used more with load balancing
|
15
|
+
|
16
|
+
# Auth + Cookie + Content-Type
|
17
|
+
opts[:headers] = headers(opts)
|
18
|
+
opts.delete :user
|
19
|
+
opts.delete :password
|
20
|
+
|
21
|
+
opts[:body] = opts[:data] if opts.include? :data # just other naming convention
|
22
|
+
opts.delete :data
|
23
|
+
opts[:path] = opts[:uri] if opts.include? :uri # just other naming convention
|
24
|
+
opts.delete :uri
|
25
|
+
|
26
|
+
was_ok = false
|
27
|
+
begin
|
28
|
+
response = connection.request opts
|
29
|
+
was_ok = (2 == (response.status / 100))
|
30
|
+
|
31
|
+
# store session ID if received to reuse in next request
|
32
|
+
cookies = CGI::Cookie::parse(response.headers['Set-Cookie'])
|
33
|
+
sessid = cookies[SESSION_COOKIE_NAME][0]
|
34
|
+
if session_id != sessid
|
35
|
+
@session_id = sessid
|
36
|
+
Orientdb4r::logger.debug "new session id: #{session_id}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def response.code
|
40
|
+
status
|
41
|
+
end
|
42
|
+
|
43
|
+
rescue Excon::Errors::SocketError
|
44
|
+
raise NodeError
|
45
|
+
end
|
38
46
|
|
39
|
-
|
40
|
-
|
47
|
+
# this is workaround for a strange behavior:
|
48
|
+
# excon delivered magic response status '1' when previous request was not 20x
|
49
|
+
unless was_ok
|
50
|
+
connection.reset
|
51
|
+
Orientdb4r::logger.debug 'response code not 20x -> connection reset'
|
41
52
|
end
|
42
53
|
|
43
54
|
response
|
@@ -45,28 +56,47 @@ module Orientdb4r
|
|
45
56
|
|
46
57
|
|
47
58
|
def post_connect(user, password, http_response) #:nodoc:
|
48
|
-
@basic_auth = basic_auth_header(user, password)
|
49
59
|
|
50
60
|
cookies = CGI::Cookie::parse(http_response.headers['Set-Cookie'])
|
51
61
|
@session_id = cookies[SESSION_COOKIE_NAME][0]
|
52
62
|
|
53
|
-
@connection = Excon.new(url) if @connection.nil?
|
54
63
|
end
|
55
64
|
|
56
65
|
|
57
66
|
def cleanup #:nodoc:
|
58
|
-
|
59
|
-
|
67
|
+
super
|
68
|
+
connection.reset
|
60
69
|
@connection = nil
|
61
70
|
end
|
62
71
|
|
63
72
|
|
73
|
+
# ---------------------------------------------------------- Assistant Stuff
|
74
|
+
|
64
75
|
private
|
65
76
|
|
77
|
+
###
|
78
|
+
# Gets Excon connection.
|
79
|
+
def connection
|
80
|
+
@connection ||= Excon::Connection.new(url)
|
81
|
+
#:read_timeout => self.class.read_timeout,
|
82
|
+
#:write_timeout => self.class.write_timeout,
|
83
|
+
#:connect_timeout => self.class.connect_timeout
|
84
|
+
end
|
85
|
+
|
66
86
|
###
|
67
87
|
# Get request headers prepared with session ID and Basic Auth.
|
68
|
-
def headers
|
69
|
-
{'Authorization' =>
|
88
|
+
def headers(options)
|
89
|
+
rslt = {'Authorization' => basic_auth_header(options[:user], options[:password])}
|
90
|
+
rslt['Cookie'] = "#{SESSION_COOKIE_NAME}=#{session_id}" unless session_id.nil?
|
91
|
+
rslt['Content-Type'] = options[:content_type] if options.include? :content_type
|
92
|
+
rslt
|
93
|
+
end
|
94
|
+
|
95
|
+
###
|
96
|
+
# Gets value of the Basic Auth header.
|
97
|
+
def basic_auth_header(user, password)
|
98
|
+
b64 = Base64.encode64("#{user}:#{password}").delete("\r\n")
|
99
|
+
"Basic #{b64}"
|
70
100
|
end
|
71
101
|
|
72
102
|
end
|
data/lib/orientdb4r/rest/node.rb
CHANGED
@@ -8,7 +8,7 @@ module Orientdb4r
|
|
8
8
|
# Name of cookie that represents a session.
|
9
9
|
SESSION_COOKIE_NAME = 'OSESSIONID'
|
10
10
|
|
11
|
-
attr_reader :ssl
|
11
|
+
attr_reader :ssl
|
12
12
|
|
13
13
|
###
|
14
14
|
# Constructor.
|
@@ -26,36 +26,16 @@ module Orientdb4r
|
|
26
26
|
|
27
27
|
# ----------------------------------------------------------- RestNode Stuff
|
28
28
|
|
29
|
-
###
|
30
|
-
# Initializes a long life connection with credentials and session ID
|
31
|
-
# after successful connect.
|
32
|
-
def post_connect(user, password, http_response)
|
33
|
-
raise NotImplementedError, 'this should be overridden by subclass'
|
34
|
-
end
|
35
|
-
|
36
29
|
|
37
30
|
###
|
38
|
-
# Sends
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
###
|
45
|
-
# Sends a request to the remote server
|
46
|
-
# based on a connection object which is reusable across multiple requests.
|
31
|
+
# Sends a HTTP request to the remote server.
|
32
|
+
# Use following if possible:
|
33
|
+
# * session_id
|
34
|
+
# * Keep-Alive (if possible)
|
47
35
|
def request(options)
|
48
36
|
raise NotImplementedError, 'this should be overridden by subclass'
|
49
37
|
end
|
50
38
|
|
51
|
-
|
52
|
-
###
|
53
|
-
# Gets value of the Basic Auth header.
|
54
|
-
def basic_auth_header(user, password)
|
55
|
-
b64 = Base64.encode64("#{user}:#{password}").delete("\r\n")
|
56
|
-
"Basic #{b64}"
|
57
|
-
end
|
58
|
-
|
59
39
|
end
|
60
40
|
|
61
41
|
end
|
@@ -4,35 +4,41 @@ module Orientdb4r
|
|
4
4
|
|
5
5
|
###
|
6
6
|
# This class represents a single sever/node in the Distributed Multi-Master Architecture
|
7
|
-
# accessible
|
7
|
+
# accessible via REST API and 'rest-client' library on the client side.
|
8
8
|
class RestClientNode < RestNode
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
options.delete :uri
|
14
|
-
response = ::RestClient::Request.new(options).execute
|
15
|
-
rescue ::RestClient::Exception => e
|
16
|
-
response = transform_error2_response(e)
|
17
|
-
end
|
10
|
+
def request(options) #:nodoc:
|
11
|
+
verify_options(options, {:user => :mandatory, :password => :mandatory, \
|
12
|
+
:uri => :mandatory, :method => :mandatory, :content_type => :optional, :data => :optional})
|
18
13
|
|
19
|
-
|
20
|
-
end
|
14
|
+
opts = options.clone # if not cloned we change original hash map that cannot be used more with load balancing
|
21
15
|
|
16
|
+
# URL
|
17
|
+
opts[:url] = "#{url}/#{opts[:uri]}"
|
18
|
+
opts.delete :uri
|
22
19
|
|
23
|
-
|
24
|
-
|
20
|
+
# data
|
21
|
+
data = opts.delete :data
|
22
|
+
data = '' if data.nil? and :post == opts[:method] # POST has to have data
|
23
|
+
opts[:payload] = data unless data.nil?
|
24
|
+
|
25
|
+
# headers
|
26
|
+
opts[:cookies] = { SESSION_COOKIE_NAME => session_id} unless session_id.nil?
|
25
27
|
|
26
|
-
data = options[:data]
|
27
|
-
options.delete :data
|
28
|
-
data = '' if data.nil? and :post == options[:method] # POST has to have data
|
29
28
|
begin
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
29
|
+
response = ::RestClient::Request.new(opts).execute
|
30
|
+
|
31
|
+
# store session ID if received to reuse in next request
|
32
|
+
sessid = response.cookies[SESSION_COOKIE_NAME]
|
33
|
+
if session_id != sessid
|
34
|
+
@session_id = sessid
|
35
|
+
Orientdb4r::logger.debug "new session id: #{session_id}"
|
35
36
|
end
|
37
|
+
|
38
|
+
rescue Errno::ECONNREFUSED
|
39
|
+
raise NodeError
|
40
|
+
rescue ::RestClient::ServerBrokeConnection
|
41
|
+
raise NodeError
|
36
42
|
rescue ::RestClient::Exception => e
|
37
43
|
response = transform_error2_response(e)
|
38
44
|
end
|
@@ -41,23 +47,6 @@ module Orientdb4r
|
|
41
47
|
end
|
42
48
|
|
43
49
|
|
44
|
-
def post_connect(user, password, http_response) #:nodoc:
|
45
|
-
@basic_auth = basic_auth_header(user, password)
|
46
|
-
@session_id = http_response.cookies[SESSION_COOKIE_NAME]
|
47
|
-
|
48
|
-
@resource = ::RestClient::Resource.new(url, \
|
49
|
-
:user => user, :password => password, \
|
50
|
-
:cookies => { SESSION_COOKIE_NAME => session_id})
|
51
|
-
end
|
52
|
-
|
53
|
-
|
54
|
-
def cleanup #:nodoc:
|
55
|
-
@session_id = nil
|
56
|
-
@basic_auth = nil
|
57
|
-
@resource = nil
|
58
|
-
end
|
59
|
-
|
60
|
-
|
61
50
|
private
|
62
51
|
|
63
52
|
###
|
data/lib/orientdb4r/utils.rb
CHANGED
data/lib/orientdb4r/version.rb
CHANGED
@@ -2,6 +2,7 @@ module Orientdb4r
|
|
2
2
|
|
3
3
|
# Version history.
|
4
4
|
VERSION_HISTORY = [
|
5
|
+
['0.3.0', '2012-08-01', "Added support for cluster of distributed servers + load balancing"],
|
5
6
|
['0.2.10', '2012-07-21', "Experimental support for Excon HTTP library with Keep-Alive connection"],
|
6
7
|
['0.2.9', '2012-07-18', "Added feature Client#delete_database, New class Rid"],
|
7
8
|
['0.2.8', '2012-07-16', "New exception handling, added feature Client#create_class(:properties)"],
|
data/lib/orientdb4r.rb
CHANGED
@@ -19,6 +19,8 @@ module Orientdb4r
|
|
19
19
|
autoload :RestNode, 'orientdb4r/rest/node'
|
20
20
|
autoload :RestClientNode, 'orientdb4r/rest/restclient_node'
|
21
21
|
autoload :ExconNode, 'orientdb4r/rest/excon_node'
|
22
|
+
autoload :Sequence, 'orientdb4r/load_balancing'
|
23
|
+
autoload :RoundRobin, 'orientdb4r/load_balancing'
|
22
24
|
|
23
25
|
|
24
26
|
class << self
|
@@ -44,8 +46,15 @@ module Orientdb4r
|
|
44
46
|
RestClient.proxy = url
|
45
47
|
end
|
46
48
|
|
49
|
+
###
|
50
|
+
# Logger used for logging output
|
47
51
|
attr_accessor :logger
|
48
52
|
|
53
|
+
###
|
54
|
+
# Predefined connection library.
|
55
|
+
# Can be overriden by option in client initialization.
|
56
|
+
attr_accessor :connection_library
|
57
|
+
|
49
58
|
end
|
50
59
|
|
51
60
|
|
@@ -76,6 +85,13 @@ module Orientdb4r
|
|
76
85
|
# mismatched types or incorrect cardinality.
|
77
86
|
class DataError < OrientdbError; end
|
78
87
|
|
88
|
+
# ---------------------------------------------------------- System Exceptions
|
89
|
+
|
90
|
+
###
|
91
|
+
# This exception represents a fatal failure which meens that the node is not accessible more.
|
92
|
+
# e.g. connection broken pipe
|
93
|
+
class NodeError < OrientdbError; end
|
94
|
+
|
79
95
|
end
|
80
96
|
|
81
97
|
|
@@ -83,6 +99,10 @@ end
|
|
83
99
|
Orientdb4r::logger = Logger.new(STDOUT)
|
84
100
|
Orientdb4r::logger.level = Logger::INFO
|
85
101
|
|
102
|
+
# Default connection library
|
103
|
+
Orientdb4r::connection_library = :restclient
|
104
|
+
#Orientdb4r::connection_library = :excon
|
105
|
+
|
86
106
|
Orientdb4r::logger.info \
|
87
107
|
"Orientdb4r #{Orientdb4r::VERSION}, running on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
|
88
108
|
|
data/test/test_database.rb
CHANGED
@@ -6,6 +6,9 @@ require 'orientdb4r'
|
|
6
6
|
# * CONNECT
|
7
7
|
# * DISCONNECT
|
8
8
|
# * CREATE DATABASE
|
9
|
+
# * GET DATABASE
|
10
|
+
# * DELETE DATABASE
|
11
|
+
# * SERVER info
|
9
12
|
class TestDatabase < Test::Unit::TestCase
|
10
13
|
|
11
14
|
Orientdb4r::logger.level = Logger::DEBUG
|
@@ -23,13 +26,9 @@ class TestDatabase < Test::Unit::TestCase
|
|
23
26
|
assert rslt.size > 0
|
24
27
|
assert rslt.include? 'classes'
|
25
28
|
|
26
|
-
#assert_equal 'localhost', @client.host # TODO moved to Node; mock?
|
27
|
-
#assert_equal 2480, @client.port
|
28
|
-
#assert_equal false, @client.ssl
|
29
29
|
assert_equal 'admin', @client.user
|
30
30
|
assert_equal 'admin', @client.password
|
31
31
|
assert_equal 'temp', @client.database
|
32
|
-
#assert_not_nil @client.session_id
|
33
32
|
assert_not_nil @client.server_version
|
34
33
|
|
35
34
|
# connection refused
|
@@ -63,13 +62,9 @@ class TestDatabase < Test::Unit::TestCase
|
|
63
62
|
# unable to query after disconnect
|
64
63
|
assert_raise Orientdb4r::ConnectionError do @client.query 'SELECT FROM OUser'; end
|
65
64
|
|
66
|
-
#assert_equal 'localhost', @client.host # TODO moved to Node; mock?
|
67
|
-
#assert_equal 2480, @client.port
|
68
|
-
#assert_equal false, @client.ssl
|
69
65
|
assert_nil @client.user
|
70
66
|
assert_nil @client.password
|
71
67
|
assert_nil @client.database
|
72
|
-
#assert_nil @client.session_id
|
73
68
|
assert_nil @client.server_version
|
74
69
|
end
|
75
70
|
|
@@ -181,4 +176,21 @@ class TestDatabase < Test::Unit::TestCase
|
|
181
176
|
assert_raise Orientdb4r::ConnectionError do @client.delete_document('#1:0'); end
|
182
177
|
end
|
183
178
|
|
179
|
+
|
180
|
+
###
|
181
|
+
# Tests using of session ID.
|
182
|
+
def test_session_id
|
183
|
+
client = Orientdb4r.client :instance => :new
|
184
|
+
assert_nil client.nodes[0].session_id
|
185
|
+
client.connect :database => 'temp', :user => 'admin', :password => 'admin'
|
186
|
+
session_id = client.nodes[0].session_id
|
187
|
+
assert_not_nil session_id
|
188
|
+
client.query 'SELECT count(*) FROM OUser'
|
189
|
+
assert_equal session_id, client.nodes[0].session_id
|
190
|
+
client.get_class 'OUser'
|
191
|
+
assert_equal session_id, client.nodes[0].session_id
|
192
|
+
client.disconnect
|
193
|
+
assert_nil client.nodes[0].session_id
|
194
|
+
end
|
195
|
+
|
184
196
|
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'orientdb4r'
|
3
|
+
|
4
|
+
###
|
5
|
+
# This class tests communication with OrientDB cluster and load balancing.
|
6
|
+
class TestDatabase < Test::Unit::TestCase
|
7
|
+
|
8
|
+
Orientdb4r::logger.level = Logger::DEBUG
|
9
|
+
|
10
|
+
|
11
|
+
###
|
12
|
+
# Test inintialization of single node.
|
13
|
+
def test_one_node_initialization
|
14
|
+
client = Orientdb4r.client :instance => :new
|
15
|
+
assert_not_nil client.nodes
|
16
|
+
assert_instance_of Array, client.nodes
|
17
|
+
assert_equal 1, client.nodes.size
|
18
|
+
assert_equal 2480, client.nodes[0].port
|
19
|
+
assert_equal false, client.nodes[0].ssl
|
20
|
+
end
|
21
|
+
|
22
|
+
###
|
23
|
+
# Test inintialization of more nodes.
|
24
|
+
def test_nodes_initialization
|
25
|
+
client = Orientdb4r.client :nodes => [{}, {:port => 2481}], :instance => :new
|
26
|
+
assert_not_nil client.nodes
|
27
|
+
assert_instance_of Array, client.nodes
|
28
|
+
assert_equal 2, client.nodes.size
|
29
|
+
assert_equal 2480, client.nodes[0].port
|
30
|
+
assert_equal 2481, client.nodes[1].port
|
31
|
+
assert_equal false, client.nodes[0].ssl
|
32
|
+
assert_equal false, client.nodes[1].ssl
|
33
|
+
end
|
34
|
+
|
35
|
+
###
|
36
|
+
# Test default Sequence strategy.
|
37
|
+
def test_sequence_loadbalancing
|
38
|
+
client = Orientdb4r.client :nodes => [{}, {:port => 2481}], :instance => :new
|
39
|
+
lb_strategy = client.lb_strategy
|
40
|
+
assert_not_nil lb_strategy
|
41
|
+
assert_instance_of Orientdb4r::Sequence, lb_strategy
|
42
|
+
assert_equal 0, lb_strategy.node_index
|
43
|
+
assert_equal 0, lb_strategy.node_index
|
44
|
+
assert_equal client.nodes[0], client.nodes[client.lb_strategy.node_index]
|
45
|
+
assert_equal client.nodes[0], client.nodes[client.lb_strategy.node_index]
|
46
|
+
end
|
47
|
+
|
48
|
+
###
|
49
|
+
# Test RoundRobin strategy.
|
50
|
+
def test_roundrobin_loadbalancing
|
51
|
+
client = Orientdb4r.client :nodes => [{}, {:port => 2481}], :load_balancing => :round_robin, :instance => :new
|
52
|
+
lb_strategy = client.lb_strategy
|
53
|
+
assert_not_nil lb_strategy
|
54
|
+
assert_instance_of Orientdb4r::RoundRobin, lb_strategy
|
55
|
+
assert_equal 0, lb_strategy.node_index
|
56
|
+
assert_equal 1, lb_strategy.node_index
|
57
|
+
assert_equal 0, lb_strategy.node_index
|
58
|
+
assert_equal client.nodes[1], client.nodes[client.lb_strategy.node_index]
|
59
|
+
assert_equal client.nodes[0], client.nodes[client.lb_strategy.node_index]
|
60
|
+
assert_equal client.nodes[1], client.nodes[client.lb_strategy.node_index]
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_load_balancing_in_problems
|
64
|
+
# invalid port
|
65
|
+
client = Orientdb4r.client :port => 9999, :instance => :new
|
66
|
+
assert_raise Orientdb4r::ConnectionError do
|
67
|
+
client.connect :database => 'temp', :user => 'admin', :password => 'admin'
|
68
|
+
end
|
69
|
+
# opened port, but not REST
|
70
|
+
client = Orientdb4r.client :port => 2424, :instance => :new
|
71
|
+
assert_raise Orientdb4r::ConnectionError do
|
72
|
+
client.connect :database => 'temp', :user => 'admin', :password => 'admin'
|
73
|
+
end
|
74
|
+
|
75
|
+
# invalid ports - both
|
76
|
+
client = Orientdb4r.client :nodes => [{:port => 9998}, {:port => 9999}], :instance => :new
|
77
|
+
begin
|
78
|
+
client.connect :database => 'temp', :user => 'admin', :password => 'admin'
|
79
|
+
assert_equal 0, 1, "Orientdb4r::ConnectionError EXPECTED"
|
80
|
+
rescue Orientdb4r::ConnectionError => e
|
81
|
+
assert_equal 'all nodes failed to communicate with server!', e.message
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
# more nodes
|
86
|
+
|
87
|
+
# first node bad, second must work (sequence)
|
88
|
+
client = Orientdb4r.client :nodes => [{:port => 2481}, {}], :instance => :new
|
89
|
+
assert_nothing_thrown do # there has to be ERROR in log
|
90
|
+
client.connect :database => 'temp', :user => 'admin', :password => 'admin'
|
91
|
+
end
|
92
|
+
assert_equal 1, client.lb_strategy.bad_nodes.size
|
93
|
+
assert client.lb_strategy.bad_nodes.include? 0
|
94
|
+
|
95
|
+
# second node bad => second call has to be realized by first one (round robin)
|
96
|
+
client = Orientdb4r.client :nodes => [{}, {:port => 2481}], :load_balancing => :round_robin, :instance => :new
|
97
|
+
assert client.lb_strategy.bad_nodes.empty?
|
98
|
+
client.connect :database => 'temp', :user => 'admin', :password => 'admin'
|
99
|
+
assert client.lb_strategy.bad_nodes.empty?
|
100
|
+
client.query 'SELECT FROM OUser'
|
101
|
+
assert_equal 1, client.lb_strategy.bad_nodes.size
|
102
|
+
assert client.lb_strategy.bad_nodes.include? 1
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
data/test/test_utils.rb
CHANGED
@@ -25,6 +25,14 @@ class TestDmo < Test::Unit::TestCase
|
|
25
25
|
assert_equal 2, options.size
|
26
26
|
assert_equal 'X', options[:a]
|
27
27
|
assert_equal 'B', options[:b]
|
28
|
+
|
29
|
+
# :optional cannot be set as default value
|
30
|
+
opt_pattern = {:a => :optional, :b => 'B'}
|
31
|
+
options = {}
|
32
|
+
verify_and_sanitize_options(options, opt_pattern)
|
33
|
+
assert_equal 1, options.size
|
34
|
+
assert !options.include?(:a)
|
35
|
+
assert_equal 'B', options[:b]
|
28
36
|
end
|
29
37
|
|
30
38
|
def test_compare_versions
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: orientdb4r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rest-client
|
@@ -53,6 +53,7 @@ files:
|
|
53
53
|
- lib/orientdb4r.rb
|
54
54
|
- lib/orientdb4r/chained_error.rb
|
55
55
|
- lib/orientdb4r/client.rb
|
56
|
+
- lib/orientdb4r/load_balancing.rb
|
56
57
|
- lib/orientdb4r/node.rb
|
57
58
|
- lib/orientdb4r/rest/client.rb
|
58
59
|
- lib/orientdb4r/rest/excon_node.rb
|
@@ -66,6 +67,7 @@ files:
|
|
66
67
|
- test/readme_sample.rb
|
67
68
|
- test/test_database.rb
|
68
69
|
- test/test_ddo.rb
|
70
|
+
- test/test_distributed.rb
|
69
71
|
- test/test_dmo.rb
|
70
72
|
- test/test_document_crud.rb
|
71
73
|
- test/test_utils.rb
|
@@ -98,6 +100,7 @@ test_files:
|
|
98
100
|
- test/readme_sample.rb
|
99
101
|
- test/test_database.rb
|
100
102
|
- test/test_ddo.rb
|
103
|
+
- test/test_distributed.rb
|
101
104
|
- test/test_dmo.rb
|
102
105
|
- test/test_document_crud.rb
|
103
106
|
- test/test_utils.rb
|