oedipus 0.0.4 → 0.0.5

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.
@@ -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