orientdb4r 0.3.0 → 0.3.1

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/changelog.txt CHANGED
@@ -1,3 +1,7 @@
1
+ 0.3.1 2012-08-27
2
+ - Timeout for reuse of dirty (already failed) nodes in load balancing
3
+ - Bug Fix #14, #15
4
+
1
5
  0.3.0 2012-08-01
2
6
  - introduced support for cluster of distributed servers
3
7
  - initial strategies for load balancing: sequence, round robin
@@ -20,7 +20,7 @@ class FlatClassPerf < FStudy::Case
20
20
  client.command 'DELETE FROM User'
21
21
  end
22
22
  def data
23
- 1.upto(10000) do |i|
23
+ 1.upto(100000) do |i|
24
24
  Orientdb4r::logger.info "...done: #{i}" if 0 == (i % 1000)
25
25
  first_name = dg.word
26
26
  surname = dg.word
@@ -9,10 +9,23 @@ module Orientdb4r
9
9
  # # Regexp to validate format of providet version.
10
10
  SERVER_VERSION_PATTERN = /^\d+\.\d+\.\d+/
11
11
 
12
+ # connection parameters
12
13
  attr_reader :user, :password, :database
14
+ # version loaded from server
13
15
  attr_reader :server_version
14
- attr_reader :nodes, :connection_library
15
- attr_reader :load_balancing, :lb_strategy
16
+ # type of connection library [:restclient, :excon]
17
+ attr_reader :connection_library
18
+ # type of load balancing [:sequence, :round_robin]
19
+ attr_reader :load_balancing
20
+ # proxy for remote communication
21
+ attr_reader :proxy
22
+
23
+ # intern structures
24
+
25
+ # nodes responsible for communication with a server
26
+ attr_reader :nodes
27
+ # object implementing a LB strategy
28
+ attr_reader :lb_strategy
16
29
 
17
30
  ###
18
31
  # Constructor.
@@ -282,6 +295,7 @@ module Orientdb4r
282
295
 
283
296
  rescue NodeError => e
284
297
  Orientdb4r::logger.error "node error, index=#{idx}, msg=#{e.message}, #{node}"
298
+ node.cleanup
285
299
  lb_strategy.bad_one idx
286
300
  idx = lb_strategy.node_index
287
301
  end
@@ -4,7 +4,7 @@ module Orientdb4r
4
4
  # Base class for implementation of load balancing strategy.
5
5
  class LBStrategy
6
6
 
7
- # If occures a new try to communicate from node can be tested.
7
+ # If occures a new try to communicate from node can be tested [s].
8
8
  RECOVERY_TIMEOUT = 30
9
9
 
10
10
  attr_reader :nodes_count, :bad_nodes
@@ -39,17 +39,39 @@ module Orientdb4r
39
39
 
40
40
  protected
41
41
 
42
+ ###
43
+ # Tries to find a new node if the given failed.
44
+ # Returns <i>nil</i> if no one found
42
45
  def search_next_good(bad_idx)
43
46
  Orientdb4r::logger.warn "identified bad node, idx=#{bad_idx}, age=#{Time.now - @bad_nodes[bad_idx]} [s]"
47
+
48
+ # alternative nodes of not found a good one
49
+ timeout_candidate = nil
50
+
51
+ # first round - try to find a first good one
44
52
  1.upto(nodes_count) do |i|
45
53
  candidate = (i + bad_idx) % nodes_count
46
- unless @bad_nodes.include? candidate
54
+
55
+ if @bad_nodes.include? candidate
56
+ failure_time = @bad_nodes[candidate]
57
+ now = Time.now
58
+ # timeout candidate
59
+ if (now - failure_time) > RECOVERY_TIMEOUT
60
+ timeout_candidate = candidate
61
+ Orientdb4r::logger.debug "node timeout recovery, idx=#{candidate}"
62
+ good_one(candidate)
63
+ end
64
+ else
47
65
  Orientdb4r::logger.debug "found good node, idx=#{candidate}"
48
66
  return candidate
49
67
  end
50
68
  end
51
69
 
52
- # TODO implement search based on LRU for next round
70
+ # no good index found -> try timeouted one
71
+ unless timeout_candidate.nil?
72
+ Orientdb4r::logger.debug "good node not found, delivering timeouted one, idx=#{timeout_candidate}"
73
+ return timeout_candidate
74
+ end
53
75
 
54
76
  Orientdb4r::logger.error 'no nodes more, all invalid'
55
77
  nil
@@ -12,18 +12,22 @@ module Orientdb4r
12
12
 
13
13
  def initialize(options) #:nodoc:
14
14
  super()
15
- options_pattern = { :host => 'localhost', :port => 2480, :ssl => false,
16
- :nodes => :optional, :load_balancing => :sequence,
17
- :connection_library => Orientdb4r::connection_library}
15
+ options_pattern = {
16
+ :host => 'localhost', :port => 2480, :ssl => false,
17
+ :nodes => :optional,
18
+ :connection_library => :restclient,
19
+ :load_balancing => :sequence,
20
+ :proxy => :optional
21
+ }
18
22
  verify_and_sanitize_options(options, options_pattern)
19
23
 
20
24
  # fake nodes for single server
21
25
  if options[:nodes].nil?
22
26
  options[:nodes] = [{:host => options[:host], :port => options[:port], :ssl => options[:ssl]}]
23
27
  end
24
- raise ArgumentError, 'nodes has to be arrray' unless options[:nodes].is_a? Array
28
+ raise ArgumentError, 'nodes has to be array' unless options[:nodes].is_a? Array
25
29
 
26
- # instantiate nodes accroding to HTTP library
30
+ # instantiate nodes according to HTTP library
27
31
  @connection_library = options[:connection_library]
28
32
  node_clazz = case connection_library
29
33
  when :restclient then Orientdb4r::RestClientNode
@@ -45,6 +49,14 @@ module Orientdb4r
45
49
  else raise ArgumentError, "unknow load balancing type: #{load_balancing}"
46
50
  end
47
51
 
52
+ # proxy
53
+ @proxy = options[:proxy]
54
+ unless proxy.nil?
55
+ case connection_library
56
+ when :restclient then ::RestClient.proxy = proxy
57
+ when :excon then nodes.each { |node| node.proxy = proxy }
58
+ end
59
+ end
48
60
 
49
61
  Orientdb4r::logger.info "client initialized with #{@nodes.size} node(s) "
50
62
  Orientdb4r::logger.info "connection_library=#{options[:connection_library]}, load_balancing=#{load_balancing}"
@@ -7,6 +7,8 @@ module Orientdb4r
7
7
  # accessible view REST API and 'excon' library on the client side.
8
8
  class ExconNode < RestNode
9
9
 
10
+ attr_accessor :proxy
11
+
10
12
  def request(options) #:nodoc:
11
13
  verify_options(options, {:user => :mandatory, :password => :mandatory, \
12
14
  :uri => :mandatory, :method => :mandatory, :content_type => :optional, :data => :optional})
@@ -77,10 +79,15 @@ module Orientdb4r
77
79
  ###
78
80
  # Gets Excon connection.
79
81
  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
82
+ return @connection unless @connection.nil?
83
+
84
+ options = {}
85
+ options[:proxy] = proxy unless proxy.nil?
86
+
87
+ @connection ||= Excon::Connection.new(url, options)
88
+ #:read_timeout => self.class.read_timeout,
89
+ #:write_timeout => self.class.write_timeout,
90
+ #:connect_timeout => self.class.connect_timeout
84
91
  end
85
92
 
86
93
  ###
@@ -2,6 +2,7 @@ module Orientdb4r
2
2
 
3
3
  # Version history.
4
4
  VERSION_HISTORY = [
5
+ ['0.3.1', '2012-08-27', "Timeout for reuse of dirty nodes in load balancing; BF #14, BF #15"],
5
6
  ['0.3.0', '2012-08-01', "Added support for cluster of distributed servers + load balancing"],
6
7
  ['0.2.10', '2012-07-21', "Experimental support for Excon HTTP library with Keep-Alive connection"],
7
8
  ['0.2.9', '2012-07-18', "Added feature Client#delete_database, New class Rid"],
data/lib/orientdb4r.rb CHANGED
@@ -40,21 +40,10 @@ module Orientdb4r
40
40
  }
41
41
  end
42
42
 
43
- ###
44
- # All calls to REST API will use the proxy specified here.
45
- def rest_proxy(url)
46
- RestClient.proxy = url
47
- end
48
-
49
43
  ###
50
44
  # Logger used for logging output
51
45
  attr_accessor :logger
52
46
 
53
- ###
54
- # Predefined connection library.
55
- # Can be overriden by option in client initialization.
56
- attr_accessor :connection_library
57
-
58
47
  end
59
48
 
60
49
 
@@ -99,10 +88,6 @@ end
99
88
  Orientdb4r::logger = Logger.new(STDOUT)
100
89
  Orientdb4r::logger.level = Logger::INFO
101
90
 
102
- # Default connection library
103
- Orientdb4r::connection_library = :restclient
104
- #Orientdb4r::connection_library = :excon
105
-
106
91
  Orientdb4r::logger.info \
107
92
  "Orientdb4r #{Orientdb4r::VERSION}, running on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
108
93
 
@@ -0,0 +1,86 @@
1
+ require 'test/unit'
2
+ require 'orientdb4r'
3
+
4
+ ###
5
+ # This class tests communication with OrientDB cluster and load balancing.
6
+ class TestClient < Test::Unit::TestCase
7
+
8
+ Orientdb4r::logger.level = Logger::DEBUG
9
+
10
+ PROXY_URL = 'http://bad.domain.com'
11
+
12
+
13
+ ###
14
+ # Test inintialization of single node.
15
+ def test_one_node_initialization
16
+ client = Orientdb4r.client :instance => :new
17
+ assert_not_nil client.nodes
18
+ assert_instance_of Array, client.nodes
19
+ assert_equal 1, client.nodes.size
20
+ assert_equal 2480, client.nodes[0].port
21
+ assert_equal false, client.nodes[0].ssl
22
+ end
23
+
24
+ ###
25
+ # Test inintialization of more nodes.
26
+ def test_nodes_initialization
27
+ client = Orientdb4r.client :nodes => [{}, {:port => 2481}], :instance => :new
28
+ assert_not_nil client.nodes
29
+ assert_instance_of Array, client.nodes
30
+ assert_equal 2, client.nodes.size
31
+ assert_equal 2480, client.nodes[0].port
32
+ assert_equal 2481, client.nodes[1].port
33
+ assert_equal false, client.nodes[0].ssl
34
+ assert_equal false, client.nodes[1].ssl
35
+
36
+ client = Orientdb4r.client :nodes => [{}, {:port => 2481}, {:port => 2482}], :instance => :new
37
+ assert_equal 3, client.nodes.size
38
+ end
39
+
40
+ ###
41
+ # Tests initialization of connection library.
42
+ def test_connection_library
43
+ # restclient
44
+ client = Orientdb4r.client :instance => :new
45
+ assert_equal :restclient, client.connection_library
46
+ assert_instance_of Orientdb4r::RestClientNode, client.nodes[0]
47
+
48
+ # excon
49
+ client = Orientdb4r.client :connection_library => :excon, :instance => :new
50
+ assert_equal :excon, client.connection_library
51
+ assert_instance_of Orientdb4r::ExconNode, client.nodes[0]
52
+ end
53
+
54
+ ###
55
+ # Tests initialization of proxy.
56
+ def test_proxy
57
+ # no proxy - resclient
58
+ client = Orientdb4r.client :instance => :new
59
+ assert_nil client.proxy
60
+ assert_nil RestClient.proxy
61
+
62
+ # proxy - restclient
63
+ client = Orientdb4r.client :proxy => PROXY_URL, :instance => :new
64
+ assert_equal PROXY_URL, client.proxy
65
+ assert_equal PROXY_URL, RestClient.proxy
66
+ assert_raise Orientdb4r::ConnectionError do
67
+ client.connect :database => 'temp', :user => 'admin', :password => 'admin'
68
+ end
69
+ RestClient.proxy = nil # restore no setting
70
+
71
+ # no proxy - excon
72
+ client = Orientdb4r.client :connection_library => :excon, :instance => :new
73
+ assert_nil client.proxy
74
+ assert_nil client.nodes[0].proxy
75
+
76
+ # proxy - restclient
77
+ client = Orientdb4r.client :connection_library => :excon, :proxy => PROXY_URL, :instance => :new
78
+ assert_equal PROXY_URL, client.proxy
79
+ assert_equal PROXY_URL, client.nodes[0].proxy
80
+ assert_raise Orientdb4r::ConnectionError do
81
+ client.connect :database => 'temp', :user => 'admin', :password => 'admin'
82
+ end
83
+ end
84
+
85
+
86
+ end
@@ -3,39 +3,16 @@ require 'orientdb4r'
3
3
 
4
4
  ###
5
5
  # This class tests communication with OrientDB cluster and load balancing.
6
- class TestDatabase < Test::Unit::TestCase
6
+ class TestLoadBalancing < Test::Unit::TestCase
7
7
 
8
8
  Orientdb4r::logger.level = Logger::DEBUG
9
9
 
10
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
11
  ###
36
12
  # Test default Sequence strategy.
37
13
  def test_sequence_loadbalancing
38
14
  client = Orientdb4r.client :nodes => [{}, {:port => 2481}], :instance => :new
15
+ assert_equal :sequence, client.load_balancing
39
16
  lb_strategy = client.lb_strategy
40
17
  assert_not_nil lb_strategy
41
18
  assert_instance_of Orientdb4r::Sequence, lb_strategy
@@ -49,6 +26,7 @@ class TestDatabase < Test::Unit::TestCase
49
26
  # Test RoundRobin strategy.
50
27
  def test_roundrobin_loadbalancing
51
28
  client = Orientdb4r.client :nodes => [{}, {:port => 2481}], :load_balancing => :round_robin, :instance => :new
29
+ assert_equal :round_robin, client.load_balancing
52
30
  lb_strategy = client.lb_strategy
53
31
  assert_not_nil lb_strategy
54
32
  assert_instance_of Orientdb4r::RoundRobin, lb_strategy
@@ -60,6 +38,8 @@ class TestDatabase < Test::Unit::TestCase
60
38
  assert_equal client.nodes[1], client.nodes[client.lb_strategy.node_index]
61
39
  end
62
40
 
41
+ ###
42
+ # Tests variant reasons for LB failure.
63
43
  def test_load_balancing_in_problems
64
44
  # invalid port
65
45
  client = Orientdb4r.client :port => 9999, :instance => :new
data/test/test_utils.rb CHANGED
@@ -3,7 +3,7 @@ require 'orientdb4r'
3
3
 
4
4
  ###
5
5
  # This class tests Utils methods.
6
- class TestDmo < Test::Unit::TestCase
6
+ class TestUtils < Test::Unit::TestCase
7
7
  include Orientdb4r::Utils
8
8
 
9
9
  def test_verify_options
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.3.0
4
+ version: 0.3.1
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-08-01 00:00:00.000000000 Z
12
+ date: 2012-08-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rest-client
@@ -65,11 +65,12 @@ files:
65
65
  - lib/orientdb4r/version.rb
66
66
  - orientdb4r.gemspec
67
67
  - test/readme_sample.rb
68
+ - test/test_client.rb
68
69
  - test/test_database.rb
69
70
  - test/test_ddo.rb
70
- - test/test_distributed.rb
71
71
  - test/test_dmo.rb
72
72
  - test/test_document_crud.rb
73
+ - test/test_loadbalancing.rb
73
74
  - test/test_utils.rb
74
75
  homepage: http://github.com/veny/orientdb4r
75
76
  licenses: []
@@ -92,15 +93,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
93
  version: 1.3.1
93
94
  requirements: []
94
95
  rubyforge_project:
95
- rubygems_version: 1.8.19
96
+ rubygems_version: 1.8.23
96
97
  signing_key:
97
98
  specification_version: 3
98
99
  summary: Ruby binding for Orient DB.
99
100
  test_files:
100
101
  - test/readme_sample.rb
102
+ - test/test_client.rb
101
103
  - test/test_database.rb
102
104
  - test/test_ddo.rb
103
- - test/test_distributed.rb
104
105
  - test/test_dmo.rb
105
106
  - test/test_document_crud.rb
107
+ - test/test_loadbalancing.rb
106
108
  - test/test_utils.rb