moped 1.0.0.beta → 1.0.0.rc
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.
Potentially problematic release.
This version of moped might be problematic. Click here for more details.
- data/LICENSE +20 -0
- data/README.md +11 -8
- data/lib/moped/bson.rb +17 -0
- data/lib/moped/bson/extensions/hash.rb +2 -2
- data/lib/moped/bson/extensions/regexp.rb +2 -2
- data/lib/moped/bson/extensions/symbol.rb +13 -3
- data/lib/moped/cluster.rb +96 -39
- data/lib/moped/collection.rb +54 -31
- data/lib/moped/connection.rb +152 -47
- data/lib/moped/cursor.rb +91 -34
- data/lib/moped/database.rb +52 -20
- data/lib/moped/errors.rb +52 -22
- data/lib/moped/indexes.rb +53 -27
- data/lib/moped/logging.rb +35 -2
- data/lib/moped/node.rb +316 -126
- data/lib/moped/protocol/delete.rb +1 -0
- data/lib/moped/protocol/get_more.rb +1 -0
- data/lib/moped/protocol/insert.rb +1 -0
- data/lib/moped/protocol/kill_cursors.rb +1 -0
- data/lib/moped/protocol/message.rb +0 -2
- data/lib/moped/protocol/query.rb +1 -0
- data/lib/moped/protocol/update.rb +1 -0
- data/lib/moped/query.rb +183 -113
- data/lib/moped/session.rb +148 -96
- data/lib/moped/threaded.rb +41 -5
- data/lib/moped/version.rb +1 -1
- metadata +5 -5
- data/MIT_LICENSE +0 -19
data/lib/moped/connection.rb
CHANGED
@@ -1,48 +1,60 @@
|
|
1
1
|
require "timeout"
|
2
2
|
|
3
3
|
module Moped
|
4
|
-
class Connection
|
5
|
-
|
6
|
-
class TCPSocket < ::TCPSocket
|
7
|
-
def self.connect(host, port, timeout)
|
8
|
-
Timeout::timeout(timeout) do
|
9
|
-
new(host, port).tap do |sock|
|
10
|
-
sock.set_encoding 'binary'
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def alive?
|
16
|
-
if Kernel::select([self], nil, nil, 0)
|
17
|
-
!eof? rescue false
|
18
|
-
else
|
19
|
-
true
|
20
|
-
end
|
21
|
-
end
|
22
4
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
5
|
+
# This class contains behaviour of database socket connections.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Connection
|
28
9
|
|
29
|
-
|
30
|
-
|
31
|
-
|
10
|
+
# Is the connection alive?
|
11
|
+
#
|
12
|
+
# @example Is the connection alive?
|
13
|
+
# connection.alive?
|
14
|
+
#
|
15
|
+
# @return [ true, false ] If the connection is alive.
|
16
|
+
#
|
17
|
+
# @since 1.0.0
|
18
|
+
def alive?
|
19
|
+
connected? ? @sock.alive? : false
|
32
20
|
end
|
33
21
|
|
22
|
+
# Connect to the server.
|
23
|
+
#
|
24
|
+
# @example Connect to the server.
|
25
|
+
# connection.connect("127.0.0.1", 27017, 30)
|
26
|
+
#
|
27
|
+
# @param [ String ] host The host to connect to.
|
28
|
+
# @param [ Integer ] post The server port.
|
29
|
+
# @param [ Integer ] timeout The connection timeout.
|
30
|
+
#
|
31
|
+
# @return [ TCPSocket ] The socket.
|
32
|
+
#
|
33
|
+
# @since 1.0.0
|
34
34
|
def connect(host, port, timeout)
|
35
35
|
@sock = TCPSocket.connect host, port, timeout
|
36
36
|
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
# Is the connection connected?
|
39
|
+
#
|
40
|
+
# @example Is the connection connected?
|
41
|
+
# connection.connected?
|
42
|
+
#
|
43
|
+
# @return [ true, false ] If the connection is connected.
|
44
|
+
#
|
45
|
+
# @since 1.0.0
|
42
46
|
def connected?
|
43
47
|
!!@sock
|
44
48
|
end
|
45
49
|
|
50
|
+
# Disconnect from the server.
|
51
|
+
#
|
52
|
+
# @example Disconnect from the server.
|
53
|
+
# connection.disconnect
|
54
|
+
#
|
55
|
+
# @return [ nil ] nil.
|
56
|
+
#
|
57
|
+
# @since 1.0.0
|
46
58
|
def disconnect
|
47
59
|
@sock.close
|
48
60
|
rescue
|
@@ -50,26 +62,27 @@ module Moped
|
|
50
62
|
@sock = nil
|
51
63
|
end
|
52
64
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
@
|
62
|
-
end
|
63
|
-
|
64
|
-
def receive_replies(operations)
|
65
|
-
operations.map do |operation|
|
66
|
-
read if operation.is_a?(Protocol::Query) || operation.is_a?(Protocol::GetMore)
|
67
|
-
end
|
65
|
+
# Initialize the connection.
|
66
|
+
#
|
67
|
+
# @example Initialize the connection.
|
68
|
+
# Connection.new
|
69
|
+
#
|
70
|
+
# @since 1.0.0
|
71
|
+
def initialize
|
72
|
+
@sock = nil
|
73
|
+
@request_id = 0
|
68
74
|
end
|
69
75
|
|
76
|
+
# Read from the connection.
|
77
|
+
#
|
78
|
+
# @example Read from the connection.
|
79
|
+
# connection.read
|
80
|
+
#
|
81
|
+
# @return [ Hash ] The returned document.
|
82
|
+
#
|
83
|
+
# @since 1.0.0
|
70
84
|
def read
|
71
85
|
reply = Protocol::Reply.allocate
|
72
|
-
|
73
86
|
reply.length,
|
74
87
|
reply.request_id,
|
75
88
|
reply.response_to,
|
@@ -88,8 +101,100 @@ module Moped
|
|
88
101
|
BSON::Document.deserialize(buffer)
|
89
102
|
end
|
90
103
|
end
|
91
|
-
|
92
104
|
reply
|
93
105
|
end
|
106
|
+
|
107
|
+
# Get the replies to the database operation.
|
108
|
+
#
|
109
|
+
# @example Get the replies.
|
110
|
+
# connection.receive_replies(operations)
|
111
|
+
#
|
112
|
+
# @param [ Array<Message> ] operations The query or get more ops.
|
113
|
+
#
|
114
|
+
# @return [ Array<Hash> ] The returned deserialized documents.
|
115
|
+
#
|
116
|
+
# @since 1.0.0
|
117
|
+
def receive_replies(operations)
|
118
|
+
operations.map do |operation|
|
119
|
+
read if operation.is_a?(Protocol::Query) || operation.is_a?(Protocol::GetMore)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Write to the connection.
|
124
|
+
#
|
125
|
+
# @example Write to the connection.
|
126
|
+
# connection.write(data)
|
127
|
+
#
|
128
|
+
# @param [ Array<Message> ] operations The database operations.
|
129
|
+
#
|
130
|
+
# @return [ Integer ] The number of bytes written.
|
131
|
+
#
|
132
|
+
# @since 1.0.0
|
133
|
+
def write(operations)
|
134
|
+
buf = ""
|
135
|
+
operations.each do |operation|
|
136
|
+
operation.request_id = (@request_id += 1)
|
137
|
+
operation.serialize(buf)
|
138
|
+
end
|
139
|
+
@sock.write(buf)
|
140
|
+
end
|
141
|
+
|
142
|
+
# This is a wrapper around a tcp socket.
|
143
|
+
class TCPSocket < ::TCPSocket
|
144
|
+
|
145
|
+
# Is the socket connection alive?
|
146
|
+
#
|
147
|
+
# @example Is the socket alive?
|
148
|
+
# socket.alive?
|
149
|
+
#
|
150
|
+
# @return [ true, false ] If the socket is alive.
|
151
|
+
#
|
152
|
+
# @since 1.0.0
|
153
|
+
def alive?
|
154
|
+
if Kernel::select([ self ], nil, nil, 0)
|
155
|
+
!eof? rescue false
|
156
|
+
else
|
157
|
+
true
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Write to the socket.
|
162
|
+
#
|
163
|
+
# @example Write to the socket.
|
164
|
+
# socket.write(data)
|
165
|
+
#
|
166
|
+
# @param [ Object ] args The data to write.
|
167
|
+
#
|
168
|
+
# @return [ Integer ] The number of bytes written.
|
169
|
+
#
|
170
|
+
# @since 1.0.0
|
171
|
+
def write(*args)
|
172
|
+
raise Errors::ConnectionFailure, "Socket connection was closed by remote host" unless alive?
|
173
|
+
super
|
174
|
+
end
|
175
|
+
|
176
|
+
class << self
|
177
|
+
|
178
|
+
# Connect to the tcp server.
|
179
|
+
#
|
180
|
+
# @example Connect to the server.
|
181
|
+
# TCPSocket.connect("127.0.0.1", 27017, 30)
|
182
|
+
#
|
183
|
+
# @param [ String ] host The host to connect to.
|
184
|
+
# @param [ Integer ] post The server port.
|
185
|
+
# @param [ Integer ] timeout The connection timeout.
|
186
|
+
#
|
187
|
+
# @return [ TCPSocket ] The socket.
|
188
|
+
#
|
189
|
+
# @since 1.0.0
|
190
|
+
def connect(host, port, timeout)
|
191
|
+
Timeout::timeout(timeout) do
|
192
|
+
new(host, port).tap do |sock|
|
193
|
+
sock.set_encoding('binary')
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
94
199
|
end
|
95
200
|
end
|
data/lib/moped/cursor.rb
CHANGED
@@ -1,13 +1,61 @@
|
|
1
1
|
module Moped
|
2
2
|
|
3
|
+
# Contains logic for cursor behaviour.
|
4
|
+
#
|
3
5
|
# @api private
|
4
6
|
class Cursor
|
5
|
-
attr_reader :session
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
# @attribute [r] get_more_op The get more message.
|
9
|
+
# @attribute [r] kill_cursor_op The kill cursor message.
|
10
|
+
# @attribute [r] query_op The query message.
|
11
|
+
# @attribute [r] session The session.
|
12
|
+
attr_reader :get_more_op, :kill_cursor_op, :query_op, :session
|
13
|
+
|
14
|
+
# Iterate over the results of the query.
|
15
|
+
#
|
16
|
+
# @example Iterate over the results.
|
17
|
+
# cursor.each do |doc|
|
18
|
+
# #...
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# @return [ Enumerator ] The cursor enum.
|
22
|
+
#
|
23
|
+
# @since 1.0.0
|
24
|
+
def each
|
25
|
+
documents = load_docs
|
26
|
+
documents.each { |doc| yield doc }
|
27
|
+
while more?
|
28
|
+
return kill if limited? && @limit <= 0
|
29
|
+
documents = get_more
|
30
|
+
documents.each { |doc| yield doc }
|
31
|
+
end
|
32
|
+
end
|
10
33
|
|
34
|
+
# Get more documents from the database for the cursor. Executes a get more
|
35
|
+
# command.
|
36
|
+
#
|
37
|
+
# @example Get more docs.
|
38
|
+
# cursor.get_more
|
39
|
+
#
|
40
|
+
# @return [ Array<Hash> ] The next batch of documents.
|
41
|
+
#
|
42
|
+
# @since 1.0.0
|
43
|
+
def get_more
|
44
|
+
reply = @node.get_more @database, @collection, @cursor_id, @limit
|
45
|
+
@limit -= reply.count if limited?
|
46
|
+
@cursor_id = reply.cursor_id
|
47
|
+
reply.documents
|
48
|
+
end
|
49
|
+
|
50
|
+
# Initialize the new cursor.
|
51
|
+
#
|
52
|
+
# @example Create the new cursor.
|
53
|
+
# Cursor.new(session, message)
|
54
|
+
#
|
55
|
+
# @param [ Session ] session The session.
|
56
|
+
# @param [ Message ] query_operation The query message.
|
57
|
+
#
|
58
|
+
# @since 1.0.0
|
11
59
|
def initialize(session, query_operation)
|
12
60
|
@session = session
|
13
61
|
|
@@ -28,52 +76,61 @@ module Moped
|
|
28
76
|
}
|
29
77
|
end
|
30
78
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
79
|
+
# Kill the cursor.
|
80
|
+
#
|
81
|
+
# @example Kill the cursor.
|
82
|
+
# cursor.kill
|
83
|
+
#
|
84
|
+
# @return [ Object ] The result of the kill cursors command.
|
85
|
+
#
|
86
|
+
# @since 1.0.0
|
87
|
+
def kill
|
88
|
+
@node.kill_cursors([ @cursor_id ])
|
89
|
+
end
|
37
90
|
|
38
|
-
|
39
|
-
|
40
|
-
|
91
|
+
# Does the cursor have a limit provided in the query?
|
92
|
+
#
|
93
|
+
# @example Is the cursor limited?
|
94
|
+
# cursor.limited?
|
95
|
+
#
|
96
|
+
# @return [ true, false ] If a limit has been provided over zero.
|
97
|
+
#
|
98
|
+
# @since 1.0.0
|
99
|
+
def limited?
|
100
|
+
@limited
|
41
101
|
end
|
42
102
|
|
43
|
-
|
103
|
+
# Load the documents from the database.
|
104
|
+
#
|
105
|
+
# @example Load the documents.
|
106
|
+
# cursor.load_docs
|
107
|
+
#
|
108
|
+
# @return [ Array<Hash> ] The documents.
|
109
|
+
#
|
110
|
+
# @since 1.0.0
|
111
|
+
def load_docs
|
44
112
|
consistency = session.consistency
|
45
113
|
@options[:flags] |= [:slave_ok] if consistency == :eventual
|
46
114
|
|
47
115
|
reply, @node = session.context.with_node do |node|
|
48
|
-
[node.query(@database, @collection, @selector, @options), node]
|
116
|
+
[ node.query(@database, @collection, @selector, @options), node ]
|
49
117
|
end
|
50
118
|
|
51
119
|
@limit -= reply.count if limited?
|
52
120
|
@cursor_id = reply.cursor_id
|
53
|
-
|
54
121
|
reply.documents
|
55
122
|
end
|
56
123
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
124
|
+
# Are there more documents to be returned from the database?
|
125
|
+
#
|
126
|
+
# @example Are there more documents?
|
127
|
+
# cursor.more?
|
128
|
+
#
|
129
|
+
# @return [ true, false ] If there are more documents to load.
|
130
|
+
#
|
131
|
+
# @since 1.0.0
|
61
132
|
def more?
|
62
133
|
@cursor_id != 0
|
63
134
|
end
|
64
|
-
|
65
|
-
def get_more
|
66
|
-
reply = @node.get_more @database, @collection, @cursor_id, @limit
|
67
|
-
|
68
|
-
@limit -= reply.count if limited?
|
69
|
-
@cursor_id = reply.cursor_id
|
70
|
-
|
71
|
-
reply.documents
|
72
|
-
end
|
73
|
-
|
74
|
-
def kill
|
75
|
-
@node.kill_cursors [@cursor_id]
|
76
|
-
end
|
77
135
|
end
|
78
|
-
|
79
136
|
end
|
data/lib/moped/database.rb
CHANGED
@@ -14,53 +14,85 @@ module Moped
|
|
14
14
|
# end
|
15
15
|
class Database
|
16
16
|
|
17
|
-
# @
|
18
|
-
|
19
|
-
|
20
|
-
# @return [String, Symbol] the database's name
|
21
|
-
attr_reader :name
|
22
|
-
|
23
|
-
# @param [Session] session the session
|
24
|
-
# @param [String, Symbol] name the database's name
|
25
|
-
def initialize(session, name)
|
26
|
-
@session = session
|
27
|
-
@name = name
|
28
|
-
end
|
17
|
+
# @attribute [r] name The name of the database.
|
18
|
+
# @attribute [r] session The session.
|
19
|
+
attr_reader :name, :session
|
29
20
|
|
30
21
|
# Drop the database.
|
22
|
+
#
|
23
|
+
# @example Drop the database.
|
24
|
+
# database.drop
|
25
|
+
#
|
26
|
+
# @return [ nil ] nil.
|
27
|
+
#
|
28
|
+
# @since 1.0.0
|
31
29
|
def drop
|
32
30
|
session.with(consistency: :strong) do |session|
|
33
|
-
session.context.command
|
31
|
+
session.context.command(name, dropDatabase: 1)
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
35
|
+
# Initialize the database.
|
36
|
+
#
|
37
|
+
# @example Initialize a database object.
|
38
|
+
# Database.new(session, :artists)
|
39
|
+
#
|
40
|
+
# @param [ Session ] session The session.
|
41
|
+
# @param [ String, Symbol ] name The name of the database.
|
42
|
+
#
|
43
|
+
# @since 1.0.0
|
44
|
+
def initialize(session, name)
|
45
|
+
@session, @name = session, name
|
46
|
+
end
|
47
|
+
|
37
48
|
# Log in with +username+ and +password+ on the current database.
|
38
49
|
#
|
39
|
-
# @
|
40
|
-
#
|
50
|
+
# @example Authenticate against the database.
|
51
|
+
# session.login("user", "pass")
|
52
|
+
#
|
53
|
+
# @param [ String ] username The username.
|
54
|
+
# @param [ String ] password The password.
|
55
|
+
#
|
56
|
+
# @since 1.0.0
|
41
57
|
def login(username, password)
|
42
58
|
session.context.login(name, username, password)
|
43
59
|
end
|
44
60
|
|
45
61
|
# Log out from the current database.
|
62
|
+
#
|
63
|
+
# @example Logout from the current database.
|
64
|
+
# session.logout
|
65
|
+
#
|
66
|
+
# @since 1.0.0
|
46
67
|
def logout
|
47
68
|
session.context.logout(name)
|
48
69
|
end
|
49
70
|
|
50
71
|
# Run +command+ on the database.
|
51
72
|
#
|
52
|
-
# @example
|
73
|
+
# @example Run a command.
|
53
74
|
# db.command(ismaster: 1)
|
54
75
|
# # => { "master" => true, hosts: [] }
|
55
76
|
#
|
56
|
-
# @param [Hash] command
|
57
|
-
#
|
77
|
+
# @param [ Hash ] command The command to run.
|
78
|
+
#
|
79
|
+
# @return [ Hash ] the result of the command.
|
80
|
+
#
|
81
|
+
# @since 1.0.0
|
58
82
|
def command(command)
|
59
83
|
session.context.command name, command
|
60
84
|
end
|
61
85
|
|
62
|
-
#
|
63
|
-
#
|
86
|
+
# Get a collection by the provided name.
|
87
|
+
#
|
88
|
+
# @example Get a collection.
|
89
|
+
# session[:users]
|
90
|
+
#
|
91
|
+
# @param [ Symbol, String ] collection The collection name.
|
92
|
+
#
|
93
|
+
# @return [ Collection ] An instance of the collection.
|
94
|
+
#
|
95
|
+
# @since 1.0.0
|
64
96
|
def [](collection)
|
65
97
|
Collection.new(self, collection)
|
66
98
|
end
|