odba 1.1.8 → 1.2.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.
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env ruby
2
- # encoding: utf-8
2
+
3
3
  # ODBA::CacheEntry -- odba -- 09.01.2012 -- mhatakeyama@ywesee.com
4
4
  # ODBA::CacheEntry -- odba -- 29.04.2004 -- hwyss@ywesee.com mwalder@ywesee.com
5
5
 
6
6
  module ODBA
7
- class CacheEntry # :nodoc: all
7
+ class CacheEntry # :nodoc: all
8
8
  @@id_table = {}
9
9
  @@finalizer = proc { |object_id|
10
- if(odba_id = @@id_table.delete(object_id))
10
+ if (odba_id = @@id_table.delete(object_id))
11
11
  ODBA.cache.invalidate odba_id
12
12
  end
13
13
  }
14
- attr_accessor :last_access
15
- attr_reader :accessed_by, :odba_id, :odba_object_id
14
+ attr_accessor :last_access
15
+ attr_reader :accessed_by, :odba_id, :odba_object_id
16
16
  def initialize(obj)
17
17
  @odba_id = obj.odba_id
18
18
  update obj
@@ -20,6 +20,7 @@ module ODBA
20
20
  @odba_observers = obj.odba_observers
21
21
  @cache_entry_mutex = Mutex.new
22
22
  end
23
+
23
24
  def update obj
24
25
  @last_access = Time.now
25
26
  @odba_object = obj
@@ -32,59 +33,68 @@ module ODBA
32
33
  ObjectSpace.define_finalizer obj, @@finalizer
33
34
  end
34
35
  end
36
+
35
37
  def object_id2ref(object_id, odba_id)
36
38
  if (obj = ObjectSpace._id2ref(object_id)) \
37
39
  && obj.is_a?(Persistable) && !obj.odba_unsaved? \
38
40
  && obj.odba_id == odba_id
39
41
  obj
40
42
  end
41
- rescue RangeError, NoMethodError => e
43
+ rescue RangeError, NoMethodError
42
44
  nil
43
45
  end
46
+
44
47
  def odba_id2ref(odba_id)
45
48
  odba_id && ODBA.cache.include?(odba_id) && ODBA.cache.fetch(odba_id)
46
49
  end
47
- def odba_add_reference(object)
50
+
51
+ def odba_add_reference(object)
48
52
  return unless object.respond_to?(:odba_id)
49
53
  @cache_entry_mutex.synchronize do
50
54
  @accessed_by.store(object.object_id, object.odba_id)
51
55
  end
52
- object
53
- end
54
- def odba_cut_connections!
56
+ object
57
+ end
58
+
59
+ def odba_cut_connections!
55
60
  @cache_entry_mutex.synchronize do
56
61
  @accessed_by.each { |object_id, odba_id|
57
- if((item = odba_id2ref(odba_id) || object_id2ref(object_id, odba_id)) \
58
- && item.respond_to?(:odba_cut_connection))
62
+ if (item = odba_id2ref(odba_id) || object_id2ref(object_id, odba_id)) \
63
+ && item.respond_to?(:odba_cut_connection)
59
64
  item.odba_cut_connection(_odba_object)
60
65
  end
61
66
  }
62
67
  end
63
- end
68
+ end
69
+
64
70
  def odba_notify_observers(*args)
65
71
  @odba_observers.each { |obs| obs.odba_update(*args) }
66
72
  end
67
- def odba_object
68
- @last_access = Time.now
73
+
74
+ def odba_object
75
+ @last_access = Time.now
69
76
  @odba_object = _odba_object
70
77
  @odba_object || ODBA.cache.fetch(@odba_id)
71
78
  end
79
+
72
80
  def _odba_object
73
81
  @odba_object || object_id2ref(@odba_object_id, @odba_id)
74
- end
75
- def odba_old?(retire_horizon = Time.now - ODBA.cache.retire_age)
82
+ end
83
+
84
+ def odba_old?(retire_horizon = Time.now - ODBA.cache.retire_age)
76
85
  !_odba_object.odba_unsaved? \
77
86
  && (retire_horizon > @last_access)
78
- end
79
- def odba_retire opts={}
80
- # replace with stubs in accessed_by
87
+ end
88
+
89
+ def odba_retire opts = {}
90
+ # replace with stubs in accessed_by
81
91
  instance = _odba_object
82
92
  if opts[:force]
83
93
  @cache_entry_mutex.synchronize do
84
94
  @accessed_by.each do |object_id, odba_id|
85
95
  if item = odba_id2ref(odba_id)
86
96
  item.odba_stubize instance, opts
87
- elsif(item = object_id2ref(object_id, odba_id))
97
+ elsif (item = object_id2ref(object_id, odba_id))
88
98
  if item.is_a?(Persistable) && !item.is_a?(Stub)
89
99
  item.odba_stubize instance, opts
90
100
  end
@@ -95,9 +105,9 @@ module ODBA
95
105
  @odba_object = nil
96
106
  else
97
107
  @accessed_by.delete_if { |object_id, odba_id|
98
- if(item = odba_id2ref(odba_id))
108
+ if (item = odba_id2ref(odba_id))
99
109
  item.odba_stubize instance
100
- elsif(item = object_id2ref(object_id, odba_id))
110
+ elsif (item = object_id2ref(object_id, odba_id))
101
111
  case item
102
112
  when Stub
103
113
  true
@@ -116,19 +126,20 @@ module ODBA
116
126
  @odba_object = nil
117
127
  end
118
128
  end
119
- end
120
- def odba_replace!(obj)
129
+ end
130
+
131
+ def odba_replace!(obj)
121
132
  oldhash = _odba_object.hash
122
- _odba_object.odba_replace!(obj)
123
- if(_odba_object.hash != oldhash)
133
+ _odba_object.odba_replace!(obj)
134
+ if _odba_object.hash != oldhash
124
135
  @cache_entry_mutex.synchronize do
125
136
  @accessed_by.each { |object_id, odba_id|
126
- if(item = odba_id2ref(odba_id) || object_id2ref(object_id, odba_id))
127
- item.rehash if(item.respond_to? :rehash)
137
+ if (item = odba_id2ref(odba_id) || object_id2ref(object_id, odba_id))
138
+ item.rehash if item.respond_to? :rehash
128
139
  end
129
140
  }
130
141
  end
131
142
  end
132
- end
133
- end
143
+ end
144
+ end
134
145
  end
@@ -1,63 +1,87 @@
1
1
  #!/usr/bin/env ruby
2
- # encoding: utf-8
2
+
3
3
  # ODBA::ConnectionPool -- odba -- 08.12.2011 -- mhatakeyama@ywesee.com
4
4
  # ODBA::ConnectionPool -- odba -- 08.03.2005 -- hwyss@ywesee.com
5
5
 
6
- require 'dbi'
7
- require 'thread'
6
+ require "dbi"
8
7
 
9
8
  module ODBA
10
- class ConnectionPool
11
- POOL_SIZE = 5
12
- SETUP_RETRIES = 3
13
- #attr_reader :connections
14
- attr_reader :connections, :dbi_args
15
- # All connections are delegated to DBI. The constructor simply records
16
- # the DBI-arguments and reuses them to setup connections when needed.
17
- def initialize(*dbi_args)
18
- @dbi_args = dbi_args
19
- @opts = @dbi_args.last.is_a?(Hash) ? @dbi_args.pop : Hash.new
20
- @connections = []
21
- @mutex = Mutex.new
22
- connect
23
- end
24
- def next_connection # :nodoc:
25
- conn = nil
26
- @mutex.synchronize {
27
- conn = @connections.shift
28
- }
29
- yield(conn)
30
- ensure
31
- @mutex.synchronize {
32
- @connections.push(conn)
33
- }
34
- end
35
- def method_missing(method, *args, &block) # :nodoc:
36
- tries = SETUP_RETRIES
37
- begin
38
- next_connection { |conn|
39
- conn.send(method, *args, &block)
40
- }
41
- rescue NoMethodError, DBI::Error => e
9
+ class ConnectionPool
10
+ POOL_SIZE = 5
11
+ SETUP_RETRIES = 3
12
+ # ydbd-pg maps every PG::Error - including connection level failures -
13
+ # onto DBI::ProgrammingError, so for that class the message is the only
14
+ # thing that tells a dead connection apart from a malformed statement.
15
+ # Without this list a restart of the database server leaves every pooled
16
+ # connection permanently broken, because the reconnect below never runs.
17
+ CONNECTION_LOST_MESSAGES = /
18
+ no\ connection\ to\ the\ server
19
+ | PQsocket
20
+ | server\ closed\ the\ connection
21
+ | connection\ not\ open
22
+ | terminating\ connection
23
+ | SSL\ connection\ has\ been\ closed
24
+ | could\ not\ connect\ to\ server
25
+ /xi
26
+ # attr_reader :connections
27
+ attr_reader :connections, :dbi_args
28
+ # All connections are delegated to DBI. The constructor simply records
29
+ # the DBI-arguments and reuses them to setup connections when needed.
30
+ def initialize(*dbi_args)
31
+ @dbi_args = dbi_args
32
+ @opts = @dbi_args.last.is_a?(Hash) ? @dbi_args.pop : {}
33
+ @connections = []
34
+ @mutex = Mutex.new
35
+ connect
36
+ end
37
+
38
+ def next_connection # :nodoc:
39
+ conn = nil
40
+ @mutex.synchronize {
41
+ conn = @connections.shift
42
+ }
43
+ yield(conn)
44
+ ensure
45
+ @mutex.synchronize {
46
+ @connections.push(conn)
47
+ }
48
+ end
49
+
50
+ def method_missing(method, *args, &block) # :nodoc:
51
+ tries = SETUP_RETRIES
52
+ begin
53
+ next_connection { |conn|
54
+ conn.send(method, *args, &block)
55
+ }
56
+ rescue NoMethodError, DBI::Error => e
42
57
  warn e
43
- if(tries > 0 && (!e.is_a?(DBI::ProgrammingError) \
44
- || e.message == 'no connection to the server'))
45
- sleep(SETUP_RETRIES - tries)
46
- tries -= 1
47
- reconnect
48
- retry
49
- else
50
- raise
51
- end
52
- end
53
- end
54
- def size
55
- @connections.size
56
- end
57
- alias :pool_size :size
58
- def connect # :nodoc:
59
- @mutex.synchronize { _connect }
60
- end
58
+ if tries > 0 && retryable?(e)
59
+ sleep(SETUP_RETRIES - tries)
60
+ tries -= 1
61
+ reconnect
62
+ retry
63
+ else
64
+ raise
65
+ end
66
+ end
67
+ end
68
+
69
+ # A statement that failed because the connection is gone is worth
70
+ # retrying on a fresh one. A statement that failed on its own merits is
71
+ # not - retrying it would only repeat the same error three times.
72
+ def retryable?(error) # :nodoc:
73
+ !error.is_a?(DBI::ProgrammingError) ||
74
+ CONNECTION_LOST_MESSAGES.match?(error.message.to_s)
75
+ end
76
+
77
+ def size
78
+ @connections.size
79
+ end
80
+ alias_method :pool_size, :size
81
+ def connect # :nodoc:
82
+ @mutex.synchronize { _connect }
83
+ end
84
+
61
85
  def _connect # :nodoc:
62
86
  POOL_SIZE.times {
63
87
  conn = DBI.connect(*@dbi_args)
@@ -67,24 +91,27 @@ module ODBA
67
91
  @connections.push(conn)
68
92
  }
69
93
  end
70
- def disconnect # :nodoc:
71
- @mutex.synchronize { _disconnect }
72
- end
73
- def _disconnect # :nodoc:
74
- while(conn = @connections.shift)
75
- begin
76
- conn.disconnect
77
- rescue DBI::InterfaceError, Exception
78
- ## we're not interested, since we are disconnecting anyway
94
+
95
+ def disconnect # :nodoc:
96
+ @mutex.synchronize { _disconnect }
97
+ end
98
+
99
+ def _disconnect # :nodoc:
100
+ while (conn = @connections.shift)
101
+ begin
102
+ conn.disconnect
103
+ rescue DBI::InterfaceError, Exception
104
+ ## we're not interested, since we are disconnecting anyway
79
105
  nil
80
- end
81
- end
82
- end
83
- def reconnect # :nodoc:
84
- @mutex.synchronize {
85
- _disconnect
86
- _connect
87
- }
88
- end
89
- end
106
+ end
107
+ end
108
+ end
109
+
110
+ def reconnect # :nodoc:
111
+ @mutex.synchronize {
112
+ _disconnect
113
+ _connect
114
+ }
115
+ end
116
+ end
90
117
  end
@@ -1,59 +1,65 @@
1
1
  #!/usr/bin/env ruby
2
2
  # DRbWrapper -- ydim -- 11.01.2006 -- hwyss@ywesee.com
3
3
 
4
- require 'drb'
5
- require 'odba/persistable'
6
- require 'odba/stub'
7
- require 'odba/odba'
8
- require 'drb/timeridconv'
4
+ require "drb"
5
+ require "odba/persistable"
6
+ require "odba/stub"
7
+ require "odba/odba"
8
+ require "drb/timeridconv"
9
9
 
10
10
  module ODBA
11
- class DRbWrapper
12
- instance_methods.each { |m|
13
- undef_method(m) unless m =~ /^(__)|(respond_to\?|object_id$)/ }
11
+ class DRbWrapper
12
+ instance_methods.each { |m|
13
+ undef_method(m) unless /^(__)|(respond_to\?|object_id$)/.match?(m)
14
+ }
14
15
  include DRb::DRbUndumped
15
16
  def initialize(obj)
16
17
  @obj = obj
17
18
  end
19
+
18
20
  def respond_to?(sym, *args)
19
21
  super || @obj.respond_to?(sym, *args)
20
22
  end
23
+
21
24
  def method_missing(sym, *args)
22
- if(block_given?)
25
+ if block_given?
23
26
  res = @obj.__send__(sym, *args) { |*block_args|
24
- yield *block_args.collect { |arg| __wrap(arg) }
27
+ yield(*block_args.collect { |arg| __wrap(arg) })
25
28
  }
26
29
  __wrap(res)
27
30
  else
28
31
  res = @obj.__send__(sym, *args)
29
- if(res.is_a?(Array))
32
+ if res.is_a?(Array)
30
33
  res.collect { |item| __wrap(item) }
31
- elsif(res.is_a?(Hash))
32
- res.inject({}) { |memo, (key, value)|
34
+ elsif res.is_a?(Hash)
35
+ res.each_with_object({}) { |(key, value), memo|
33
36
  memo.store(__wrap(key), __wrap(value))
34
- memo
35
37
  }
36
38
  else
37
39
  __wrap(res)
38
40
  end
39
41
  end
40
42
  end
43
+
41
44
  def __wrap(obj)
42
- if(obj.is_a?(ODBA::Persistable))
45
+ if obj.is_a?(ODBA::Persistable)
43
46
  DRbWrapper.new(obj.odba_instance)
44
47
  else
45
48
  obj
46
49
  end
47
50
  end
51
+
48
52
  def __wrappee
49
53
  @obj
50
54
  end
51
55
  end
56
+
52
57
  class DRbIdConv < DRb::DRbIdConv
53
58
  def initialize(*args)
54
59
  super
55
60
  @unsaved = {}
56
61
  end
62
+
57
63
  def odba_update(key, odba_id, object_id)
58
64
  case key
59
65
  when :store
@@ -62,9 +68,10 @@ module ODBA
62
68
  @unsaved.delete(object_id)
63
69
  end
64
70
  end
71
+
65
72
  def to_obj(ref)
66
73
  test = ref
67
- if(test.is_a?(String) || (test = @unsaved[ref]))
74
+ if test.is_a?(String) || (test = @unsaved[ref])
68
75
  DRbWrapper.new(ODBA.cache.fetch(test.to_i))
69
76
  else
70
77
  super
@@ -72,9 +79,10 @@ module ODBA
72
79
  rescue RuntimeError => e
73
80
  raise RangeError, e.message
74
81
  end
82
+
75
83
  def to_id(obj)
76
- if(obj.is_a?(ODBA::Persistable))
77
- if(obj.odba_unsaved?)
84
+ if obj.is_a?(ODBA::Persistable)
85
+ if obj.odba_unsaved?
78
86
  obj.odba_add_observer(self)
79
87
  super
80
88
  else
@@ -1,26 +1,26 @@
1
1
  #!/usr/bin/env ruby
2
2
  #-- IdServer -- odba -- 10.11.2004 -- hwyss@ywesee.com
3
3
 
4
- require 'odba/persistable'
5
- require 'thread'
4
+ require "odba/persistable"
6
5
 
7
6
  module ODBA
8
- class IdServer
9
- include Persistable
10
- ODBA_SERIALIZABLE = ['@ids']
11
- ODBA_EXCLUDE_VARS = ['@mutex']
12
- def initialize
13
- @ids = {}
14
- end
15
- def next_id(key, startval=1)
16
- @mutex ||= Mutex.new
17
- res = nil
18
- @mutex.synchronize {
19
- @ids[key] ||= (startval - 1)
20
- res = @ids[key] += 1
21
- }
22
- odba_store
23
- res
24
- end
25
- end
7
+ class IdServer
8
+ include Persistable
9
+ ODBA_SERIALIZABLE = ["@ids"]
10
+ ODBA_EXCLUDE_VARS = ["@mutex"]
11
+ def initialize
12
+ @ids = {}
13
+ end
14
+
15
+ def next_id(key, startval = 1)
16
+ @mutex ||= Mutex.new
17
+ res = nil
18
+ @mutex.synchronize {
19
+ @ids[key] ||= (startval - 1)
20
+ res = @ids[key] += 1
21
+ }
22
+ odba_store
23
+ res
24
+ end
25
+ end
26
26
  end