monga 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +5 -1
- data/benchmarks/inserts.rb +159 -54
- data/lib/monga/collection.rb +57 -1
- data/lib/monga/connection.rb +27 -17
- data/lib/monga/connections/buffer.rb +52 -38
- data/lib/monga/connections/em_connection.rb +2 -0
- data/lib/monga/connections/kgio_connection.rb +28 -18
- data/lib/monga/database.rb +71 -4
- data/lib/monga/protocol/delete.rb +1 -1
- data/lib/monga/protocol/insert.rb +3 -2
- data/lib/monga/protocol/query.rb +2 -2
- data/lib/monga/protocol/update.rb +2 -2
- data/lib/monga.rb +1 -8
- data/monga.gemspec +6 -5
- data/spec/helpers/mongodb.rb +7 -13
- data/spec/monga/block/collection_spec.rb +44 -0
- data/spec/monga/em/collection_spec.rb +70 -0
- data/spec/monga/sync/collection_spec.rb +56 -0
- data/spec/spec_helper.rb +2 -0
- metadata +10 -27
- data/lib/monga/connections/tcp_connection.rb +0 -59
data/README.md
CHANGED
@@ -143,7 +143,11 @@ puts "We have got #{docs.size} documents in this pretty array"
|
|
143
143
|
* [ ] check maxBsonSize / validate
|
144
144
|
* [x] cmd
|
145
145
|
* [x] eval
|
146
|
-
* [
|
146
|
+
* [x] aggregate
|
147
|
+
* [x] distinct
|
148
|
+
* [x] group
|
149
|
+
* [x] mapReduce
|
150
|
+
* [x] text
|
147
151
|
* [ ] gridfs?
|
148
152
|
|
149
153
|
### Collection
|
data/benchmarks/inserts.rb
CHANGED
@@ -1,86 +1,191 @@
|
|
1
1
|
require 'benchmark'
|
2
|
-
require 'mongo'
|
3
|
-
require 'moped'
|
4
|
-
require File.expand_path('../../lib/monga', __FILE__)
|
5
2
|
|
6
|
-
|
3
|
+
TOTAL_INSERTS = 10000
|
4
|
+
TOTAL_READS = 50
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
moped_session.use "dbTest"
|
6
|
+
chars = ('a'..'z').to_a
|
7
|
+
DOCS = [10, 100, 1000, 10000].map do |size|
|
8
|
+
doc = {}
|
9
|
+
doc[:title] = "Title"
|
10
|
+
doc[:body] = size.times.map{ chars.sample }.join
|
11
|
+
[size, doc]
|
12
|
+
end
|
16
13
|
|
17
|
-
|
18
|
-
document[:title] = "Some title"
|
19
|
-
chars = ('a'..'z').to_a
|
20
|
-
document[:body] = 100.times.map{ chars.sample } * ""
|
14
|
+
# Mongo Ruby Driver
|
21
15
|
|
22
|
-
|
16
|
+
fork do
|
17
|
+
require 'mongo'
|
18
|
+
include Mongo
|
23
19
|
|
24
|
-
|
20
|
+
Benchmark.bm do |x|
|
21
|
+
collection = MongoClient.new.db("dbTest").collection("testCollection")
|
25
22
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
23
|
+
DOCS.each do |size, doc|
|
24
|
+
GC.start
|
25
|
+
x.report("Mongo: Inserting #{size}b document") do
|
26
|
+
TOTAL_INSERTS.times do
|
27
|
+
collection.insert(doc.dup)
|
28
|
+
end
|
29
|
+
end
|
31
30
|
|
32
|
-
|
31
|
+
GC.start
|
32
|
+
x.report("Mongo: Reading #{size}b documents") do
|
33
|
+
TOTAL_READS.times do
|
34
|
+
collection.find.to_a
|
35
|
+
end
|
36
|
+
end
|
33
37
|
|
34
|
-
|
35
|
-
fetch.times do
|
36
|
-
mongo_collection.find.to_a
|
38
|
+
collection.drop
|
37
39
|
end
|
38
40
|
end
|
39
|
-
|
41
|
+
end
|
40
42
|
|
41
|
-
|
43
|
+
Process.waitall
|
44
|
+
puts "---"*5
|
42
45
|
|
43
|
-
|
46
|
+
# Monga Driver (blocking mode)
|
44
47
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
fork do
|
49
|
+
require File.expand_path('../../lib/monga', __FILE__)
|
50
|
+
|
51
|
+
Benchmark.bm do |x|
|
52
|
+
collection = Monga::Client.new.get_database("dbTest").get_collection("testCollection")
|
53
|
+
|
54
|
+
DOCS.each do |size, doc|
|
55
|
+
GC.start
|
56
|
+
x.report("Monga: Inserting #{size}b document") do
|
57
|
+
TOTAL_INSERTS.times do
|
58
|
+
collection.safe_insert(doc)
|
59
|
+
end
|
60
|
+
end
|
50
61
|
|
51
|
-
|
62
|
+
GC.start
|
63
|
+
x.report("Monga: Reading #{size}b documents") do
|
64
|
+
TOTAL_READS.times do
|
65
|
+
collection.find.all
|
66
|
+
end
|
67
|
+
end
|
52
68
|
|
53
|
-
|
54
|
-
fetch.times do
|
55
|
-
monga_collection.find.all
|
69
|
+
collection.drop
|
56
70
|
end
|
57
71
|
end
|
72
|
+
end
|
58
73
|
|
59
|
-
|
74
|
+
Process.waitall
|
75
|
+
puts "---"*5
|
60
76
|
|
61
|
-
|
77
|
+
# Moped
|
62
78
|
|
63
|
-
|
79
|
+
fork do
|
80
|
+
require 'moped'
|
64
81
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
82
|
+
Benchmark.bm do |x|
|
83
|
+
session = Moped::Session.new([ "127.0.0.1:27017" ])
|
84
|
+
session.use("dbTest")
|
85
|
+
|
86
|
+
DOCS.each do |size, doc|
|
87
|
+
GC.start
|
88
|
+
x.report("Moped: Inserting #{size}b document") do
|
89
|
+
session.with(safe: true) do |safe|
|
90
|
+
TOTAL_INSERTS.times do
|
91
|
+
safe[:testCollection].insert(doc)
|
92
|
+
end
|
93
|
+
end
|
69
94
|
end
|
70
|
-
end
|
71
|
-
end
|
72
95
|
|
73
|
-
|
96
|
+
GC.start
|
97
|
+
x.report("Moped: Reading #{size}b documents") do
|
98
|
+
TOTAL_READS.times do
|
99
|
+
session[:testCollection].find.to_a
|
100
|
+
end
|
101
|
+
end
|
74
102
|
|
75
|
-
|
76
|
-
fetch.times do
|
77
|
-
moped_session[:testCollection].find.to_a
|
103
|
+
session[:testCollection].drop
|
78
104
|
end
|
79
105
|
end
|
80
|
-
|
81
|
-
monga_collection.drop
|
82
106
|
end
|
83
107
|
|
108
|
+
Process.waitall
|
109
|
+
|
110
|
+
# # require 'moped'
|
111
|
+
|
112
|
+
# # include Mongo
|
113
|
+
|
114
|
+
# Benchmark.bm do |x|
|
115
|
+
# total = 1000
|
116
|
+
# fetch = 50
|
117
|
+
# # mongo_collection = MongoClient.new.db("dbTest").collection("testCollection")
|
118
|
+
# monga_collection = Monga::Client.new(type: :block).get_database("dbTest").get_collection("testCollection")
|
119
|
+
# Monga.logger.level = Logger::ERROR
|
120
|
+
# # moped_session = Moped::Session.new([ "127.0.0.1:27017" ])
|
121
|
+
# # moped_session.use "dbTest"
|
122
|
+
|
123
|
+
# document = {}
|
124
|
+
# document[:title] = "Some title"
|
125
|
+
# document[:body] = 10000.times.map{ chars.sample } * ""
|
126
|
+
|
127
|
+
# # sleep 0.5
|
128
|
+
|
129
|
+
# # GC.start
|
130
|
+
|
131
|
+
# # x.report("Inserting with mongo") do
|
132
|
+
# # total.times do |i|
|
133
|
+
# # mongo_collection.insert(document.dup)
|
134
|
+
# # end
|
135
|
+
# # end
|
136
|
+
|
137
|
+
# # GC.start
|
138
|
+
|
139
|
+
# # x.report("Fetching with mongo") do
|
140
|
+
# # fetch.times do
|
141
|
+
# # mongo_collection.find.to_a
|
142
|
+
# # end
|
143
|
+
# # end
|
144
|
+
# # mongo_collection.drop
|
145
|
+
|
146
|
+
# # sleep 0.5
|
147
|
+
|
148
|
+
# # GC.start
|
149
|
+
|
150
|
+
# x.report("Inserting with monga") do
|
151
|
+
# total.times do |i|
|
152
|
+
# monga_collection.safe_insert(document)
|
153
|
+
# end
|
154
|
+
# end
|
155
|
+
|
156
|
+
# GC.start
|
157
|
+
|
158
|
+
# x.report("Fetching with monga") do
|
159
|
+
# fetch.times do
|
160
|
+
# monga_collection.find.all
|
161
|
+
# end
|
162
|
+
# end
|
163
|
+
|
164
|
+
# monga_collection.drop
|
165
|
+
|
166
|
+
# # sleep 0.5
|
167
|
+
|
168
|
+
# # GC.start
|
169
|
+
|
170
|
+
# # x.report("Inserting with moped") do
|
171
|
+
# # moped_session.with(safe: true) do |safe|
|
172
|
+
# # total.times do |i|
|
173
|
+
# # safe[:testCollection].insert(document)
|
174
|
+
# # end
|
175
|
+
# # end
|
176
|
+
# # end
|
177
|
+
|
178
|
+
# # GC.start
|
179
|
+
|
180
|
+
# # x.report("Fetching with moped") do
|
181
|
+
# # fetch.times do
|
182
|
+
# # moped_session[:testCollection].find.to_a
|
183
|
+
# # end
|
184
|
+
# # end
|
185
|
+
|
186
|
+
# # monga_collection.drop
|
187
|
+
# end
|
188
|
+
|
84
189
|
|
85
190
|
|
86
191
|
|
data/lib/monga/collection.rb
CHANGED
@@ -8,7 +8,7 @@ module Monga
|
|
8
8
|
end
|
9
9
|
|
10
10
|
# Querying database. It returns cursor.
|
11
|
-
# Alias to collection#query is
|
11
|
+
# Alias to collection#query is collection#find
|
12
12
|
#
|
13
13
|
# cursor = collection.find(title: "Madonna")
|
14
14
|
# # choose fields to return
|
@@ -132,6 +132,62 @@ module Monga
|
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|
135
|
+
def map_reduce(opts, &blk)
|
136
|
+
@db.map_reduce(@collection_name, opts) do |err, resp|
|
137
|
+
if block_given?
|
138
|
+
yield(err, resp)
|
139
|
+
else
|
140
|
+
raise err if err
|
141
|
+
return resp
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def aggregate(pipeline, &blk)
|
147
|
+
@db.aggregate(@collection_name, pipeline) do |err, resp|
|
148
|
+
if block_given?
|
149
|
+
yield(err, resp)
|
150
|
+
else
|
151
|
+
raise err if err
|
152
|
+
return resp
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def distinct(opts, &blk)
|
158
|
+
@db.distinct(collection_name, opts) do |err, resp|
|
159
|
+
if block_given?
|
160
|
+
yield(err, resp)
|
161
|
+
else
|
162
|
+
raise err if err
|
163
|
+
return resp
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def group(opts, &blk)
|
169
|
+
@db.group(collection_name, opts) do |err, resp|
|
170
|
+
if block_given?
|
171
|
+
yield(err, resp)
|
172
|
+
else
|
173
|
+
raise err if err
|
174
|
+
return resp
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def text(search, opts = {}, &blk)
|
180
|
+
opts[:search] = search
|
181
|
+
@db.text(collection_name, opts) do |err, resp|
|
182
|
+
if block_given?
|
183
|
+
yield(err, resp)
|
184
|
+
else
|
185
|
+
raise err if err
|
186
|
+
return resp
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
135
191
|
# Safe methods
|
136
192
|
[:update, :insert, :delete, :remove, :ensure_index].each do |meth|
|
137
193
|
class_eval <<-EOS
|
data/lib/monga/connection.rb
CHANGED
@@ -6,17 +6,6 @@ module Monga
|
|
6
6
|
|
7
7
|
attr_reader :type
|
8
8
|
|
9
|
-
CONNECTIONS = {
|
10
|
-
em: Monga::Connections::EMConnection,
|
11
|
-
sync: Monga::Connections::FiberedConnection,
|
12
|
-
block: Monga::Connections::KGIOConnection,
|
13
|
-
}
|
14
|
-
PROXY_CONNECTIONS = {
|
15
|
-
em: Monga::Connections::EMProxyConnection,
|
16
|
-
sync: Monga::Connections::FiberedProxyConnection,
|
17
|
-
block: Monga::Connections::ProxyConnection,
|
18
|
-
}
|
19
|
-
|
20
9
|
# Simple connection wrapper.
|
21
10
|
# Accpets
|
22
11
|
# * host/port or server
|
@@ -35,15 +24,36 @@ module Monga
|
|
35
24
|
end
|
36
25
|
timeout = opts[:timeout]
|
37
26
|
|
38
|
-
|
39
|
-
|
40
|
-
|
27
|
+
@connection = case @type
|
28
|
+
when :em
|
29
|
+
require File.expand_path("../connections/em_connection", __FILE__)
|
30
|
+
Monga::Connections::EMConnection.connect(host, port, timeout)
|
31
|
+
when :sync
|
32
|
+
require File.expand_path("../connections/em_connection", __FILE__)
|
33
|
+
require File.expand_path("../connections/fibered_connection", __FILE__)
|
34
|
+
Monga::Connections::FiberedConnection.connect(host, port, timeout)
|
35
|
+
when :block
|
36
|
+
require File.expand_path("../connections/kgio_connection", __FILE__)
|
37
|
+
Monga::Connections::KGIOConnection.connect(host, port, timeout)
|
38
|
+
else
|
39
|
+
raise Monga::Exceptions::WrongConnectionType, "Connection type `#{opts[:type]}` is non valid, choose one of: :em, :sync, or :block" unless conn_type
|
40
|
+
end
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
# Returns name of proxy_connection class
|
44
44
|
def self.proxy_connection_class(type, client)
|
45
|
-
|
46
|
-
|
45
|
+
case type
|
46
|
+
when :em
|
47
|
+
require File.expand_path("../connections/em_proxy_connection", __FILE__)
|
48
|
+
Monga::Connections::EMProxyConnection.new(client)
|
49
|
+
when :sync
|
50
|
+
require File.expand_path("../connections/em_proxy_connection", __FILE__)
|
51
|
+
require File.expand_path("../connections/fibered_proxy_connection", __FILE__)
|
52
|
+
Monga::Connections::FiberedProxyConnection.new(client)
|
53
|
+
when :block
|
54
|
+
require File.expand_path("../connections/proxy_connection", __FILE__)
|
55
|
+
Monga::Connections::ProxyConnection.new(client)
|
56
|
+
end
|
47
57
|
end
|
48
58
|
end
|
49
59
|
end
|
@@ -1,33 +1,54 @@
|
|
1
1
|
module Monga::Connections
|
2
2
|
class Buffer
|
3
|
-
|
3
|
+
include Enumerable
|
4
|
+
EMPTY = ""
|
4
5
|
|
5
|
-
attr_reader :buffer, :
|
6
|
+
attr_reader :buffer, :buffer_size
|
6
7
|
|
7
8
|
def initialize
|
8
9
|
@buffer = ""
|
9
10
|
@position = 0
|
10
|
-
@
|
11
|
-
@
|
11
|
+
@buffer_size = 0
|
12
|
+
@response = []
|
12
13
|
end
|
13
14
|
|
14
15
|
def append(data)
|
15
16
|
@buffer << data
|
16
|
-
@buffer_size
|
17
|
-
|
18
|
-
|
17
|
+
@buffer_size += data.bytesize
|
18
|
+
end
|
19
|
+
|
20
|
+
def each
|
21
|
+
while doc = parse_buffer
|
22
|
+
yield doc
|
23
|
+
end
|
19
24
|
end
|
20
25
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
+
def parse_buffer
|
27
|
+
return if @buffer_size == 0
|
28
|
+
|
29
|
+
if @position == 0
|
30
|
+
parse_doc if parse_meta
|
31
|
+
else
|
32
|
+
parse_doc
|
33
|
+
end
|
34
|
+
|
35
|
+
if @number_returned == 0
|
36
|
+
if @buffer_size == @position
|
37
|
+
@buffer.clear
|
38
|
+
@buffer_size = 0
|
39
|
+
else
|
40
|
+
@buffer = @buffer[@position, @buffer_size-@position]
|
41
|
+
@buffer_size -= @position
|
42
|
+
end
|
43
|
+
@position = 0
|
44
|
+
|
45
|
+
@response
|
46
|
+
end
|
26
47
|
end
|
27
48
|
|
28
49
|
def parse_meta
|
29
50
|
return if @buffer_size < 36
|
30
|
-
@response
|
51
|
+
@response.clear
|
31
52
|
@response << ::BinUtils.get_int32_le(@buffer, @position)
|
32
53
|
@response << ::BinUtils.get_int32_le(@buffer, @position += 4)
|
33
54
|
@response << ::BinUtils.get_int32_le(@buffer, @position += 4)
|
@@ -35,43 +56,36 @@ module Monga::Connections
|
|
35
56
|
@response << ::BinUtils.get_int32_le(@buffer, @position += 4)
|
36
57
|
@response << ::BinUtils.get_int64_le(@buffer, @position += 4)
|
37
58
|
@response << ::BinUtils.get_int32_le(@buffer, @position += 8)
|
38
|
-
@
|
59
|
+
@number_returned = ::BinUtils.get_int32_le(@buffer, @position += 4)
|
60
|
+
@response << @number_returned
|
61
|
+
@position += 4
|
39
62
|
@response << []
|
40
63
|
|
41
|
-
@position += 4
|
42
64
|
end
|
43
65
|
|
44
66
|
def parse_doc
|
45
|
-
|
46
|
-
break if done
|
47
|
-
break if @buffer_size < @position + 4
|
48
|
-
doc_length = ::BinUtils.get_int32_le(@buffer, @position)
|
49
|
-
break if @buffer_size < @position + doc_length
|
67
|
+
@str_io = nil if @number_returned == @response[7]
|
50
68
|
|
51
|
-
|
52
|
-
|
53
|
-
@position
|
69
|
+
current_pos = @position
|
70
|
+
while (l = @buffer_size - @position) > 4
|
71
|
+
doc_length = ::BinUtils.get_int32_le(@buffer, @position)
|
72
|
+
break if l < doc_length
|
54
73
|
@number_returned -= 1
|
74
|
+
@position += doc_length
|
55
75
|
end
|
56
|
-
end
|
57
76
|
|
58
|
-
|
59
|
-
|
60
|
-
|
77
|
+
if @str_io
|
78
|
+
@str_io << @buffer[current_pos..@position]
|
79
|
+
else
|
80
|
+
@str_io = StringIO.new @buffer[current_pos..@position]
|
61
81
|
end
|
62
|
-
end
|
63
82
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
@buffer.clear
|
70
|
-
else
|
71
|
-
@buffer = @buffer[@position, @buffer_size-@position]
|
83
|
+
if @number_returned == 0
|
84
|
+
@str_io.rewind
|
85
|
+
@response[7].times do
|
86
|
+
@response[-1] << BSON::Document.from_bson(@str_io)
|
87
|
+
end
|
72
88
|
end
|
73
|
-
@buffer_size = @buffer.bytesize
|
74
|
-
@position = 0
|
75
89
|
end
|
76
90
|
end
|
77
91
|
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
require 'kgio'
|
2
|
-
|
2
|
+
|
3
|
+
# Toy blocking connection over TCP
|
3
4
|
module Monga::Connections
|
4
5
|
class KGIOConnection
|
6
|
+
TO_RECV = 512
|
7
|
+
|
5
8
|
def self.connect(host, port, timeout)
|
6
9
|
new(host, port, timeout)
|
7
10
|
end
|
@@ -10,6 +13,7 @@ module Monga::Connections
|
|
10
13
|
@host, @port, @timout = host, port, timeout
|
11
14
|
@connected = true
|
12
15
|
@buffer = Buffer.new
|
16
|
+
@tmp = ""
|
13
17
|
end
|
14
18
|
|
15
19
|
def connected?
|
@@ -20,10 +24,10 @@ module Monga::Connections
|
|
20
24
|
def socket
|
21
25
|
@socket ||= begin
|
22
26
|
sock = Kgio::TCPSocket.new(@host, @port)
|
27
|
+
# MacOS doesn't support autopush
|
23
28
|
sock.kgio_autopush = true unless RUBY_PLATFORM['darwin']
|
24
29
|
# check connection
|
25
30
|
sock.kgio_write ""
|
26
|
-
# Macos doesn't support autopush
|
27
31
|
@connected = true
|
28
32
|
sock
|
29
33
|
end
|
@@ -31,18 +35,19 @@ module Monga::Connections
|
|
31
35
|
nil
|
32
36
|
end
|
33
37
|
|
34
|
-
# Fake answer, as far as we are blocking
|
38
|
+
# Fake answer, as far as we are blocking,
|
39
|
+
# but we should support API
|
35
40
|
def responses
|
36
41
|
0
|
37
42
|
end
|
38
43
|
|
39
44
|
def send_command(msg, request_id=nil, &cb)
|
40
45
|
raise Errno::ECONNREFUSED, "Connection Refused" unless socket
|
41
|
-
socket.kgio_write msg
|
46
|
+
socket.kgio_write msg
|
42
47
|
if cb
|
43
48
|
read_socket
|
44
49
|
|
45
|
-
message = @buffer.
|
50
|
+
message = @buffer.first
|
46
51
|
rid = message[2]
|
47
52
|
|
48
53
|
fail "Returned Request Id is not equal to sended one (#{rid} != #{request_id}), #{message}" if rid != request_id
|
@@ -58,19 +63,24 @@ module Monga::Connections
|
|
58
63
|
end
|
59
64
|
|
60
65
|
def read_socket
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
size
|
70
|
-
|
71
|
-
|
66
|
+
while @buffer.buffer_size < 4
|
67
|
+
unless socket.kgio_read(TO_RECV, @tmp)
|
68
|
+
raise Errno::ECONNREFUSED.new "Nil was return. Closing connection"
|
69
|
+
end
|
70
|
+
|
71
|
+
@buffer.append(@tmp)
|
72
|
+
|
73
|
+
size = @buffer.buffer_size
|
74
|
+
if size >= 4
|
75
|
+
length = ::BinUtils.get_int32_le(@buffer.buffer)
|
76
|
+
|
77
|
+
torecv = length - size
|
78
|
+
if torecv > 0
|
79
|
+
socket.read(torecv, @tmp)
|
80
|
+
@buffer.append(@tmp)
|
81
|
+
end
|
82
|
+
end
|
72
83
|
end
|
73
|
-
@buffer.append(buf)
|
74
84
|
end
|
75
85
|
|
76
86
|
def primary?
|
@@ -83,7 +93,7 @@ module Monga::Connections
|
|
83
93
|
request_id = req.request_id
|
84
94
|
socket.kgio_write command
|
85
95
|
read_socket
|
86
|
-
message = @buffer.
|
96
|
+
message = @buffer.first
|
87
97
|
@primary = message.last.first["ismaster"]
|
88
98
|
yield @primary ? :primary : :secondary
|
89
99
|
rescue => e
|
data/lib/monga/database.rb
CHANGED
@@ -146,12 +146,79 @@ module Monga
|
|
146
146
|
run_cmd(cmd, blk)
|
147
147
|
end
|
148
148
|
|
149
|
-
|
150
|
-
|
149
|
+
# Run mapReduce command.
|
150
|
+
# Available options:
|
151
|
+
#
|
152
|
+
# * map - A JavaScript function that associates or “maps” a value with a key and emits the key and value pair.
|
153
|
+
# * reduce - A JavaScript function that “reduces” to a single object all the values associated with a particular key.
|
154
|
+
# * out - Specifies the location of the result of the map-reduce operation.
|
155
|
+
# * query - Specifies the selection criteria.
|
156
|
+
# * sort - Sorts the input documents.
|
157
|
+
# * limit - Specifies a maximum number of documents to return from the collection
|
158
|
+
# * finalize
|
159
|
+
# * scope
|
160
|
+
# * jsMode
|
161
|
+
# * verbose
|
162
|
+
#
|
163
|
+
# Inline response returned by default.
|
164
|
+
#
|
165
|
+
def map_reduce(collection_name, opts, &blk)
|
166
|
+
cmd = {}
|
167
|
+
cmd[:mapReduce] = collection_name
|
168
|
+
cmd.merge! opts
|
169
|
+
cmd[:out] ||= { inline: 1 }
|
170
|
+
run_cmd(cmd, blk)
|
151
171
|
end
|
152
172
|
|
153
|
-
|
154
|
-
|
173
|
+
# Run aggregate command.
|
174
|
+
#
|
175
|
+
def aggregate(collection_name, pipeline, &blk)
|
176
|
+
cmd = {}
|
177
|
+
cmd[:aggregate] = collection_name
|
178
|
+
cmd[:pipeline] = pipeline
|
179
|
+
run_cmd(cmd, blk)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Run distinct command.
|
183
|
+
# You should pass collection_name and key.
|
184
|
+
# Query option is optional.
|
185
|
+
#
|
186
|
+
def distinct(collection_name, opts, &blk)
|
187
|
+
cmd = {}
|
188
|
+
cmd[:distinct] = collection_name
|
189
|
+
cmd.merge! opts
|
190
|
+
run_cmd(cmd, blk)
|
191
|
+
end
|
192
|
+
|
193
|
+
# Run group command.
|
194
|
+
# Available options are:
|
195
|
+
# key – Specifies one or more document fields to group
|
196
|
+
# $reduce – Specifies an aggregation function that operates on the documents during the grouping operation
|
197
|
+
# initial – Initializes the aggregation result document
|
198
|
+
# $keyf – Specifies a function that creates a “key object” for use as the grouping key
|
199
|
+
# cond – Specifies the selection criteria to determine which documents in the collection to process
|
200
|
+
# finalize – Specifies a function that runs each item in the result
|
201
|
+
#
|
202
|
+
def group(collection_name, opts, &blk)
|
203
|
+
cmd = {}
|
204
|
+
cmd[:group] = opts
|
205
|
+
cmd[:group][:ns] ||= collection_name
|
206
|
+
run_cmd(cmd, blk)
|
207
|
+
end
|
208
|
+
|
209
|
+
# Run text command.
|
210
|
+
# Available options are:
|
211
|
+
# search (string) – A string of terms that MongoDB parses and uses to query the text index
|
212
|
+
# filter (document) – A query document to further limit the results of the query using another database field
|
213
|
+
# project (document) – Allows you to limit the fields returned by the query to only those specified.
|
214
|
+
# limit (number) – Specify the maximum number of documents to include in the response
|
215
|
+
# language (string) – Specify the language that determines for the search the list of stop words and the rules for the stemmer and tokenizer
|
216
|
+
#
|
217
|
+
def text(collection_name, opts, &blk)
|
218
|
+
cmd = {}
|
219
|
+
cmd[:text] = collection_name
|
220
|
+
cmd.merge! opts
|
221
|
+
run_cmd(cmd, blk)
|
155
222
|
end
|
156
223
|
|
157
224
|
# Just helper to show all list of collections
|
@@ -15,10 +15,11 @@ module Monga::Protocol
|
|
15
15
|
case documents
|
16
16
|
when Array
|
17
17
|
documents.each do |doc|
|
18
|
-
msg <<
|
18
|
+
msg << doc.to_bson
|
19
19
|
end
|
20
20
|
when Hash
|
21
|
-
msg << BSON::BSON_C.serialize(documents).to_s
|
21
|
+
# msg << BSON::BSON_C.serialize(documents).to_s
|
22
|
+
msg << documents.to_bson
|
22
23
|
end
|
23
24
|
msg
|
24
25
|
end
|
data/lib/monga/protocol/query.rb
CHANGED
@@ -26,8 +26,8 @@ module Monga::Protocol
|
|
26
26
|
msg = ::BinUtils.append_int32_le!(nil, flags)
|
27
27
|
msg << full_name << Monga::NULL_BYTE
|
28
28
|
::BinUtils.append_int32_le!(msg, skip, limit)
|
29
|
-
msg <<
|
30
|
-
msg <<
|
29
|
+
msg << query.to_bson
|
30
|
+
msg << selector.to_bson if selector.any?
|
31
31
|
msg
|
32
32
|
end
|
33
33
|
end
|
@@ -15,8 +15,8 @@ module Monga::Protocol
|
|
15
15
|
msg = ::BinUtils.append_int32_le!(nil, 0)
|
16
16
|
msg << full_name << Monga::NULL_BYTE
|
17
17
|
::BinUtils.append_int32_le!(msg, flags)
|
18
|
-
msg <<
|
19
|
-
msg <<
|
18
|
+
msg << query.to_bson
|
19
|
+
msg << update.to_bson
|
20
20
|
msg
|
21
21
|
end
|
22
22
|
end
|
data/lib/monga.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
gem "bson", "2.0.0.beta"
|
2
2
|
require "bson"
|
3
3
|
require "bin_utils"
|
4
4
|
require "logger"
|
@@ -21,13 +21,6 @@ require File.expand_path("../monga/cursor", __FILE__)
|
|
21
21
|
|
22
22
|
require File.expand_path("../monga/clients/single_instance_client", __FILE__)
|
23
23
|
require File.expand_path("../monga/clients/replica_set_client", __FILE__)
|
24
|
-
require File.expand_path("../monga/connections/em_connection", __FILE__)
|
25
|
-
require File.expand_path("../monga/connections/fibered_connection", __FILE__)
|
26
|
-
require File.expand_path("../monga/connections/tcp_connection", __FILE__)
|
27
|
-
require File.expand_path("../monga/connections/kgio_connection", __FILE__)
|
28
|
-
require File.expand_path("../monga/connections/em_proxy_connection", __FILE__)
|
29
|
-
require File.expand_path("../monga/connections/fibered_proxy_connection", __FILE__)
|
30
|
-
require File.expand_path("../monga/connections/proxy_connection", __FILE__)
|
31
24
|
require File.expand_path("../monga/connections/buffer", __FILE__)
|
32
25
|
|
33
26
|
require File.expand_path("../monga/client", __FILE__)
|
data/monga.gemspec
CHANGED
@@ -4,11 +4,11 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "monga"
|
7
|
-
spec.version = "0.0.
|
7
|
+
spec.version = "0.0.7"
|
8
8
|
spec.authors = ["Petr Yanovich"]
|
9
9
|
spec.email = ["fl00r@yandex.ru"]
|
10
|
-
spec.description = %q{MongoDB Ruby
|
11
|
-
spec.summary = %q{MongoDB Ruby
|
10
|
+
spec.description = %q{Yet another MongoDB Ruby Client}
|
11
|
+
spec.summary = %q{Yet another MongoDB Ruby Client}
|
12
12
|
spec.homepage = ""
|
13
13
|
spec.license = "MIT"
|
14
14
|
|
@@ -22,7 +22,8 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency "kgio"
|
23
23
|
spec.add_development_dependency "em-synchrony"
|
24
24
|
|
25
|
-
spec.add_dependency "bson"
|
26
|
-
spec.add_dependency "
|
25
|
+
spec.add_dependency "bson", ["~> 2.0.0.beta"]
|
26
|
+
# spec.add_dependency "bson"
|
27
|
+
# spec.add_dependency "bson_ext"
|
27
28
|
spec.add_dependency "bin_utils"
|
28
29
|
end
|
data/spec/helpers/mongodb.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'eventmachine'
|
2
2
|
|
3
|
+
module Fake
|
3
4
|
# Fake Response.
|
4
5
|
# It could be `ok`, or `primary?` reply.
|
5
6
|
class Response
|
@@ -11,12 +12,10 @@ module Fake
|
|
11
12
|
def ok(doc = nil)
|
12
13
|
document = doc || { ok: 1.0 }
|
13
14
|
[flags, cursor_id, starting_from, number_returned].pack("LQLL")
|
14
|
-
b =
|
15
|
-
|
16
|
-
|
17
|
-
b.
|
18
|
-
b.put_int(number_returned)
|
19
|
-
b.append!(BSON::BSON_C.serialize(document).to_s)
|
15
|
+
b = ::BinUtils.append_int32_le!(nil, flags)
|
16
|
+
::BinUtils.append_int64_le!(b, cursor_id)
|
17
|
+
::BinUtils.append_int32_le!(b, starting_from, number_returned)
|
18
|
+
b << document.to_bson
|
20
19
|
|
21
20
|
header(b) + b.to_s
|
22
21
|
end
|
@@ -33,12 +32,7 @@ module Fake
|
|
33
32
|
request_id = 0
|
34
33
|
op_code = 0
|
35
34
|
|
36
|
-
h =
|
37
|
-
h.put_int(length)
|
38
|
-
h.put_int(request_id)
|
39
|
-
h.put_int(response_to)
|
40
|
-
h.put_int(op_code)
|
41
|
-
h.to_s
|
35
|
+
h = ::BinUtils.append_int32_le!(nil, flags, request_id, response_to, op_code)
|
42
36
|
end
|
43
37
|
|
44
38
|
def response_to
|
@@ -169,4 +169,48 @@ describe Monga::Collection do
|
|
169
169
|
docs.select{ |d| d["ns"] == "dbTest.testCollection" }.size.must_equal 1
|
170
170
|
end
|
171
171
|
end
|
172
|
+
|
173
|
+
# MAP/REDUCE
|
174
|
+
|
175
|
+
describe "map_reduce" do
|
176
|
+
before do
|
177
|
+
@collection.safe_remove
|
178
|
+
5.times do |i|
|
179
|
+
@collection.safe_insert(title: "The Book", count: i)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should run map reduce" do
|
184
|
+
map_func = "function() {
|
185
|
+
emit(this.title, this.count);
|
186
|
+
};"
|
187
|
+
red_func = "function(docTitle, docCount) {
|
188
|
+
return Array.sum(docCount);
|
189
|
+
};"
|
190
|
+
@collection.map_reduce(map: map_func, reduce: red_func, out: {inline: 1} )["results"].first["value"].must_equal 10.0
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# AGGREGATE, GROUP, DISTINCT
|
195
|
+
|
196
|
+
describe "aggregate, group, distinct" do
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
# TEXT SEARCH
|
201
|
+
|
202
|
+
# Travis.ci doesn't support text search in mongodb
|
203
|
+
# describe "text search" do
|
204
|
+
# before do
|
205
|
+
# @collection.safe_ensure_index(author: "text")
|
206
|
+
# @collection.safe_insert(author: "Lady Gaga", track: "No. 1")
|
207
|
+
# @collection.safe_insert(author: "Lady Gaga", track: "No. 2")
|
208
|
+
# @collection.safe_insert(author: "Madonna", track: "No. 1")
|
209
|
+
# end
|
210
|
+
|
211
|
+
# it "should find some tracks" do
|
212
|
+
# @collection.text("Lady")["results"].map{ |r| r["obj"]["track"] }.sort.must_equal ["No. 1", "No. 2"]
|
213
|
+
# @collection.text("Madonna")["results"].map{ |r| r["obj"]["track"] }.sort.must_equal ["No. 1"]
|
214
|
+
# end
|
215
|
+
# end
|
172
216
|
end
|
@@ -305,4 +305,74 @@ describe Monga::Collection do
|
|
305
305
|
end
|
306
306
|
end
|
307
307
|
end
|
308
|
+
|
309
|
+
# MAP/REDUCE
|
310
|
+
|
311
|
+
describe "map_reduce" do
|
312
|
+
before do
|
313
|
+
EM.run do
|
314
|
+
@collection.safe_remove do
|
315
|
+
docs = []
|
316
|
+
5.times do |i|
|
317
|
+
docs << { title: "The Book", count: i }
|
318
|
+
end
|
319
|
+
@collection.safe_insert(docs) do
|
320
|
+
EM.stop
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
it "should run map reduce" do
|
327
|
+
EM.run do
|
328
|
+
map_func = "function() {
|
329
|
+
emit(this.title, this.count);
|
330
|
+
};"
|
331
|
+
red_func = "function(docTitle, docCount) {
|
332
|
+
return Array.sum(docCount);
|
333
|
+
};"
|
334
|
+
@collection.map_reduce(map: map_func, reduce: red_func, out: {inline: 1} ) do |err, res|
|
335
|
+
res["results"].first["value"].must_equal 10.0
|
336
|
+
EM.stop
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
# AGGREGATE, GROUP, DISTINCT
|
343
|
+
|
344
|
+
describe "aggregate, group, distinct" do
|
345
|
+
|
346
|
+
end
|
347
|
+
|
348
|
+
# TEXT SEARCH
|
349
|
+
|
350
|
+
# Travis.ci doesn't support text search in mongodb
|
351
|
+
# describe "text search" do
|
352
|
+
# before do
|
353
|
+
# EM.run do
|
354
|
+
# @collection.safe_ensure_index(author: "text") do
|
355
|
+
# @collection.safe_insert([
|
356
|
+
# { author: "Lady Gaga", track: "No. 1" },
|
357
|
+
# { author: "Lady Gaga", track: "No. 2" },
|
358
|
+
# { author: "Madonna", track: "No. 1" }
|
359
|
+
# ]) do
|
360
|
+
# EM.stop
|
361
|
+
# end
|
362
|
+
# end
|
363
|
+
# end
|
364
|
+
# end
|
365
|
+
|
366
|
+
# it "should find some tracks" do
|
367
|
+
# EM.run do
|
368
|
+
# @collection.text("Lady") do |err, res|
|
369
|
+
# res["results"].map{ |r| r["obj"]["track"] }.sort.must_equal ["No. 1", "No. 2"]
|
370
|
+
# @collection.text("Madonna") do |err, res|
|
371
|
+
# res["results"].map{ |r| r["obj"]["track"] }.sort.must_equal ["No. 1"]
|
372
|
+
# EM.stop
|
373
|
+
# end
|
374
|
+
# end
|
375
|
+
# end
|
376
|
+
# end
|
377
|
+
# end
|
308
378
|
end
|
@@ -244,4 +244,60 @@ describe Monga::Collection do
|
|
244
244
|
end
|
245
245
|
end
|
246
246
|
end
|
247
|
+
|
248
|
+
# MAP/REDUCE
|
249
|
+
|
250
|
+
describe "map_reduce" do
|
251
|
+
before do
|
252
|
+
EM.synchrony do
|
253
|
+
@collection.safe_remove
|
254
|
+
5.times do |i|
|
255
|
+
@collection.safe_insert(title: "The Book", count: i)
|
256
|
+
end
|
257
|
+
EM.stop
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should run map reduce" do
|
262
|
+
EM.synchrony do
|
263
|
+
map_func = "function() {
|
264
|
+
emit(this.title, this.count);
|
265
|
+
};"
|
266
|
+
red_func = "function(docTitle, docCount) {
|
267
|
+
return Array.sum(docCount);
|
268
|
+
};"
|
269
|
+
@collection.map_reduce(map: map_func, reduce: red_func, out: {inline: 1} )["results"].first["value"].must_equal 10.0
|
270
|
+
EM.stop
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
# AGGREGATE, GROUP, DISTINCT
|
276
|
+
|
277
|
+
describe "aggregate, group, distinct" do
|
278
|
+
|
279
|
+
end
|
280
|
+
|
281
|
+
# TEXT SEARCH
|
282
|
+
|
283
|
+
# Travis.ci doesn't support text search in mongodb
|
284
|
+
# describe "text search" do
|
285
|
+
# before do
|
286
|
+
# EM.synchrony do
|
287
|
+
# @collection.safe_ensure_index(author: "text")
|
288
|
+
# @collection.safe_insert(author: "Lady Gaga", track: "No. 1")
|
289
|
+
# @collection.safe_insert(author: "Lady Gaga", track: "No. 2")
|
290
|
+
# @collection.safe_insert(author: "Madonna", track: "No. 1")
|
291
|
+
# EM.stop
|
292
|
+
# end
|
293
|
+
# end
|
294
|
+
|
295
|
+
# it "should find some tracks" do
|
296
|
+
# EM.synchrony do
|
297
|
+
# @collection.text("Lady")["results"].map{ |r| r["obj"]["track"] }.sort.must_equal ["No. 1", "No. 2"]
|
298
|
+
# @collection.text("Madonna")["results"].map{ |r| r["obj"]["track"] }.sort.must_equal ["No. 1"]
|
299
|
+
# EM.stop
|
300
|
+
# end
|
301
|
+
# end
|
302
|
+
# end
|
247
303
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: monga
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,35 +78,19 @@ dependencies:
|
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
79
|
requirement: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- -
|
81
|
+
- - ~>
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version:
|
83
|
+
version: 2.0.0.beta
|
84
84
|
none: false
|
85
85
|
type: :runtime
|
86
86
|
version_requirements: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- -
|
88
|
+
- - ~>
|
89
89
|
- !ruby/object:Gem::Version
|
90
|
-
version:
|
90
|
+
version: 2.0.0.beta
|
91
91
|
none: false
|
92
92
|
prerelease: false
|
93
93
|
name: bson
|
94
|
-
- !ruby/object:Gem::Dependency
|
95
|
-
requirement: !ruby/object:Gem::Requirement
|
96
|
-
requirements:
|
97
|
-
- - ! '>='
|
98
|
-
- !ruby/object:Gem::Version
|
99
|
-
version: '0'
|
100
|
-
none: false
|
101
|
-
type: :runtime
|
102
|
-
version_requirements: !ruby/object:Gem::Requirement
|
103
|
-
requirements:
|
104
|
-
- - ! '>='
|
105
|
-
- !ruby/object:Gem::Version
|
106
|
-
version: '0'
|
107
|
-
none: false
|
108
|
-
prerelease: false
|
109
|
-
name: bson_ext
|
110
94
|
- !ruby/object:Gem::Dependency
|
111
95
|
requirement: !ruby/object:Gem::Requirement
|
112
96
|
requirements:
|
@@ -123,7 +107,7 @@ dependencies:
|
|
123
107
|
none: false
|
124
108
|
prerelease: false
|
125
109
|
name: bin_utils
|
126
|
-
description: MongoDB Ruby
|
110
|
+
description: Yet another MongoDB Ruby Client
|
127
111
|
email:
|
128
112
|
- fl00r@yandex.ru
|
129
113
|
executables: []
|
@@ -153,7 +137,6 @@ files:
|
|
153
137
|
- lib/monga/connections/fibered_proxy_connection.rb
|
154
138
|
- lib/monga/connections/kgio_connection.rb
|
155
139
|
- lib/monga/connections/proxy_connection.rb
|
156
|
-
- lib/monga/connections/tcp_connection.rb
|
157
140
|
- lib/monga/cursor.rb
|
158
141
|
- lib/monga/database.rb
|
159
142
|
- lib/monga/protocol/delete.rb
|
@@ -194,7 +177,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
194
177
|
requirements:
|
195
178
|
- - ! '>='
|
196
179
|
- !ruby/object:Gem::Version
|
197
|
-
hash: -
|
180
|
+
hash: -862637376897312253
|
198
181
|
version: '0'
|
199
182
|
segments:
|
200
183
|
- 0
|
@@ -203,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
203
186
|
requirements:
|
204
187
|
- - ! '>='
|
205
188
|
- !ruby/object:Gem::Version
|
206
|
-
hash: -
|
189
|
+
hash: -862637376897312253
|
207
190
|
version: '0'
|
208
191
|
segments:
|
209
192
|
- 0
|
@@ -213,7 +196,7 @@ rubyforge_project:
|
|
213
196
|
rubygems_version: 1.8.25
|
214
197
|
signing_key:
|
215
198
|
specification_version: 3
|
216
|
-
summary: MongoDB Ruby
|
199
|
+
summary: Yet another MongoDB Ruby Client
|
217
200
|
test_files:
|
218
201
|
- spec/helpers/mongodb.rb
|
219
202
|
- spec/monga/block/collection_spec.rb
|
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
|
3
|
-
# Currently blocking mode is very poor.
|
4
|
-
# It is working as is.
|
5
|
-
# Going to support reconnecting and timouts later.
|
6
|
-
# Use it for tests and prototyping. Not the best choice for production.
|
7
|
-
|
8
|
-
module Monga::Connections
|
9
|
-
class TCPConnection
|
10
|
-
def self.connect(host, port, timeout)
|
11
|
-
new(host, port, timeout)
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(host, port, timeout)
|
15
|
-
@host, @port, @timout = host, port, timeout
|
16
|
-
@connected = true
|
17
|
-
@buffer = Buffer.new
|
18
|
-
end
|
19
|
-
|
20
|
-
def connected?
|
21
|
-
@connected
|
22
|
-
end
|
23
|
-
|
24
|
-
def socket
|
25
|
-
@socket ||= begin
|
26
|
-
TCPSocket.new(@host, @port)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# Fake answer, as far as we are blocking
|
31
|
-
def responses
|
32
|
-
0
|
33
|
-
end
|
34
|
-
|
35
|
-
def send_command(msg, request_id=nil, &cb)
|
36
|
-
socket.send msg.to_s, 0
|
37
|
-
if cb
|
38
|
-
length = socket.read(4)
|
39
|
-
raise Errno::ECONNREFUSED, "Socket returns nothing like it would be closed." unless length
|
40
|
-
@buffer.append(length)
|
41
|
-
l = length.unpack("L").first
|
42
|
-
rest = socket.read(l-4)
|
43
|
-
@buffer.append(rest)
|
44
|
-
@buffer.each do |message|
|
45
|
-
rid = message[2]
|
46
|
-
fail "Returned Request Id is not equal to sended one" if rid != request_id
|
47
|
-
cb.call(message)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
rescue Errno::ECONNREFUSED, Errno::EPIPE => e
|
51
|
-
@connected = false
|
52
|
-
@socket = nil
|
53
|
-
if cb
|
54
|
-
err = Monga::Exceptions::Disconnected.new("Disconnected from #{@host}:#{@port}, #{e.message}")
|
55
|
-
cb.call(err)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|