orientdb4r 0.2.10 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|