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.

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