monga 0.0.2 → 0.0.3
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/.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
|
+
[](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
|