monga 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +1 -0
- data/README.md +59 -3
- data/lib/monga/client.rb +51 -6
- data/lib/monga/clients/master_slave_client.rb +0 -5
- data/lib/monga/clients/replica_set_client.rb +32 -71
- data/lib/monga/clients/single_instance_client.rb +53 -0
- data/lib/monga/collection.rb +102 -41
- data/lib/monga/connection.rb +38 -13
- data/lib/monga/connection_pool.rb +6 -17
- data/lib/monga/connections/buffer.rb +33 -0
- data/lib/monga/connections/em_connection.rb +25 -56
- data/lib/monga/connections/em_proxy_connection.rb +80 -0
- data/lib/monga/connections/fibered_connection.rb +26 -0
- data/lib/monga/connections/fibered_proxy_connection.rb +23 -0
- data/lib/monga/connections/proxy_connection.rb +4 -0
- data/lib/monga/connections/tcp_connection.rb +57 -0
- data/lib/monga/cursor.rb +197 -95
- data/lib/monga/database.rb +175 -60
- data/lib/monga/{requests → protocol}/delete.rb +1 -2
- data/lib/monga/{requests → protocol}/get_more.rb +1 -1
- data/lib/monga/{requests → protocol}/insert.rb +1 -2
- data/lib/monga/{requests → protocol}/kill_cursors.rb +1 -1
- data/lib/monga/{requests → protocol}/query.rb +3 -3
- data/lib/monga/{requests → protocol}/update.rb +1 -1
- data/lib/monga/request.rb +27 -23
- data/lib/monga/utils/constants.rb +5 -0
- data/lib/monga/utils/exceptions.rb +11 -0
- data/lib/monga.rb +19 -11
- data/monga.gemspec +2 -2
- data/spec/helpers/mongodb.rb +115 -38
- data/spec/monga/block/collection_spec.rb +172 -0
- data/spec/monga/block/cursor_spec.rb +160 -0
- data/spec/monga/block/database_spec.rb +80 -0
- data/spec/monga/block/single_instance_client_spec.rb +31 -0
- data/spec/monga/em/collection_spec.rb +308 -0
- data/spec/monga/em/cursor_spec.rb +256 -0
- data/spec/monga/em/database_spec.rb +140 -0
- data/spec/monga/em/replica_set_client_spec.rb +86 -0
- data/spec/monga/em/single_instance_client_spec.rb +28 -0
- data/spec/monga/sync/collection_spec.rb +247 -0
- data/spec/monga/sync/cursor_spec.rb +211 -0
- data/spec/monga/sync/database_spec.rb +110 -0
- data/spec/monga/sync/replica_set_client_spec.rb +54 -0
- data/spec/monga/sync/single_instance_client_spec.rb +25 -0
- data/spec/spec_helper.rb +2 -20
- metadata +50 -38
- data/lib/monga/clients/client.rb +0 -24
- data/lib/monga/connections/primary.rb +0 -46
- data/lib/monga/connections/secondary.rb +0 -13
- data/lib/monga/exceptions.rb +0 -9
- data/lib/monga/miner.rb +0 -72
- data/lib/monga/response.rb +0 -11
- data/spec/helpers/truncate.rb +0 -15
- data/spec/monga/collection_spec.rb +0 -448
- data/spec/monga/connection_pool_spec.rb +0 -50
- data/spec/monga/connection_spec.rb +0 -64
- data/spec/monga/cursor_spec.rb +0 -186
- data/spec/monga/database_spec.rb +0 -67
- data/spec/monga/replica_set_client_spec.rb +0 -46
- data/spec/monga/requests/delete_spec.rb +0 -0
- data/spec/monga/requests/insert_spec.rb +0 -0
- data/spec/monga/requests/query_spec.rb +0 -28
data/.gitignore
CHANGED
data/.travis.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
services: mongodb
|
data/README.md
CHANGED
@@ -1,11 +1,66 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/fl00r/monga.png?branch=master)](https://travis-ci.org/fl00r/monga)
|
2
|
+
|
1
3
|
# Monga
|
2
4
|
|
3
|
-
[MongoDB](http://www.mongodb.org/) Ruby Client on [EventMachine](https://github.com/eventmachine/eventmachine).
|
5
|
+
[MongoDB](http://www.mongodb.org/) Ruby Client on [EventMachine](https://github.com/eventmachine/eventmachine). Also it supports synchrony mode ([em-synchrony](https://github.com/igrigorik/em-synchrony)).
|
4
6
|
|
5
7
|
This client is under development. You can try [em-mongo](https://github.com/bcg/em-mongo).
|
6
8
|
|
7
9
|
Client supports MongoDB 2.4. Some features won't work in lower versions.
|
8
10
|
|
11
|
+
# Introduction
|
12
|
+
|
13
|
+
Monga supports asynchronous (over EventMachine), synchronous (Fibers) and blocking (TCPSocket) interfaces.
|
14
|
+
|
15
|
+
API will be familiar to Node.js developers: it returns `err, response` into callback.
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
# Async mode
|
19
|
+
EM.run do
|
20
|
+
connection = Monga::Client.new(host: "127.0.0.1", port: 27017, type: :em)
|
21
|
+
db = connection["dbTest"]
|
22
|
+
collection = db["testCollection"]
|
23
|
+
collection.safe_insert(title: "Test") do |err, resp|
|
24
|
+
if err
|
25
|
+
puts "Error happend: #{err.message}"
|
26
|
+
else
|
27
|
+
puts "saved!"
|
28
|
+
collection.find.all do |err, docs|
|
29
|
+
if err
|
30
|
+
puts "Error happend: #{err.message}"
|
31
|
+
else
|
32
|
+
puts "Docs fetched: #{docs.size}"
|
33
|
+
end
|
34
|
+
EM.stop
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Sync mode
|
41
|
+
EM.synchrony do
|
42
|
+
connection = Monga::Client.new(host: "127.0.0.1", port: 27017, type: :sync)
|
43
|
+
db = connection["dbTest"]
|
44
|
+
collection = db["testCollection"]
|
45
|
+
collection.safe_insert(title: "Test")
|
46
|
+
puts "saved"
|
47
|
+
docs = collection.find.all
|
48
|
+
puts "Docs fetched: #{docs.size}"
|
49
|
+
EM.stop
|
50
|
+
end
|
51
|
+
|
52
|
+
# Blocking mode
|
53
|
+
connection = Monga::Client.new(host: "127.0.0.1", port: 27017, type: :block)
|
54
|
+
db = connection["dbTest"]
|
55
|
+
collection = db["testCollection"]
|
56
|
+
collection.safe_insert(title: "Test")
|
57
|
+
puts "saved"
|
58
|
+
docs = collection.find.all
|
59
|
+
puts "Docs fetched: #{docs.size}"
|
60
|
+
```
|
61
|
+
|
62
|
+
README and WIKI is going to be written.
|
63
|
+
|
9
64
|
## To Do List
|
10
65
|
|
11
66
|
* [ ] Write a Wiki
|
@@ -46,13 +101,14 @@ Client supports MongoDB 2.4. Some features won't work in lower versions.
|
|
46
101
|
* [ ] check maxBsonSize / validate
|
47
102
|
* [x] cmd
|
48
103
|
* [x] eval
|
49
|
-
* [ ]
|
104
|
+
* [ ] aggregation
|
105
|
+
* [ ] gridfs?
|
50
106
|
|
51
107
|
### Collection
|
52
108
|
* QUERY_OP
|
53
109
|
* [x] find
|
54
110
|
* [x] find_one (first)
|
55
|
-
* [
|
111
|
+
* [x] sorting
|
56
112
|
* INSERT_OP
|
57
113
|
* [x] insert (single)
|
58
114
|
* [x] insert (batch)
|
data/lib/monga/client.rb
CHANGED
@@ -1,8 +1,53 @@
|
|
1
|
-
require File.expand_path("../clients/client", __FILE__)
|
2
|
-
require File.expand_path("../clients/replica_set_client", __FILE__)
|
3
|
-
require File.expand_path("../clients/master_slave_client", __FILE__)
|
4
1
|
module Monga
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
class Client
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegators :@client, :aquire_connection
|
6
|
+
|
7
|
+
VALID_OPTS = [:host, :port, :server, :type, :pool_size, :servers, :read_pref, :timeout]
|
8
|
+
|
9
|
+
# Following options are allowed
|
10
|
+
# * host - host of server to connect, default 127.0.0.1
|
11
|
+
# * port - port of server to connect, default 27017
|
12
|
+
# * server - host:port of server to connect (you can pass server or host/port pair)
|
13
|
+
# * type - :em/:sync/:block - socket type, asynchronouse on EventMachine, Fibered or blocking TCP
|
14
|
+
# * pool_size - connection pool size
|
15
|
+
# * servers - array of server names (host:port) to connect or array of hashes host/port (for Replica Set connection)
|
16
|
+
# * read_pref - read preference for Replica Set (:primary, :secondary, :primary_preferred, :secondary_preferred), default :primary
|
17
|
+
# * timeout - client will try to reconnect till timout (in seconds) if connection failed, default 10 seconds
|
18
|
+
def initialize(opts = {})
|
19
|
+
@opts = opts
|
20
|
+
@opts[:type] ||= :block
|
21
|
+
|
22
|
+
sanitize_opts!
|
23
|
+
create_client
|
24
|
+
end
|
25
|
+
|
26
|
+
# Choose database by it's name
|
27
|
+
def get_database(db_name)
|
28
|
+
Monga::Database.new(@client, db_name)
|
29
|
+
end
|
30
|
+
alias :[] :get_database
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# Validates incoming options to prevent missunderstanding
|
35
|
+
def sanitize_opts!
|
36
|
+
@opts.each_key do |key|
|
37
|
+
unless VALID_OPTS.include? key
|
38
|
+
raise Monga::Exceptions::InvalidClientOption, "`#{key}` is invalid option for Client. Following options are valid: #{VALID_OPTS * ', '}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# If servers options is defined it will create ReplicaSetClient,
|
44
|
+
# otherwise SingleInstanceClient will be created
|
45
|
+
def create_client
|
46
|
+
@client = if @opts[:servers]
|
47
|
+
Monga::Clients::ReplicaSetClient.new(@opts)
|
48
|
+
else
|
49
|
+
Monga::Clients::SingleInstanceClient.new(@opts)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
8
53
|
end
|
@@ -1,45 +1,35 @@
|
|
1
|
-
# How it works
|
2
|
-
# Replica Set tries to establish connections to all passed servers.
|
3
|
-
# Till no connection established it queues al queries inside it's
|
4
|
-
|
5
1
|
module Monga::Clients
|
6
2
|
class ReplicaSetClient
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
3
|
+
attr_reader :read_pref, :timeout, :clients
|
4
|
+
|
5
|
+
# ReplicaSetClient creates SingleInstanceClient to each server.
|
6
|
+
# Accepts
|
7
|
+
# * servers - you could pas them as a array of servers (['1.1.1.1:27017', '1.1.1.2:27017']), or as a array of hashes: ([{host: '1.1.1.1', port: 27017}, {host: '1.1.1.2', port: 27017}])
|
8
|
+
# * read_pref - read preferrence (:primary, :primary_preferred, :secondary, :secondary_preferred)
|
9
|
+
# * pool_size - connection pool size to each server
|
10
|
+
# * type - connection type (:em/:sync/:block)
|
11
|
+
def initialize(opts)
|
12
|
+
@timeout = opts[:timeout]
|
13
|
+
@read_pref = opts[:read_pref] || :primary
|
14
|
+
|
15
|
+
servers = opts.delete :servers
|
16
|
+
@clients = servers.map do |server|
|
17
|
+
case server
|
18
|
+
when Hash
|
19
|
+
Monga::Clients::SingleInstanceClient.new(opts.merge(server))
|
20
|
+
when String
|
21
|
+
h, p = server.split(":")
|
22
|
+
o = { host: h, port: p.to_i }
|
23
|
+
Monga::Clients::SingleInstanceClient.new(opts.merge(o))
|
17
24
|
end
|
18
25
|
end
|
19
|
-
end
|
20
|
-
|
21
|
-
include EM::Deferrable
|
22
|
-
|
23
|
-
attr_reader :servers, :clients
|
24
|
-
|
25
|
-
def initialize(opts = {})
|
26
|
-
@read_pref = opts.delete(:read_pref) || :primary
|
27
|
-
@servers = opts.delete(:servers)
|
28
|
-
raise ArgumentError, "servers option is not passed or empty" if @servers.empty?
|
29
|
-
|
30
|
-
@clients = @servers.map do |server|
|
31
|
-
Monga::Client.new(server.merge(opts))
|
32
|
-
end
|
33
|
-
|
34
|
-
@proxy_connection = ProxyConnection.new(self)
|
35
|
-
end
|
36
26
|
|
37
|
-
|
38
|
-
Monga::Database.new(self, db_name)
|
27
|
+
@proxy_connection = Monga::Connection.proxy_connection_class(opts[:type]).new(self)
|
39
28
|
end
|
40
29
|
|
30
|
+
# Aquires connection due to read_pref option
|
41
31
|
def aquire_connection
|
42
|
-
server
|
32
|
+
server = case @read_pref
|
43
33
|
when :primary
|
44
34
|
primary
|
45
35
|
when :secondary
|
@@ -49,53 +39,24 @@ module Monga::Clients
|
|
49
39
|
when :secondary_preferred
|
50
40
|
secondary || primary
|
51
41
|
when :nearest
|
52
|
-
|
42
|
+
raise ArgumentError, "nearest read preferrence is not implemented yet"
|
53
43
|
else
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
if server
|
59
|
-
if @deferred_status != :succeeded
|
60
|
-
set_deferred_status :succeeded
|
61
|
-
@proxy_connection.set_deferred_status :succeeded
|
62
|
-
end
|
63
|
-
else
|
64
|
-
if @deferred_status == :succeeded
|
65
|
-
set_deferred_status nil
|
66
|
-
@proxy_connection.set_deferred_status nil
|
67
|
-
end
|
44
|
+
raise ArgumentError, "`#{@read_pref}` is not valid read preferrence, use :primary, :primary_preferred, :secondary, or :secondary_preferred"
|
68
45
|
end
|
69
46
|
|
70
47
|
server || @proxy_connection
|
71
48
|
end
|
72
49
|
|
50
|
+
# Fetch primary server
|
73
51
|
def primary
|
74
|
-
|
75
|
-
|
76
|
-
find_primary!
|
77
|
-
end
|
78
|
-
prim
|
52
|
+
pr = @clients.detect{ |c| c.primary? && c.connected? }
|
53
|
+
pr.aquire_connection if pr
|
79
54
|
end
|
80
55
|
|
56
|
+
# Fetch secondary server
|
81
57
|
def secondary
|
82
|
-
@clients.select{ |c|
|
83
|
-
|
84
|
-
|
85
|
-
def find_primary!
|
86
|
-
unless @pending_primary
|
87
|
-
@pending_primary = true
|
88
|
-
@clients.each{ |c| c.find_primary! }
|
89
|
-
EM.add_timer(0.1) do
|
90
|
-
if primary
|
91
|
-
aquire_connection
|
92
|
-
@pending_primary = false
|
93
|
-
else
|
94
|
-
@pending_primary = false
|
95
|
-
find_primary!
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
58
|
+
sc = @clients.select{ |c| c.secondary? && c.connected? }.sample
|
59
|
+
sc.aquire_connection if sc
|
99
60
|
end
|
100
61
|
end
|
101
62
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Monga::Clients
|
2
|
+
class SingleInstanceClient
|
3
|
+
# Status will inform Replica Set client of current client's status
|
4
|
+
# primary/secondary/nil
|
5
|
+
attr_reader :status
|
6
|
+
|
7
|
+
def initialize(opts)
|
8
|
+
pool_size = opts[:pool_size]
|
9
|
+
if pool_size && pool_size > 1
|
10
|
+
@connection_pool = Monga::ConnectionPool.new(opts)
|
11
|
+
else
|
12
|
+
@connection = Monga::Connection.new(opts)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# If single connection then return it.
|
17
|
+
# If connection pool then aquire connection from pool.
|
18
|
+
# If connection is not connected, then status will be setted to nil.
|
19
|
+
def aquire_connection
|
20
|
+
conn = if @connection_pool
|
21
|
+
@connection_pool.aquire_connection
|
22
|
+
else
|
23
|
+
@connection
|
24
|
+
end
|
25
|
+
@status = nil unless conn.connected?
|
26
|
+
conn
|
27
|
+
end
|
28
|
+
|
29
|
+
def connected?
|
30
|
+
aquire_connection.connected?
|
31
|
+
end
|
32
|
+
|
33
|
+
# Check status of connection.
|
34
|
+
# If ReplicaSetClient can't find connection with read_pref status
|
35
|
+
# it will send foce_status! to all clients while timout happend
|
36
|
+
# or while preferred status will be returned
|
37
|
+
def force_status!
|
38
|
+
conn = aquire_connection
|
39
|
+
conn.is_master? do |status|
|
40
|
+
@status = status
|
41
|
+
yield(@status) if block_given?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def primary?
|
46
|
+
@status == :primary
|
47
|
+
end
|
48
|
+
|
49
|
+
def secondary?
|
50
|
+
@status == :secondary
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/monga/collection.rb
CHANGED
@@ -1,40 +1,50 @@
|
|
1
1
|
module Monga
|
2
2
|
class Collection
|
3
|
-
attr_reader :
|
3
|
+
attr_reader :collection_name
|
4
4
|
|
5
|
-
def initialize(db,
|
5
|
+
def initialize(db, collection_name)
|
6
6
|
@db = db
|
7
|
-
@
|
7
|
+
@collection_name = collection_name
|
8
8
|
end
|
9
9
|
|
10
|
-
|
10
|
+
# Querying database. It returns cursor.
|
11
|
+
# Alias to collection#query is colleciotn#find
|
12
|
+
#
|
13
|
+
# cursor = collection.find(title: "Madonna")
|
14
|
+
# # choose fields to return
|
15
|
+
# cursor = collection.find({ title: "Madonna" }, { track: 1 })
|
16
|
+
# # get all documents
|
17
|
+
# cursor.all{ |err, docs| docs.each{ |doc| puts doc } }
|
18
|
+
#
|
19
|
+
def query(query = {}, selector = {}, opts = {})
|
11
20
|
options = {}
|
12
21
|
options[:query] = query
|
13
|
-
options[:
|
14
|
-
options.merge!
|
15
|
-
Monga::
|
22
|
+
options[:selector] = selector
|
23
|
+
options.merge!(opts)
|
24
|
+
Monga::Cursor.create(connection, db_name, collection_name, options)
|
16
25
|
end
|
17
26
|
alias :find :query
|
18
27
|
|
19
|
-
def find_one(query = {},
|
28
|
+
def find_one(query = {}, selector = {}, opts = {})
|
20
29
|
options = {}
|
21
30
|
options[:query] = query
|
22
|
-
options[:
|
23
|
-
options.merge!
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
options[:selector] = selector
|
32
|
+
options.merge!(opts)
|
33
|
+
Monga::Cursor.create(connection, db_name, collection_name, options).first do |err, resp|
|
34
|
+
if block_given?
|
35
|
+
yield(err, resp)
|
36
|
+
else
|
37
|
+
err ? raise(err) : resp
|
38
|
+
end
|
29
39
|
end
|
30
40
|
end
|
31
41
|
alias :first :find_one
|
32
42
|
|
33
|
-
def insert(
|
43
|
+
def insert(document, opts = {})
|
34
44
|
options = {}
|
35
|
-
options[:documents] =
|
45
|
+
options[:documents] = document
|
36
46
|
options.merge!(opts)
|
37
|
-
Monga::
|
47
|
+
Monga::Protocol::Insert.new(connection, db_name, collection_name, options).perform
|
38
48
|
end
|
39
49
|
|
40
50
|
def update(query = {}, update = {}, flags = {})
|
@@ -42,67 +52,118 @@ module Monga
|
|
42
52
|
options[:query] = query
|
43
53
|
options[:update] = update
|
44
54
|
options.merge!(flags)
|
45
|
-
Monga::
|
55
|
+
Monga::Protocol::Update.new(connection, db_name, collection_name, options).perform
|
46
56
|
end
|
47
57
|
|
48
58
|
def delete(query = {}, opts = {})
|
49
59
|
options = {}
|
50
60
|
options[:query] = query
|
51
61
|
options.merge!(opts)
|
52
|
-
Monga::
|
62
|
+
Monga::Protocol::Delete.new(connection, db_name, collection_name, options).perform
|
53
63
|
end
|
54
64
|
alias :remove :delete
|
55
65
|
|
56
66
|
def ensure_index(keys, opts={})
|
57
67
|
doc = {}
|
58
|
-
doc
|
68
|
+
doc[:key] = keys
|
59
69
|
# Read docs about naming
|
60
70
|
doc[:name] ||= keys.to_a.flatten * "_"
|
61
|
-
doc[:
|
62
|
-
doc
|
63
|
-
Monga::
|
71
|
+
doc[:ns] = "#{db_name}.#{collection_name}"
|
72
|
+
doc.merge!(opts)
|
73
|
+
Monga::Protocol::Insert.new(connection, db_name, "system.indexes", {documents: doc}).perform
|
64
74
|
end
|
65
75
|
|
66
76
|
def drop_index(indexes)
|
67
|
-
@db.drop_indexes(@
|
77
|
+
@db.drop_indexes(@collection_name, indexes) do |err, resp|
|
78
|
+
if block_given?
|
79
|
+
yield(err, resp)
|
80
|
+
else
|
81
|
+
raise err if err
|
82
|
+
return resp
|
83
|
+
end
|
84
|
+
end
|
68
85
|
end
|
69
86
|
|
70
87
|
def drop_indexes
|
71
|
-
@db.drop_indexes(@
|
88
|
+
@db.drop_indexes(@collection_name, "*") do |err, resp|
|
89
|
+
if block_given?
|
90
|
+
yield(err, resp)
|
91
|
+
else
|
92
|
+
raise err if err
|
93
|
+
return resp
|
94
|
+
end
|
95
|
+
end
|
72
96
|
end
|
73
97
|
|
74
98
|
def get_indexes
|
75
|
-
Monga::
|
99
|
+
Monga::Cursor.create(connection, db_name, "system.indexes").all do |err, resp|
|
100
|
+
if block_given?
|
101
|
+
yield(err, resp)
|
102
|
+
else
|
103
|
+
raise err if err
|
104
|
+
return resp
|
105
|
+
end
|
106
|
+
end
|
76
107
|
end
|
77
108
|
|
78
109
|
def drop
|
79
|
-
@db.drop_collection(@
|
110
|
+
@db.drop_collection(@collection_name) do |err, resp|
|
111
|
+
if block_given?
|
112
|
+
yield(err, resp)
|
113
|
+
else
|
114
|
+
raise err if err
|
115
|
+
return resp
|
116
|
+
end
|
117
|
+
end
|
80
118
|
end
|
81
119
|
|
82
|
-
|
83
|
-
|
120
|
+
# You could pass query/limit/skip options
|
121
|
+
#
|
122
|
+
# count(query: {artist: "Madonna"}, limit: 10, skip: 0)
|
123
|
+
#
|
124
|
+
def count(opts = {})
|
125
|
+
@db.count(@collection_name, opts) do |err, resp|
|
126
|
+
if block_given?
|
127
|
+
yield(err, resp)
|
128
|
+
else
|
129
|
+
raise err if err
|
130
|
+
return resp
|
131
|
+
end
|
132
|
+
end
|
84
133
|
end
|
85
134
|
|
86
135
|
# Safe methods
|
87
136
|
[:update, :insert, :delete, :remove, :ensure_index].each do |meth|
|
88
137
|
class_eval <<-EOS
|
89
138
|
def safe_#{meth}(*args)
|
90
|
-
|
91
|
-
|
139
|
+
last = args.last
|
140
|
+
opts = {}
|
141
|
+
if Hash === last
|
142
|
+
[ :j, :w, :fsync, :wtimeout ].each do |k|
|
143
|
+
v = last.delete k
|
144
|
+
opts[k] = v if v
|
145
|
+
end
|
146
|
+
end
|
147
|
+
req = #{meth}(*args)
|
148
|
+
@db.raise_last_error(req.connection, opts) do |err, resp|
|
149
|
+
if block_given?
|
150
|
+
yield(err, resp)
|
151
|
+
else
|
152
|
+
err ? raise(err) : resp
|
153
|
+
end
|
92
154
|
end
|
93
155
|
end
|
94
156
|
EOS
|
95
157
|
end
|
96
158
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
response
|
159
|
+
private
|
160
|
+
|
161
|
+
def connection
|
162
|
+
@db.client.aquire_connection
|
163
|
+
end
|
164
|
+
|
165
|
+
def db_name
|
166
|
+
@db.name
|
106
167
|
end
|
107
168
|
end
|
108
169
|
end
|
data/lib/monga/connection.rb
CHANGED
@@ -1,23 +1,48 @@
|
|
1
|
-
require File.expand_path("../connections/em_connection", __FILE__)
|
2
|
-
require File.expand_path("../connections/primary", __FILE__)
|
3
|
-
require File.expand_path("../connections/secondary", __FILE__)
|
4
|
-
|
5
1
|
module Monga
|
6
2
|
class Connection
|
7
3
|
extend Forwardable
|
8
4
|
|
9
|
-
def_delegators :@connection, :connected?, :
|
5
|
+
def_delegators :@connection, :connected?, :responses, :send_command, :is_master?, :port
|
6
|
+
|
7
|
+
attr_reader :type
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
CONNECTIONS = {
|
10
|
+
em: Monga::Connections::EMConnection,
|
11
|
+
sync: Monga::Connections::FiberedConnection,
|
12
|
+
block: Monga::Connections::TCPConnection,
|
15
13
|
}
|
14
|
+
PROXY_CONNECTIONS = {
|
15
|
+
em: Monga::Connections::EMProxyConnection,
|
16
|
+
sync: Monga::Connections::FiberedProxyConnection,
|
17
|
+
block: Monga::Connections::ProxyConnection,
|
18
|
+
}
|
19
|
+
|
20
|
+
# Simple connection wrapper.
|
21
|
+
# Accpets
|
22
|
+
# * host/port or server
|
23
|
+
# * connection type
|
24
|
+
# * timeout
|
25
|
+
def initialize(opts)
|
26
|
+
@type = opts[:type]
|
27
|
+
|
28
|
+
host, port = if server = opts[:server]
|
29
|
+
h, p = server.split(":")
|
30
|
+
[h, p.to_i]
|
31
|
+
else
|
32
|
+
h = opts[:host] || Monga::DEFAULT_HOST
|
33
|
+
p = opts[:port] || Monga::DEFAULT_PORT
|
34
|
+
[h, p]
|
35
|
+
end
|
36
|
+
timeout = opts[:timeout]
|
37
|
+
|
38
|
+
conn_type = CONNECTIONS[@type]
|
39
|
+
raise Monga::Exceptions::WrongConnectionType, "Connection type `#{opts[:type]}` is non valid, choose one of: :em, :sync, or :block" unless conn_type
|
40
|
+
@connection = conn_type.connect(host, port, timeout)
|
41
|
+
end
|
16
42
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@connection = conn_class.connect(opts)
|
43
|
+
# Returns name of proxy_connection class
|
44
|
+
def self.proxy_connection_class(type)
|
45
|
+
PROXY_CONNECTIONS[type]
|
21
46
|
end
|
22
47
|
end
|
23
48
|
end
|
@@ -1,20 +1,18 @@
|
|
1
1
|
module Monga
|
2
|
-
class ConnectionPool
|
3
|
-
extend Forwardable
|
4
|
-
|
5
|
-
def_delegators :aquire_connection, :send_command
|
6
|
-
|
2
|
+
class ConnectionPool
|
7
3
|
attr_reader :connections
|
8
|
-
|
9
|
-
def initialize(opts
|
10
|
-
@connections = []
|
4
|
+
|
5
|
+
def initialize(opts)
|
11
6
|
pool_size = opts.delete :pool_size
|
12
7
|
|
8
|
+
@connections = []
|
13
9
|
pool_size.times do
|
14
10
|
@connections << Monga::Connection.new(opts)
|
15
11
|
end
|
16
12
|
end
|
17
13
|
|
14
|
+
# Aquires random connection with min waiting responses among connected.
|
15
|
+
# Otherwise return random disconnected one.
|
18
16
|
def aquire_connection
|
19
17
|
connected = @connections.select(&:connected?)
|
20
18
|
if connected.any?
|
@@ -25,14 +23,5 @@ module Monga
|
|
25
23
|
@connections.sample
|
26
24
|
end
|
27
25
|
end
|
28
|
-
|
29
|
-
def primary?
|
30
|
-
conn = aquire_connection
|
31
|
-
conn ? conn.master? : false
|
32
|
-
end
|
33
|
-
|
34
|
-
def connected?
|
35
|
-
@connections.any?(&:connected?)
|
36
|
-
end
|
37
26
|
end
|
38
27
|
end
|