sequel_core 1.0.1 → 1.0.2
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 +4 -0
- data/Rakefile +2 -1
- data/lib/sequel_core/core_ext.rb +0 -35
- data/lib/sequel_core.rb +4 -1
- data/spec/core_ext_spec.rb +0 -48
- data/spec/database_spec.rb +5 -5
- data/spec/rcov.opts +3 -1
- metadata +11 -5
- data/lib/sequel_core/connection_pool.rb +0 -152
- data/spec/connection_pool_spec.rb +0 -356
data/CHANGELOG
CHANGED
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ include FileUtils
|
|
9
9
|
# Configuration
|
10
10
|
##############################################################################
|
11
11
|
NAME = "sequel_core"
|
12
|
-
VERS = "1.0.
|
12
|
+
VERS = "1.0.2"
|
13
13
|
CLEAN.include ["**/.*.sw?", "pkg/*", ".config", "doc/*", "coverage/*"]
|
14
14
|
RDOC_OPTS = [
|
15
15
|
"--quiet",
|
@@ -58,6 +58,7 @@ spec = Gem::Specification.new do |s|
|
|
58
58
|
s.required_ruby_version = ">= 1.8.4"
|
59
59
|
|
60
60
|
s.add_dependency("metaid")
|
61
|
+
s.add_dependency("assistance", ">= 0.1")
|
61
62
|
|
62
63
|
case RUBY_PLATFORM
|
63
64
|
when /mswin/
|
data/lib/sequel_core/core_ext.rb
CHANGED
@@ -22,38 +22,3 @@ class Object
|
|
22
22
|
nil
|
23
23
|
end
|
24
24
|
end
|
25
|
-
|
26
|
-
module Sequel
|
27
|
-
# Facilitates time calculations by providing methods to convert from larger
|
28
|
-
# time units to seconds, and to convert relative time intervals to absolute
|
29
|
-
# ones. This module duplicates some of the functionality provided by Rails'
|
30
|
-
# ActiveSupport::CoreExtensions::Numeric::Time module.
|
31
|
-
module NumericExtensions
|
32
|
-
MINUTE = 60
|
33
|
-
HOUR = 3600
|
34
|
-
DAY = 86400
|
35
|
-
WEEK = DAY * 7
|
36
|
-
|
37
|
-
# Converts self from minutes to seconds
|
38
|
-
def minutes; self * MINUTE; end; alias_method :minute, :minutes
|
39
|
-
# Converts self from hours to seconds
|
40
|
-
def hours; self * HOUR; end; alias_method :hour, :hours
|
41
|
-
# Converts self from days to seconds
|
42
|
-
def days; self * DAY; end; alias_method :day, :days
|
43
|
-
# Converts self from weeks to seconds
|
44
|
-
def weeks; self * WEEK; end; alias_method :week, :weeks
|
45
|
-
|
46
|
-
# Returns the time at now - self.
|
47
|
-
def ago(t = Time.now); t - self; end
|
48
|
-
alias_method :before, :ago
|
49
|
-
|
50
|
-
# Returns the time at now + self.
|
51
|
-
def from_now(t = Time.now); t + self; end
|
52
|
-
alias_method :since, :from_now
|
53
|
-
|
54
|
-
# Extends the Numeric class with numeric extensions.
|
55
|
-
def self.enable
|
56
|
-
Numeric.send(:include, self)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
data/lib/sequel_core.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
gem "assistance", ">= 0.1"
|
2
|
+
|
1
3
|
require "metaid"
|
4
|
+
require "assistance"
|
2
5
|
require "bigdecimal"
|
3
6
|
require "bigdecimal/util"
|
4
7
|
|
5
8
|
files = %w[
|
6
|
-
core_ext core_sql array_keys exceptions
|
9
|
+
core_ext core_sql array_keys exceptions pretty_table
|
7
10
|
dataset migration model schema database worker
|
8
11
|
]
|
9
12
|
dir = File.join(File.dirname(__FILE__), "sequel_core")
|
data/spec/core_ext_spec.rb
CHANGED
@@ -17,51 +17,3 @@ context "Range#interval" do
|
|
17
17
|
(t1..t2).interval.should == r
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
21
|
-
context "Numeric extensions" do
|
22
|
-
setup do
|
23
|
-
Sequel::NumericExtensions.enable
|
24
|
-
end
|
25
|
-
|
26
|
-
specify "should support conversion of minutes to seconds" do
|
27
|
-
1.minute.should == 60
|
28
|
-
3.minutes.should == 180
|
29
|
-
end
|
30
|
-
|
31
|
-
specify "should support conversion of hours to seconds" do
|
32
|
-
1.hour.should == 3600
|
33
|
-
3.hours.should == 3600 * 3
|
34
|
-
end
|
35
|
-
|
36
|
-
specify "should support conversion of days to seconds" do
|
37
|
-
1.day.should == 86400
|
38
|
-
3.days.should == 86400 * 3
|
39
|
-
end
|
40
|
-
|
41
|
-
specify "should support conversion of weeks to seconds" do
|
42
|
-
1.week.should == 86400 * 7
|
43
|
-
3.weeks.should == 86400 * 7 * 3
|
44
|
-
end
|
45
|
-
|
46
|
-
specify "should provide #ago functionality" do
|
47
|
-
t1 = Time.now
|
48
|
-
t2 = 1.day.ago
|
49
|
-
t1.should > t2
|
50
|
-
((t1 - t2).to_i - 86400).abs.should < 2
|
51
|
-
|
52
|
-
t1 = Time.now
|
53
|
-
t2 = 1.day.before(t1)
|
54
|
-
t2.should == t1 - 1.day
|
55
|
-
end
|
56
|
-
|
57
|
-
specify "should provide #from_now functionality" do
|
58
|
-
t1 = Time.now
|
59
|
-
t2 = 1.day.from_now
|
60
|
-
t1.should < t2
|
61
|
-
((t2 - t1).to_i - 86400).abs.should < 2
|
62
|
-
|
63
|
-
t1 = Time.now
|
64
|
-
t2 = 1.day.since(t1)
|
65
|
-
t2.should == t1 + 1.day
|
66
|
-
end
|
67
|
-
end
|
data/spec/database_spec.rb
CHANGED
@@ -14,7 +14,7 @@ context "A new Database" do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
specify "should create a connection pool" do
|
17
|
-
@db.pool.should be_a_kind_of(
|
17
|
+
@db.pool.should be_a_kind_of(ConnectionPool)
|
18
18
|
@db.pool.max_size.should == 4
|
19
19
|
|
20
20
|
Sequel::Database.new(:max_connections => 10).pool.max_size.should == 10
|
@@ -590,24 +590,24 @@ context "A single threaded database" do
|
|
590
590
|
|
591
591
|
specify "should use a SingleThreadedPool instead of a ConnectionPool" do
|
592
592
|
db = Sequel::Database.new(:single_threaded => true)
|
593
|
-
db.pool.should be_a_kind_of(
|
593
|
+
db.pool.should be_a_kind_of(SingleThreadedPool)
|
594
594
|
end
|
595
595
|
|
596
596
|
specify "should be constructable using :single_threaded => true option" do
|
597
597
|
db = Sequel::Database.new(:single_threaded => true)
|
598
|
-
db.pool.should be_a_kind_of(
|
598
|
+
db.pool.should be_a_kind_of(SingleThreadedPool)
|
599
599
|
end
|
600
600
|
|
601
601
|
specify "should be constructable using Database.single_threaded = true" do
|
602
602
|
Sequel::Database.single_threaded = true
|
603
603
|
db = Sequel::Database.new
|
604
|
-
db.pool.should be_a_kind_of(
|
604
|
+
db.pool.should be_a_kind_of(SingleThreadedPool)
|
605
605
|
end
|
606
606
|
|
607
607
|
specify "should be constructable using Sequel.single_threaded = true" do
|
608
608
|
Sequel.single_threaded = true
|
609
609
|
db = Sequel::Database.new
|
610
|
-
db.pool.should be_a_kind_of(
|
610
|
+
db.pool.should be_a_kind_of(SingleThreadedPool)
|
611
611
|
end
|
612
612
|
end
|
613
613
|
|
data/spec/rcov.opts
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-01-
|
12
|
+
date: 2008-01-14 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -21,6 +21,15 @@ dependencies:
|
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: "0"
|
23
23
|
version:
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: assistance
|
26
|
+
version_requirement:
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: "0.1"
|
32
|
+
version:
|
24
33
|
- !ruby/object:Gem::Dependency
|
25
34
|
name: RubyInline
|
26
35
|
version_requirement:
|
@@ -63,7 +72,6 @@ files:
|
|
63
72
|
- README
|
64
73
|
- Rakefile
|
65
74
|
- bin/sequel
|
66
|
-
- doc/rdoc
|
67
75
|
- spec/adapters
|
68
76
|
- spec/adapters/informix_spec.rb
|
69
77
|
- spec/adapters/mysql_spec.rb
|
@@ -71,7 +79,6 @@ files:
|
|
71
79
|
- spec/adapters/postgres_spec.rb
|
72
80
|
- spec/adapters/sqlite_spec.rb
|
73
81
|
- spec/array_keys_spec.rb
|
74
|
-
- spec/connection_pool_spec.rb
|
75
82
|
- spec/core_ext_spec.rb
|
76
83
|
- spec/core_sql_spec.rb
|
77
84
|
- spec/database_spec.rb
|
@@ -101,7 +108,6 @@ files:
|
|
101
108
|
- lib/sequel_core/adapters/postgres.rb
|
102
109
|
- lib/sequel_core/adapters/sqlite.rb
|
103
110
|
- lib/sequel_core/array_keys.rb
|
104
|
-
- lib/sequel_core/connection_pool.rb
|
105
111
|
- lib/sequel_core/core_ext.rb
|
106
112
|
- lib/sequel_core/core_sql.rb
|
107
113
|
- lib/sequel_core/database.rb
|
@@ -1,152 +0,0 @@
|
|
1
|
-
require 'thread'
|
2
|
-
|
3
|
-
module Sequel
|
4
|
-
# A ConnectionPool manages access to database connections by keeping
|
5
|
-
# multiple connections and giving threads exclusive access to each
|
6
|
-
# connection.
|
7
|
-
class ConnectionPool
|
8
|
-
attr_reader :mutex
|
9
|
-
|
10
|
-
# The maximum number of connections.
|
11
|
-
attr_reader :max_size
|
12
|
-
|
13
|
-
# The proc used to create a new connection.
|
14
|
-
attr_accessor :connection_proc
|
15
|
-
|
16
|
-
attr_reader :available_connections, :allocated, :created_count
|
17
|
-
|
18
|
-
# Constructs a new pool with a maximum size. If a block is supplied, it
|
19
|
-
# is used to create new connections as they are needed.
|
20
|
-
#
|
21
|
-
# pool = ConnectionPool.new(10) {MyConnection.new(opts)}
|
22
|
-
#
|
23
|
-
# The connection creation proc can be changed at any time by assigning a
|
24
|
-
# Proc to pool#connection_proc.
|
25
|
-
#
|
26
|
-
# pool = ConnectionPool.new(10)
|
27
|
-
# pool.connection_proc = proc {MyConnection.new(opts)}
|
28
|
-
def initialize(max_size = 4, &block)
|
29
|
-
@max_size = max_size
|
30
|
-
@mutex = Mutex.new
|
31
|
-
@connection_proc = block
|
32
|
-
|
33
|
-
@available_connections = []
|
34
|
-
@allocated = {}
|
35
|
-
@created_count = 0
|
36
|
-
end
|
37
|
-
|
38
|
-
# Returns the number of created connections.
|
39
|
-
def size
|
40
|
-
@created_count
|
41
|
-
end
|
42
|
-
|
43
|
-
# Assigns a connection to the current thread, yielding the connection
|
44
|
-
# to the supplied block.
|
45
|
-
#
|
46
|
-
# pool.hold {|conn| conn.execute('DROP TABLE posts')}
|
47
|
-
#
|
48
|
-
# Pool#hold is re-entrant, meaning it can be called recursively in
|
49
|
-
# the same thread without blocking.
|
50
|
-
#
|
51
|
-
# If no connection is available, Pool#hold will block until a connection
|
52
|
-
# is available.
|
53
|
-
def hold
|
54
|
-
t = Thread.current
|
55
|
-
if (conn = owned_connection(t))
|
56
|
-
return yield(conn)
|
57
|
-
end
|
58
|
-
while !(conn = acquire(t))
|
59
|
-
sleep 0.001
|
60
|
-
end
|
61
|
-
begin
|
62
|
-
yield conn
|
63
|
-
ensure
|
64
|
-
release(t)
|
65
|
-
end
|
66
|
-
rescue Exception => e
|
67
|
-
# if the error is not a StandardError it is converted into RuntimeError.
|
68
|
-
raise e.is_a?(StandardError) ? e : e.message
|
69
|
-
end
|
70
|
-
|
71
|
-
# Removes all connection currently available, optionally yielding each
|
72
|
-
# connection to the given block. This method has the effect of
|
73
|
-
# disconnecting from the database. Once a connection is requested using
|
74
|
-
# #hold, the connection pool creates new connections to the database.
|
75
|
-
def disconnect(&block)
|
76
|
-
@mutex.synchronize do
|
77
|
-
@available_connections.each {|c| block[c]} if block
|
78
|
-
@available_connections = []
|
79
|
-
@created_count = @allocated.size
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
private
|
84
|
-
# Returns the connection owned by the supplied thread, if any.
|
85
|
-
def owned_connection(thread)
|
86
|
-
@mutex.synchronize {@allocated[thread]}
|
87
|
-
end
|
88
|
-
|
89
|
-
# Assigns a connection to the supplied thread, if one is available.
|
90
|
-
def acquire(thread)
|
91
|
-
@mutex.synchronize do
|
92
|
-
if conn = available
|
93
|
-
@allocated[thread] = conn
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Returns an available connection. If no connection is available,
|
99
|
-
# tries to create a new connection.
|
100
|
-
def available
|
101
|
-
@available_connections.pop || make_new
|
102
|
-
end
|
103
|
-
|
104
|
-
# Creates a new connection if the size of the pool is less than the
|
105
|
-
# maximum size.
|
106
|
-
def make_new
|
107
|
-
if @created_count < @max_size
|
108
|
-
@created_count += 1
|
109
|
-
@connection_proc ? @connection_proc.call : \
|
110
|
-
(raise Error, "No connection proc specified")
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# Releases the connection assigned to the supplied thread.
|
115
|
-
def release(thread)
|
116
|
-
@mutex.synchronize do
|
117
|
-
@available_connections << @allocated[thread]
|
118
|
-
@allocated.delete(thread)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
# A SingleThreadedPool acts as a replacement for a ConnectionPool for use
|
124
|
-
# in single-threaded applications. ConnectionPool imposes a substantial
|
125
|
-
# performance penalty, so SingleThreadedPool is used to gain some speed.
|
126
|
-
class SingleThreadedPool
|
127
|
-
attr_reader :conn
|
128
|
-
attr_writer :connection_proc
|
129
|
-
|
130
|
-
# Initializes the instance with the supplied block as the connection_proc.
|
131
|
-
def initialize(&block)
|
132
|
-
@connection_proc = block
|
133
|
-
end
|
134
|
-
|
135
|
-
# Yields the connection to the supplied block. This method simulates the
|
136
|
-
# ConnectionPool#hold API.
|
137
|
-
def hold
|
138
|
-
@conn ||= @connection_proc.call
|
139
|
-
yield @conn
|
140
|
-
rescue Exception => e
|
141
|
-
# if the error is not a StandardError it is converted into RuntimeError.
|
142
|
-
raise e.is_a?(StandardError) ? e : e.message
|
143
|
-
end
|
144
|
-
|
145
|
-
# Disconnects from the database. Once a connection is requested using
|
146
|
-
# #hold, the connection is reestablished.
|
147
|
-
def disconnect(&block)
|
148
|
-
block[@conn] if block && @conn
|
149
|
-
@conn = nil
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
@@ -1,356 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
-
|
3
|
-
context "An empty ConnectionPool" do
|
4
|
-
setup do
|
5
|
-
@cpool = Sequel::ConnectionPool.new
|
6
|
-
end
|
7
|
-
|
8
|
-
specify "should have no available connections" do
|
9
|
-
@cpool.available_connections.should == []
|
10
|
-
end
|
11
|
-
|
12
|
-
specify "should have no allocated connections" do
|
13
|
-
@cpool.allocated.should == {}
|
14
|
-
end
|
15
|
-
|
16
|
-
specify "should have a created_count of zero" do
|
17
|
-
@cpool.created_count.should == 0
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
context "A connection pool handling connections" do
|
22
|
-
setup do
|
23
|
-
@max_size = 2
|
24
|
-
@cpool = Sequel::ConnectionPool.new(@max_size) {:got_connection}
|
25
|
-
end
|
26
|
-
|
27
|
-
specify "#hold should increment #created_count" do
|
28
|
-
@cpool.hold do
|
29
|
-
@cpool.created_count.should == 1
|
30
|
-
@cpool.hold {@cpool.created_count.should == 1}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
specify "#hold should add the connection to the #allocated hash" do
|
35
|
-
@cpool.hold do
|
36
|
-
@cpool.allocated.size.should == 1
|
37
|
-
|
38
|
-
@cpool.allocated.values.should == [:got_connection]
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
specify "#hold should yield a new connection" do
|
43
|
-
@cpool.hold {|conn| conn.should == :got_connection}
|
44
|
-
end
|
45
|
-
|
46
|
-
specify "a connection should be de-allocated after it has been used in #hold" do
|
47
|
-
@cpool.hold {}
|
48
|
-
@cpool.allocated.size.should == 0
|
49
|
-
end
|
50
|
-
|
51
|
-
specify "#hold should return the value of its block" do
|
52
|
-
@cpool.hold {:block_return}.should == :block_return
|
53
|
-
end
|
54
|
-
|
55
|
-
specify "#make_new should not make more than max_size connections" do
|
56
|
-
@cpool.send(:make_new).should == :got_connection
|
57
|
-
@cpool.send(:make_new).should == :got_connection
|
58
|
-
@cpool.send(:make_new).should == nil
|
59
|
-
@cpool.created_count.should == 2
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
class DummyConnection
|
64
|
-
@@value = 0
|
65
|
-
def initialize
|
66
|
-
@@value += 1
|
67
|
-
end
|
68
|
-
|
69
|
-
def value
|
70
|
-
@@value
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
context "ConnectionPool#hold" do
|
75
|
-
setup do
|
76
|
-
@pool = Sequel::ConnectionPool.new {DummyConnection.new}
|
77
|
-
end
|
78
|
-
|
79
|
-
specify "should pass the result of the connection maker proc to the supplied block" do
|
80
|
-
res = nil
|
81
|
-
@pool.hold {|c| res = c}
|
82
|
-
res.should be_a_kind_of(DummyConnection)
|
83
|
-
res.value.should == 1
|
84
|
-
@pool.hold {|c| res = c}
|
85
|
-
res.should be_a_kind_of(DummyConnection)
|
86
|
-
res.value.should == 1 # the connection maker is invoked only once
|
87
|
-
end
|
88
|
-
|
89
|
-
specify "should be re-entrant by the same thread" do
|
90
|
-
cc = nil
|
91
|
-
@pool.hold {|c| @pool.hold {|c| @pool.hold {|c| cc = c}}}
|
92
|
-
cc.should be_a_kind_of(DummyConnection)
|
93
|
-
end
|
94
|
-
|
95
|
-
specify "should catch exceptions and reraise them" do
|
96
|
-
proc {@pool.hold {|c| c.foobar}}.should raise_error(NoMethodError)
|
97
|
-
end
|
98
|
-
|
99
|
-
specify "should handle Exception errors (normally not caught be rescue)" do
|
100
|
-
begin
|
101
|
-
@pool.hold {raise Exception}
|
102
|
-
rescue => e
|
103
|
-
e.should be_a_kind_of(RuntimeError)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
context "ConnectionPool#connection_proc" do
|
109
|
-
setup do
|
110
|
-
@pool = Sequel::ConnectionPool.new
|
111
|
-
end
|
112
|
-
|
113
|
-
specify "should be nil if no block is supplied to the pool" do
|
114
|
-
@pool.connection_proc.should be_nil
|
115
|
-
proc {@pool.hold {}}.should raise_error
|
116
|
-
end
|
117
|
-
|
118
|
-
specify "should be mutable" do
|
119
|
-
@pool.connection_proc = proc {'herro'}
|
120
|
-
res = nil
|
121
|
-
proc {@pool.hold {|c| res = c}}.should_not raise_error
|
122
|
-
res.should == 'herro'
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
context "A connection pool with a max size of 1" do
|
127
|
-
setup do
|
128
|
-
@invoked_count = 0
|
129
|
-
@pool = Sequel::ConnectionPool.new(1) {@invoked_count += 1; 'herro'}
|
130
|
-
end
|
131
|
-
|
132
|
-
specify "should let only one thread access the connection at any time" do
|
133
|
-
cc,c1, c2 = nil
|
134
|
-
|
135
|
-
t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; while c == 'herro';sleep 0.1;end}}
|
136
|
-
sleep 0.2
|
137
|
-
cc.should == 'herro'
|
138
|
-
c1.should == 'herro'
|
139
|
-
|
140
|
-
t2 = Thread.new {@pool.hold {|c| c2 = c.dup; while c == 'hello';sleep 0.1;end}}
|
141
|
-
sleep 0.2
|
142
|
-
|
143
|
-
# connection held by t1
|
144
|
-
t1.should be_alive
|
145
|
-
t2.should be_alive
|
146
|
-
|
147
|
-
cc.should == 'herro'
|
148
|
-
c1.should == 'herro'
|
149
|
-
c2.should be_nil
|
150
|
-
|
151
|
-
@pool.available_connections.should be_empty
|
152
|
-
@pool.allocated.should == {t1 => cc}
|
153
|
-
|
154
|
-
cc.gsub!('rr', 'll')
|
155
|
-
sleep 0.5
|
156
|
-
|
157
|
-
# connection held by t2
|
158
|
-
t1.should_not be_alive
|
159
|
-
t2.should be_alive
|
160
|
-
|
161
|
-
c2.should == 'hello'
|
162
|
-
|
163
|
-
@pool.available_connections.should be_empty
|
164
|
-
@pool.allocated.should == {t2 => cc}
|
165
|
-
|
166
|
-
cc.gsub!('ll', 'rr')
|
167
|
-
sleep 0.5
|
168
|
-
|
169
|
-
#connection released
|
170
|
-
t2.should_not be_alive
|
171
|
-
|
172
|
-
cc.should == 'herro'
|
173
|
-
|
174
|
-
@invoked_count.should == 1
|
175
|
-
@pool.size.should == 1
|
176
|
-
@pool.available_connections.should == [cc]
|
177
|
-
@pool.allocated.should be_empty
|
178
|
-
end
|
179
|
-
|
180
|
-
specify "should let the same thread reenter #hold" do
|
181
|
-
c1, c2, c3 = nil
|
182
|
-
@pool.hold do |c|
|
183
|
-
c1 = c
|
184
|
-
@pool.hold do |c|
|
185
|
-
c2 = c
|
186
|
-
@pool.hold do |c|
|
187
|
-
c3 = c
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
c1.should == 'herro'
|
192
|
-
c2.should == 'herro'
|
193
|
-
c3.should == 'herro'
|
194
|
-
|
195
|
-
@invoked_count.should == 1
|
196
|
-
@pool.size.should == 1
|
197
|
-
@pool.available_connections.size.should == 1
|
198
|
-
@pool.allocated.should be_empty
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
context "A connection pool with a max size of 5" do
|
203
|
-
setup do
|
204
|
-
@invoked_count = 0
|
205
|
-
@pool = Sequel::ConnectionPool.new(5) {@invoked_count += 1}
|
206
|
-
end
|
207
|
-
|
208
|
-
specify "should let five threads simultaneously access separate connections" do
|
209
|
-
cc = {}
|
210
|
-
threads = []
|
211
|
-
stop = nil
|
212
|
-
|
213
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.1;end}}; sleep 0.1}
|
214
|
-
sleep 0.2
|
215
|
-
threads.each {|t| t.should be_alive}
|
216
|
-
cc.size.should == 5
|
217
|
-
@invoked_count.should == 5
|
218
|
-
@pool.size.should == 5
|
219
|
-
@pool.available_connections.should be_empty
|
220
|
-
@pool.allocated.should == {threads[0] => 1, threads[1] => 2, threads[2] => 3,
|
221
|
-
threads[3] => 4, threads[4] => 5}
|
222
|
-
|
223
|
-
threads[0].raise "your'e dead"
|
224
|
-
sleep 0.1
|
225
|
-
threads[3].raise "your'e dead too"
|
226
|
-
|
227
|
-
sleep 0.1
|
228
|
-
|
229
|
-
@pool.available_connections.should == [1, 4]
|
230
|
-
@pool.allocated.should == {threads[1] => 2, threads[2] => 3, threads[4] => 5}
|
231
|
-
|
232
|
-
stop = true
|
233
|
-
sleep 0.2
|
234
|
-
|
235
|
-
@pool.available_connections.size.should == 5
|
236
|
-
@pool.allocated.should be_empty
|
237
|
-
end
|
238
|
-
|
239
|
-
specify "should block threads until a connection becomes available" do
|
240
|
-
cc = {}
|
241
|
-
threads = []
|
242
|
-
stop = nil
|
243
|
-
|
244
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.1;end}}; sleep 0.1}
|
245
|
-
sleep 0.2
|
246
|
-
threads.each {|t| t.should be_alive}
|
247
|
-
@pool.available_connections.should be_empty
|
248
|
-
|
249
|
-
3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c}}}
|
250
|
-
|
251
|
-
sleep 0.2
|
252
|
-
threads[5].should be_alive
|
253
|
-
threads[6].should be_alive
|
254
|
-
threads[7].should be_alive
|
255
|
-
cc.size.should == 5
|
256
|
-
cc[5].should be_nil
|
257
|
-
cc[6].should be_nil
|
258
|
-
cc[7].should be_nil
|
259
|
-
|
260
|
-
stop = true
|
261
|
-
sleep 0.3
|
262
|
-
|
263
|
-
threads.each {|t| t.should_not be_alive}
|
264
|
-
|
265
|
-
@pool.size.should == 5
|
266
|
-
@invoked_count.should == 5
|
267
|
-
@pool.available_connections.size.should == 5
|
268
|
-
@pool.allocated.should be_empty
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
context "ConnectionPool#disconnect" do
|
273
|
-
setup do
|
274
|
-
@count = 0
|
275
|
-
@pool = Sequel::ConnectionPool.new(5) {{:id => @count += 1}}
|
276
|
-
end
|
277
|
-
|
278
|
-
specify "should invoke the given block for each available connection" do
|
279
|
-
threads = []
|
280
|
-
stop = nil
|
281
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
|
282
|
-
while @pool.size < 5
|
283
|
-
sleep 0.2
|
284
|
-
end
|
285
|
-
stop = true
|
286
|
-
sleep 1
|
287
|
-
threads.each {|t| t.join}
|
288
|
-
|
289
|
-
@pool.size.should == 5
|
290
|
-
@pool.available_connections.size.should == 5
|
291
|
-
@pool.available_connections.each {|c| c[:id].should_not be_nil}
|
292
|
-
conns = []
|
293
|
-
@pool.disconnect {|c| conns << c}
|
294
|
-
conns.size.should == 5
|
295
|
-
end
|
296
|
-
|
297
|
-
specify "should remove all available connections" do
|
298
|
-
threads = []
|
299
|
-
stop = nil
|
300
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
|
301
|
-
while @pool.size < 5
|
302
|
-
sleep 0.2
|
303
|
-
end
|
304
|
-
stop = true
|
305
|
-
sleep 1
|
306
|
-
threads.each {|t| t.join}
|
307
|
-
|
308
|
-
@pool.size.should == 5
|
309
|
-
@pool.disconnect
|
310
|
-
@pool.size.should == 0
|
311
|
-
end
|
312
|
-
|
313
|
-
specify "should not touch connections in use" do
|
314
|
-
threads = []
|
315
|
-
stop = nil
|
316
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
|
317
|
-
while @pool.size < 5
|
318
|
-
sleep 0.2
|
319
|
-
end
|
320
|
-
stop = true
|
321
|
-
sleep 1
|
322
|
-
threads.each {|t| t.join}
|
323
|
-
|
324
|
-
@pool.size.should == 5
|
325
|
-
|
326
|
-
@pool.hold do |conn|
|
327
|
-
@pool.available_connections.size.should == 4
|
328
|
-
@pool.available_connections.each {|c| c.should_not be(conn)}
|
329
|
-
conns = []
|
330
|
-
@pool.disconnect {|c| conns << c}
|
331
|
-
conns.size.should == 4
|
332
|
-
end
|
333
|
-
@pool.size.should == 1
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
context "SingleThreadedPool" do
|
338
|
-
setup do
|
339
|
-
@pool = Sequel::SingleThreadedPool.new {1234}
|
340
|
-
end
|
341
|
-
|
342
|
-
specify "should provide a #hold method" do
|
343
|
-
conn = nil
|
344
|
-
@pool.hold {|c| conn = c}
|
345
|
-
conn.should == 1234
|
346
|
-
end
|
347
|
-
|
348
|
-
specify "should provide a #disconnect method" do
|
349
|
-
@pool.hold {|c|}
|
350
|
-
@pool.conn.should == 1234
|
351
|
-
conn = nil
|
352
|
-
@pool.disconnect {|c| conn = c}
|
353
|
-
conn.should == 1234
|
354
|
-
@pool.conn.should be_nil
|
355
|
-
end
|
356
|
-
end
|