oedipus 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,109 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # Oedipus Sphinx 2 Search.
5
+ # Copyright © 2012 Chris Corbyn.
6
+ #
7
+ # See LICENSE file for details.
8
+ ##
9
+
10
+ require "thread"
11
+
12
+ module Oedipus
13
+ class Connection
14
+ # Provides a thread-safe pool of connections, with a specified TTL.
15
+ class Pool
16
+ # Initialize a new connection pool with the given options.
17
+ #
18
+ # @param [Hash] options
19
+ # configuration for the pool
20
+ #
21
+ # @option [String] host
22
+ # the host to use when allocating new connections
23
+ #
24
+ # @option [Fixnum] port
25
+ # the port to use when allocating new connections
26
+ #
27
+ # @option [Fixnum] size
28
+ # the maximum number of connections (defaults to 8)
29
+ #
30
+ # @option [Fixnum] ttl
31
+ # the length of time for which any given connection should live
32
+ def initialize(options)
33
+ @host = options[:host]
34
+ @port = options[:port]
35
+
36
+ @size = options.fetch(:size, 8)
37
+ @ttl = options.fetch(:ttl, 60)
38
+
39
+ @available = []
40
+ @used = {}
41
+ @expiries = {}
42
+ @condition = ConditionVariable.new
43
+ @lock = Mutex.new
44
+
45
+ sweeper
46
+ end
47
+
48
+ # Acquire a connection from the pool, for the duration of a block.
49
+ #
50
+ # The release of the connection is done automatically.
51
+ #
52
+ # @yields [Oedipus::Mysql]
53
+ # a connection object
54
+ def acquire
55
+ instance = nil
56
+ begin
57
+ @lock.synchronize do
58
+ if instance = @available.pop
59
+ @used[instance] = instance
60
+ elsif @size > (@available.size + @used.size)
61
+ instance = new_instance
62
+ else
63
+ @condition.wait(@lock)
64
+ end
65
+ end
66
+ end until instance
67
+
68
+ yield instance
69
+ ensure
70
+ release(instance)
71
+ end
72
+
73
+ private
74
+
75
+ def release(instance)
76
+ @lock.synchronize do
77
+ @available << @used.delete(instance) if instance
78
+ @condition.broadcast
79
+ end
80
+ end
81
+
82
+ def new_instance
83
+ Oedipus::Mysql.new(@host, @port).tap do |instance|
84
+ @used[instance] = instance
85
+ @expiries[instance] = Time.now + @ttl
86
+ end
87
+ end
88
+
89
+ # Close connections past their ttl (runs in a new Thread)
90
+ def sweeper
91
+ Thread.new(@expiries, @available) do |exp, avail|
92
+ loop do
93
+ sleep 15
94
+ @lock.synchronize {
95
+ avail.each do |instance|
96
+ if exp[instance] < Time.now
97
+ avail.delete(instance)
98
+ exp.delete(instance)
99
+ instance.close
100
+ end
101
+ end
102
+ }
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+ end
109
+ end
@@ -65,11 +65,21 @@ module Oedipus
65
65
  # a Hash containing :host and :port
66
66
  #
67
67
  # The connection will be established on initialization.
68
+ #
69
+ # The underlying implementation uses a thread-safe connection pool.
68
70
  def initialize(options)
69
71
  options = options.kind_of?(String) ?
70
72
  Hash[ [:host, :port].zip(options.split(":")) ] :
71
73
  options
72
- @conn = Oedipus::Mysql.new(options[:host], options[:port].to_i)
74
+
75
+ @pool = Pool.new(
76
+ host: options[:host],
77
+ port: options[:port].to_i,
78
+ size: options.fetch(:pool_size, 8),
79
+ ttl: 60
80
+ )
81
+
82
+ assert_valid_pool
73
83
  end
74
84
 
75
85
  # Acess a specific index for querying.
@@ -96,7 +106,7 @@ module Oedipus
96
106
  #
97
107
  # Note that SphinxQL does not support prepared statements.
98
108
  def multi_query(sql)
99
- @conn.query(sql)
109
+ @pool.acquire { |conn| conn.query(sql) }
100
110
  end
101
111
 
102
112
  # Execute a single read query.
@@ -109,7 +119,7 @@ module Oedipus
109
119
  #
110
120
  # Note that SphinxQL does not support prepared statements.
111
121
  def query(sql)
112
- @conn.query(sql).first
122
+ @pool.acquire { |conn| conn.query(sql).first }
113
123
  end
114
124
 
115
125
  # Execute a non-read query.
@@ -122,7 +132,13 @@ module Oedipus
122
132
  #
123
133
  # Note that SphinxQL does not support prepared statements.
124
134
  def execute(sql)
125
- @conn.execute(sql)
135
+ @pool.acquire { |conn| conn.execute(sql) }
136
+ end
137
+
138
+ private
139
+
140
+ def assert_valid_pool
141
+ @pool.acquire { nil }
126
142
  end
127
143
  end
128
144
  end
@@ -8,5 +8,5 @@
8
8
  ##
9
9
 
10
10
  module Oedipus
11
- VERSION = "0.0.4"
11
+ VERSION = "0.0.5"
12
12
  end
data/lib/oedipus.rb CHANGED
@@ -29,6 +29,7 @@ require "oedipus/query_builder"
29
29
 
30
30
  require "oedipus/connection_error"
31
31
  require "oedipus/connection"
32
+ require "oedipus/connection/pool"
32
33
 
33
34
  require "oedipus/index"
34
35
 
@@ -23,8 +23,6 @@ describe Oedipus::Connection do
23
23
 
24
24
  before(:each) { empty_indexes }
25
25
 
26
- let(:conn) { Oedipus::Connection.new(searchd_host) }
27
-
28
26
  describe "#initialize" do
29
27
  context "with a hosname:port string" do
30
28
  context "on successful connection" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oedipus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-04-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &12876920 !ruby/object:Gem::Requirement
16
+ requirement: &14417400 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *12876920
24
+ version_requirements: *14417400
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake-compiler
27
- requirement: &12831220 !ruby/object:Gem::Requirement
27
+ requirement: &14717600 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *12831220
35
+ version_requirements: *14717600
36
36
  description: ! "== Sphinx 2 Comes to Ruby\n\nOedipus brings full support for Sphinx
37
37
  2 to Ruby:\n\n - real-time indexes (insert, replace, update, delete)\n - faceted
38
38
  search (variations on a base query)\n - multi-queries (multiple queries executed
@@ -70,6 +70,7 @@ files:
70
70
  - lib/oedipus/comparison/outside.rb
71
71
  - lib/oedipus/comparison/shortcuts.rb
72
72
  - lib/oedipus/connection.rb
73
+ - lib/oedipus/connection/pool.rb
73
74
  - lib/oedipus/connection_error.rb
74
75
  - lib/oedipus/index.rb
75
76
  - lib/oedipus/query_builder.rb
@@ -108,7 +109,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
108
109
  version: '0'
109
110
  segments:
110
111
  - 0
111
- hash: 765099216142211442
112
+ hash: 4166348847258820467
112
113
  required_rubygems_version: !ruby/object:Gem::Requirement
113
114
  none: false
114
115
  requirements:
@@ -117,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
118
  version: '0'
118
119
  segments:
119
120
  - 0
120
- hash: 765099216142211442
121
+ hash: 4166348847258820467
121
122
  requirements: []
122
123
  rubyforge_project: oedipus
123
124
  rubygems_version: 1.8.11