moped 1.0.0.alpha → 1.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of moped might be problematic. Click here for more details.
- data/README.md +160 -0
- data/lib/moped.rb +4 -2
- data/lib/moped/bson/object_id.rb +31 -50
- data/lib/moped/cluster.rb +104 -152
- data/lib/moped/collection.rb +1 -3
- data/lib/moped/connection.rb +95 -0
- data/lib/moped/cursor.rb +38 -19
- data/lib/moped/database.rb +6 -14
- data/lib/moped/errors.rb +26 -11
- data/lib/moped/node.rb +334 -0
- data/lib/moped/protocol/command.rb +3 -2
- data/lib/moped/query.rb +24 -26
- data/lib/moped/session.rb +25 -71
- data/lib/moped/session/context.rb +105 -0
- data/lib/moped/threaded.rb +32 -0
- data/lib/moped/version.rb +1 -1
- metadata +7 -5
- data/lib/moped/server.rb +0 -73
- data/lib/moped/socket.rb +0 -201
data/lib/moped/server.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
module Moped
|
2
|
-
|
3
|
-
# @api private
|
4
|
-
#
|
5
|
-
# The internal class for storing information about a server.
|
6
|
-
class Server
|
7
|
-
|
8
|
-
# @return [String] the original host:port address provided
|
9
|
-
attr_reader :address
|
10
|
-
|
11
|
-
# @return [String] the resolved host:port address
|
12
|
-
attr_reader :resolved_address
|
13
|
-
|
14
|
-
# @return [String] the resolved ip address
|
15
|
-
attr_reader :ip_address
|
16
|
-
|
17
|
-
# @return [Integer] the resolved port
|
18
|
-
attr_reader :port
|
19
|
-
|
20
|
-
attr_writer :primary
|
21
|
-
attr_writer :secondary
|
22
|
-
|
23
|
-
def initialize(address)
|
24
|
-
@address = address
|
25
|
-
|
26
|
-
host, port = address.split(":")
|
27
|
-
port = port ? port.to_i : 27017
|
28
|
-
|
29
|
-
ip_address = ::Socket.getaddrinfo(host, nil, ::Socket::AF_INET, ::Socket::SOCK_STREAM).first[3]
|
30
|
-
|
31
|
-
@primary = @secondary = false
|
32
|
-
@ip_address = ip_address
|
33
|
-
@port = port
|
34
|
-
@resolved_address = "#{ip_address}:#{port}"
|
35
|
-
end
|
36
|
-
|
37
|
-
def primary?
|
38
|
-
!!@primary
|
39
|
-
end
|
40
|
-
|
41
|
-
def secondary?
|
42
|
-
!!@secondary
|
43
|
-
end
|
44
|
-
|
45
|
-
def merge(other)
|
46
|
-
@primary = other.primary?
|
47
|
-
@secondary = other.secondary?
|
48
|
-
|
49
|
-
other.close
|
50
|
-
end
|
51
|
-
|
52
|
-
def close
|
53
|
-
if @socket
|
54
|
-
@socket.close
|
55
|
-
@socket = nil
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def socket
|
60
|
-
@socket ||= Socket.new(ip_address, port)
|
61
|
-
end
|
62
|
-
|
63
|
-
def ==(other)
|
64
|
-
self.class === other && hash == other.hash
|
65
|
-
end
|
66
|
-
alias eql? ==
|
67
|
-
|
68
|
-
def hash
|
69
|
-
[ip_address, port].hash
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
73
|
-
end
|
data/lib/moped/socket.rb
DELETED
@@ -1,201 +0,0 @@
|
|
1
|
-
require "timeout"
|
2
|
-
|
3
|
-
module Moped
|
4
|
-
|
5
|
-
# @api private
|
6
|
-
#
|
7
|
-
# The internal class wrapping a socket connection.
|
8
|
-
class Socket
|
9
|
-
|
10
|
-
# Thread-safe atomic integer.
|
11
|
-
class RequestId
|
12
|
-
def initialize
|
13
|
-
@mutex = Mutex.new
|
14
|
-
@id = 0
|
15
|
-
end
|
16
|
-
|
17
|
-
def next
|
18
|
-
@mutex.synchronize { @id += 1 }
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
attr_reader :connection
|
23
|
-
|
24
|
-
attr_reader :host
|
25
|
-
attr_reader :port
|
26
|
-
|
27
|
-
def initialize(host, port)
|
28
|
-
@host = host
|
29
|
-
@port = port
|
30
|
-
|
31
|
-
@mutex = Mutex.new
|
32
|
-
@request_id = RequestId.new
|
33
|
-
end
|
34
|
-
|
35
|
-
# @return [true, false] whether the connection was successful
|
36
|
-
# @note The connection timeout is currently just 0.5 seconds, which should
|
37
|
-
# be sufficient, but may need to be raised or made configurable for
|
38
|
-
# high-latency situations. That said, if connecting to the remote server
|
39
|
-
# takes that long, we may not want to use the node any way.
|
40
|
-
def connect
|
41
|
-
return true if connection
|
42
|
-
|
43
|
-
Timeout::timeout 0.5 do
|
44
|
-
@connection = TCPSocket.new(host, port)
|
45
|
-
end
|
46
|
-
rescue Errno::ECONNREFUSED, Timeout::Error
|
47
|
-
return false
|
48
|
-
end
|
49
|
-
|
50
|
-
# @return [true, false] whether this socket connection is alive
|
51
|
-
def alive?
|
52
|
-
if connection
|
53
|
-
return false if connection.closed?
|
54
|
-
|
55
|
-
@mutex.synchronize do
|
56
|
-
if select([connection], nil, nil, 0)
|
57
|
-
!connection.eof? rescue false
|
58
|
-
else
|
59
|
-
true
|
60
|
-
end
|
61
|
-
end
|
62
|
-
else
|
63
|
-
false
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
# Execute the operations on the connection.
|
68
|
-
def execute(*ops)
|
69
|
-
instrument(ops) do
|
70
|
-
buf = ""
|
71
|
-
|
72
|
-
last = ops.each do |op|
|
73
|
-
op.request_id = @request_id.next
|
74
|
-
op.serialize buf
|
75
|
-
end.last
|
76
|
-
|
77
|
-
if Protocol::Query === last || Protocol::GetMore === last
|
78
|
-
length = nil
|
79
|
-
|
80
|
-
@mutex.synchronize do
|
81
|
-
connection.write buf
|
82
|
-
|
83
|
-
length, = connection.read(4).unpack('l<')
|
84
|
-
|
85
|
-
# Re-use the already allocated buffer used for writing the command.
|
86
|
-
connection.read(length - 4, buf)
|
87
|
-
end
|
88
|
-
|
89
|
-
parse_reply length, buf
|
90
|
-
else
|
91
|
-
@mutex.synchronize do
|
92
|
-
connection.write buf
|
93
|
-
end
|
94
|
-
|
95
|
-
nil
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def parse_reply(length, data)
|
101
|
-
buffer = StringIO.new data
|
102
|
-
|
103
|
-
reply = Protocol::Reply.allocate
|
104
|
-
|
105
|
-
reply.length = length
|
106
|
-
|
107
|
-
reply.request_id,
|
108
|
-
reply.response_to,
|
109
|
-
reply.op_code,
|
110
|
-
reply.flags,
|
111
|
-
reply.cursor_id,
|
112
|
-
reply.offset,
|
113
|
-
reply.count = buffer.read(32).unpack('l4<q<l2<')
|
114
|
-
|
115
|
-
reply.documents = reply.count.times.map do
|
116
|
-
BSON::Document.deserialize(buffer)
|
117
|
-
end
|
118
|
-
|
119
|
-
reply
|
120
|
-
end
|
121
|
-
|
122
|
-
# Executes a simple (one result) query and returns the first document.
|
123
|
-
#
|
124
|
-
# @return [Hash] the first document in a result set.
|
125
|
-
def simple_query(query)
|
126
|
-
query = query.dup
|
127
|
-
query.limit = -1
|
128
|
-
|
129
|
-
execute(query).documents.first
|
130
|
-
end
|
131
|
-
|
132
|
-
# Manually closes the connection
|
133
|
-
def close
|
134
|
-
@mutex.synchronize do
|
135
|
-
connection.close if connection && !connection.closed?
|
136
|
-
@connection = nil
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
def auth
|
141
|
-
@auth ||= {}
|
142
|
-
end
|
143
|
-
|
144
|
-
def apply_auth(credentials)
|
145
|
-
return if auth == credentials
|
146
|
-
logouts = auth.keys - credentials.keys
|
147
|
-
|
148
|
-
logouts.each do |database|
|
149
|
-
logout database
|
150
|
-
end
|
151
|
-
|
152
|
-
credentials.each do |database, (username, password)|
|
153
|
-
login(database, username, password) unless auth[database] == [username, password]
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def login(database, username, password)
|
158
|
-
getnonce = Protocol::Command.new(database, getnonce: 1)
|
159
|
-
result = simple_query getnonce
|
160
|
-
|
161
|
-
raise Errors::OperationFailure.new(getnonce, result) unless result["ok"] == 1
|
162
|
-
|
163
|
-
authenticate = Protocol::Commands::Authenticate.new(database, username, password, result["nonce"])
|
164
|
-
result = simple_query authenticate
|
165
|
-
raise Errors::OperationFailure.new(authenticate, result) unless result["ok"] == 1
|
166
|
-
|
167
|
-
auth[database.to_s] = [username, password]
|
168
|
-
end
|
169
|
-
|
170
|
-
def logout(database)
|
171
|
-
command = Protocol::Command.new(database, logout: 1)
|
172
|
-
result = simple_query command
|
173
|
-
raise Errors::OperationFailure.new(command, result) unless result["ok"] == 1
|
174
|
-
auth.delete(database.to_s)
|
175
|
-
end
|
176
|
-
|
177
|
-
def instrument(ops)
|
178
|
-
instrument_start = (logger = Moped.logger) && logger.debug? && Time.now
|
179
|
-
yield
|
180
|
-
ensure
|
181
|
-
log_operations(logger, ops, Time.now - instrument_start) if instrument_start && !$!
|
182
|
-
end
|
183
|
-
|
184
|
-
def log_operations(logger, ops, duration)
|
185
|
-
prefix = " MOPED: #{host}:#{port} "
|
186
|
-
indent = " "*prefix.length
|
187
|
-
runtime = (" (%.1fms)" % duration)
|
188
|
-
|
189
|
-
if ops.length == 1
|
190
|
-
logger.debug prefix + ops.first.log_inspect + runtime
|
191
|
-
else
|
192
|
-
first, *middle, last = ops
|
193
|
-
|
194
|
-
logger.debug prefix + first.log_inspect
|
195
|
-
middle.each { |m| logger.debug indent + m.log_inspect }
|
196
|
-
logger.debug indent + last.log_inspect + runtime
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
end
|
201
|
-
end
|