moped 1.5.3 → 2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +42 -5
- data/README.md +1 -1
- data/lib/moped.rb +10 -13
- data/lib/moped/address.rb +56 -0
- data/lib/moped/authenticatable.rb +89 -0
- data/lib/moped/cluster.rb +169 -136
- data/lib/moped/collection.rb +53 -19
- data/lib/moped/connection.rb +69 -10
- data/lib/moped/connection/manager.rb +49 -0
- data/lib/moped/connection/pool.rb +198 -0
- data/lib/moped/connection/queue.rb +93 -0
- data/lib/moped/connection/reaper.rb +52 -0
- data/lib/moped/connection/socket.rb +4 -0
- data/lib/moped/connection/socket/connectable.rb +169 -0
- data/lib/moped/connection/socket/ssl.rb +52 -0
- data/lib/moped/connection/socket/tcp.rb +25 -0
- data/lib/moped/connection/sockets.rb +4 -0
- data/lib/moped/cursor.rb +3 -5
- data/lib/moped/database.rb +18 -24
- data/lib/moped/errors.rb +35 -6
- data/lib/moped/executable.rb +96 -0
- data/lib/moped/failover.rb +41 -0
- data/lib/moped/failover/disconnect.rb +31 -0
- data/lib/moped/failover/ignore.rb +29 -0
- data/lib/moped/failover/reconfigure.rb +34 -0
- data/lib/moped/failover/retry.rb +37 -0
- data/lib/moped/indexes.rb +4 -1
- data/lib/moped/instrumentable.rb +39 -0
- data/lib/moped/instrumentable/log.rb +43 -0
- data/lib/moped/instrumentable/noop.rb +31 -0
- data/lib/moped/loggable.rb +110 -0
- data/lib/moped/node.rb +316 -297
- data/lib/moped/operation.rb +3 -0
- data/lib/moped/operation/read.rb +62 -0
- data/lib/moped/operation/write.rb +57 -0
- data/lib/moped/protocol/command.rb +65 -4
- data/lib/moped/protocol/commands/authenticate.rb +1 -2
- data/lib/moped/protocol/delete.rb +16 -0
- data/lib/moped/protocol/get_more.rb +102 -31
- data/lib/moped/protocol/insert.rb +17 -0
- data/lib/moped/protocol/message.rb +44 -46
- data/lib/moped/protocol/query.rb +175 -92
- data/lib/moped/protocol/reply.rb +19 -8
- data/lib/moped/protocol/update.rb +18 -0
- data/lib/moped/query.rb +43 -17
- data/lib/moped/read_preference.rb +49 -0
- data/lib/moped/read_preference/nearest.rb +55 -0
- data/lib/moped/read_preference/primary.rb +60 -0
- data/lib/moped/read_preference/primary_preferred.rb +55 -0
- data/lib/moped/read_preference/secondary.rb +50 -0
- data/lib/moped/read_preference/secondary_preferred.rb +53 -0
- data/lib/moped/read_preference/selectable.rb +79 -0
- data/lib/moped/readable.rb +55 -0
- data/lib/moped/session.rb +122 -70
- data/lib/moped/{mongo_uri.rb → uri.rb} +75 -31
- data/lib/moped/version.rb +1 -1
- data/lib/moped/write_concern.rb +33 -0
- data/lib/moped/write_concern/propagate.rb +38 -0
- data/lib/moped/write_concern/unverified.rb +28 -0
- metadata +79 -44
- data/lib/moped/bson.rb +0 -45
- data/lib/moped/bson/binary.rb +0 -137
- data/lib/moped/bson/code.rb +0 -112
- data/lib/moped/bson/document.rb +0 -41
- data/lib/moped/bson/extensions.rb +0 -91
- data/lib/moped/bson/extensions/array.rb +0 -37
- data/lib/moped/bson/extensions/boolean.rb +0 -16
- data/lib/moped/bson/extensions/false_class.rb +0 -19
- data/lib/moped/bson/extensions/float.rb +0 -22
- data/lib/moped/bson/extensions/hash.rb +0 -39
- data/lib/moped/bson/extensions/integer.rb +0 -36
- data/lib/moped/bson/extensions/nil_class.rb +0 -19
- data/lib/moped/bson/extensions/object.rb +0 -11
- data/lib/moped/bson/extensions/regexp.rb +0 -38
- data/lib/moped/bson/extensions/string.rb +0 -45
- data/lib/moped/bson/extensions/symbol.rb +0 -33
- data/lib/moped/bson/extensions/time.rb +0 -23
- data/lib/moped/bson/extensions/true_class.rb +0 -19
- data/lib/moped/bson/max_key.rb +0 -51
- data/lib/moped/bson/min_key.rb +0 -51
- data/lib/moped/bson/object_id.rb +0 -301
- data/lib/moped/bson/timestamp.rb +0 -38
- data/lib/moped/bson/types.rb +0 -67
- data/lib/moped/logging.rb +0 -58
- data/lib/moped/session/context.rb +0 -115
- data/lib/moped/sockets/connectable.rb +0 -167
- data/lib/moped/sockets/ssl.rb +0 -50
- data/lib/moped/sockets/tcp.rb +0 -23
- data/lib/moped/threaded.rb +0 -69
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Moped
|
3
|
+
module Operation
|
4
|
+
|
5
|
+
# Represents a read from the database that is executed on a specific node
|
6
|
+
# determined by a read preference.
|
7
|
+
#
|
8
|
+
# @since 2.0.0
|
9
|
+
class Read
|
10
|
+
|
11
|
+
# @!attribute database
|
12
|
+
# @return [ String ] The database the read is from.
|
13
|
+
# @!attribute operation
|
14
|
+
# @return [ Protocol::Query, Protocol::GetMore, Protocol::Command ]
|
15
|
+
# The read operation.
|
16
|
+
attr_reader :database, :operation
|
17
|
+
|
18
|
+
# Instantiate the read operation.
|
19
|
+
#
|
20
|
+
# @example Instantiate the read.
|
21
|
+
# Read.new(get_more)
|
22
|
+
#
|
23
|
+
# @param [ Protocol::Query, Protocol::GetMore, Protocol::Command ] operation
|
24
|
+
# The read operation.
|
25
|
+
#
|
26
|
+
# @since 2.0.0
|
27
|
+
def initialize(operation)
|
28
|
+
@operation = operation
|
29
|
+
@database = operation.database
|
30
|
+
end
|
31
|
+
|
32
|
+
# Execute the read operation on the provided node. If the query failed, we
|
33
|
+
# will check if the failure was due to authorization and attempt the
|
34
|
+
# operation again. This could sometimes happen in the case of a step down
|
35
|
+
# or reconfiguration on the server side.
|
36
|
+
#
|
37
|
+
# @example Execute the operation.
|
38
|
+
# read.execute(node)
|
39
|
+
#
|
40
|
+
# @param [ Node ] node The node to execute the read on.
|
41
|
+
#
|
42
|
+
# @raise [ Failure ] If the read operation failed.
|
43
|
+
#
|
44
|
+
# @return [ Protocol::Reply ] The reply from the database.
|
45
|
+
#
|
46
|
+
# @since 2.0.0
|
47
|
+
def execute(node)
|
48
|
+
node.process(operation) do |reply|
|
49
|
+
if operation.failure?(reply)
|
50
|
+
if reply.unauthorized? && node.credentials.has_key?(database)
|
51
|
+
node.login(database, *node.credentials[database])
|
52
|
+
return execute(node)
|
53
|
+
else
|
54
|
+
raise operation.failure_exception(reply)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
operation.results(reply)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Moped
|
3
|
+
module Operation
|
4
|
+
|
5
|
+
# Encapsulates behaviour for write operations.
|
6
|
+
#
|
7
|
+
# @since 2.0.0
|
8
|
+
class Write
|
9
|
+
|
10
|
+
# @!attribute concern
|
11
|
+
# @return [ Object ] The configured write concern.
|
12
|
+
# @!attribute database
|
13
|
+
# @return [ String ] The database the read is from.
|
14
|
+
# @!attribute operation
|
15
|
+
# @return [ Protocol::Insert, Protocol::Update, Protocol::Delete ]
|
16
|
+
# The write operation.
|
17
|
+
attr_reader :concern, :database, :operation
|
18
|
+
|
19
|
+
# Instantiate the write operation.
|
20
|
+
#
|
21
|
+
# @example Instantiate the write.
|
22
|
+
# Write.new(insert)
|
23
|
+
#
|
24
|
+
# @param [ Protocol::Insert, Protocol::Update, Protocol::Delete ] operation
|
25
|
+
# The write operation.
|
26
|
+
#
|
27
|
+
# @since 2.0.0
|
28
|
+
def initialize(operation, concern)
|
29
|
+
@operation = operation
|
30
|
+
@database = operation.database
|
31
|
+
@concern = concern
|
32
|
+
end
|
33
|
+
|
34
|
+
# Execute the write operation on the provided node. If the write concern
|
35
|
+
# is propagating, then the gle command will be piggybacked onto the
|
36
|
+
# initial write operation.
|
37
|
+
#
|
38
|
+
# @example Execute the operation.
|
39
|
+
# write.execute(node)
|
40
|
+
#
|
41
|
+
# @param [ Node ] node The node to execute the write on.
|
42
|
+
#
|
43
|
+
# @since 2.0.0
|
44
|
+
def execute(node)
|
45
|
+
propagate = concern.operation
|
46
|
+
if propagate
|
47
|
+
node.pipeline do
|
48
|
+
node.process(operation)
|
49
|
+
node.command(database, propagate)
|
50
|
+
end
|
51
|
+
else
|
52
|
+
node.process(operation)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -7,19 +7,80 @@ module Moped
|
|
7
7
|
# @example
|
8
8
|
# command = Moped::Protocol::Command.new :moped, ismaster: 1
|
9
9
|
# socket.write command.serialize
|
10
|
+
#
|
11
|
+
# @since 1.0.0
|
10
12
|
class Command < Query
|
11
13
|
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
14
|
+
# Determine if the provided reply message is a failure with respect to a
|
15
|
+
# command.
|
16
|
+
#
|
17
|
+
# @example Is the reply a command failure?
|
18
|
+
# command.failure?(reply)
|
19
|
+
#
|
20
|
+
# @param [ Reply ] reply The reply to the command.
|
21
|
+
#
|
22
|
+
# @return [ true, false ] If the reply is a failure.
|
23
|
+
#
|
24
|
+
# @since 2.0.0
|
25
|
+
def failure?(reply)
|
26
|
+
reply.command_failure?
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get the exception specific to a failure of this particular operation.
|
30
|
+
#
|
31
|
+
# @example Get the failure exception.
|
32
|
+
# command.failure_exception(document)
|
33
|
+
#
|
34
|
+
# @param [ Moped::Protocol::Reply ] reply The reply from the database.
|
35
|
+
#
|
36
|
+
# @return [ Moped::Errors::OperationFailure ] The failure exception.
|
37
|
+
#
|
38
|
+
# @since 2.0.0
|
39
|
+
def failure_exception(reply)
|
40
|
+
Errors::OperationFailure.new(self, reply.documents.first)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Instantiate the new command.
|
44
|
+
#
|
45
|
+
# @example Instantiate the new command.
|
46
|
+
# Moped::Protocol::Command.new(:moped_test, ismaster: 1)
|
47
|
+
#
|
48
|
+
# @param [ String, Symbol ] database The database to run the command on.
|
49
|
+
# @param [ Hash ] command The command to run.
|
50
|
+
# @param [ Hash ] options And additional query options.
|
51
|
+
#
|
52
|
+
# @since 1.0.0
|
15
53
|
def initialize(database, command, options = {})
|
16
|
-
super
|
54
|
+
super(database, '$cmd', command, options.merge(limit: -1))
|
17
55
|
end
|
18
56
|
|
57
|
+
# Provide the value that will be logged when the command runs.
|
58
|
+
#
|
59
|
+
# @example Provide the log inspection.
|
60
|
+
# command.log_inspect
|
61
|
+
#
|
62
|
+
# @return [ String ] The string value for logging.
|
63
|
+
#
|
64
|
+
# @since 1.0.0
|
19
65
|
def log_inspect
|
20
66
|
type = "COMMAND"
|
21
67
|
"%-12s database=%s command=%s" % [type, database, selector.inspect]
|
22
68
|
end
|
69
|
+
|
70
|
+
# Take the provided reply and return the expected results to api
|
71
|
+
# consumers. In the case of the command it's the first document.
|
72
|
+
#
|
73
|
+
# @example Get the expected results of the reply.
|
74
|
+
# command.results(reply)
|
75
|
+
#
|
76
|
+
# @param [ Moped::Protocol::Reply ] reply The reply from the database.
|
77
|
+
#
|
78
|
+
# @return [ Hash ] The first document in the reply.
|
79
|
+
#
|
80
|
+
# @since 2.0.0
|
81
|
+
def results(reply)
|
82
|
+
reply.documents.first
|
83
|
+
end
|
23
84
|
end
|
24
85
|
end
|
25
86
|
end
|
@@ -22,7 +22,7 @@ module Moped
|
|
22
22
|
# @param [String] nonce the nonce returned from running the getnonce
|
23
23
|
# command.
|
24
24
|
def initialize(database, username, password, nonce)
|
25
|
-
super
|
25
|
+
super(database, build_auth_command(username, password, nonce))
|
26
26
|
end
|
27
27
|
|
28
28
|
# @param [String] username
|
@@ -47,7 +47,6 @@ module Moped
|
|
47
47
|
key: digest(username, password, nonce)
|
48
48
|
}
|
49
49
|
end
|
50
|
-
|
51
50
|
end
|
52
51
|
end
|
53
52
|
end
|
@@ -90,6 +90,22 @@ module Moped
|
|
90
90
|
"%-12s database=%s collection=%s selector=%s flags=%s" % [type, database, collection, selector.inspect, flags.inspect]
|
91
91
|
end
|
92
92
|
|
93
|
+
private
|
94
|
+
|
95
|
+
# Duplicate the attributes in the delete that need to be.
|
96
|
+
#
|
97
|
+
# @api private
|
98
|
+
#
|
99
|
+
# @example Clone the delete.
|
100
|
+
# delete.clone
|
101
|
+
#
|
102
|
+
# @param [ Delete ] The delete that was cloned from.
|
103
|
+
#
|
104
|
+
# @since 2.0.0
|
105
|
+
def initialize_copy(_)
|
106
|
+
@selector = selector.dup
|
107
|
+
@flags = flags.dup
|
108
|
+
end
|
93
109
|
end
|
94
110
|
end
|
95
111
|
end
|
@@ -3,15 +3,7 @@ module Moped
|
|
3
3
|
|
4
4
|
# The Protocol class for retrieving more documents from a cursor.
|
5
5
|
#
|
6
|
-
# @
|
7
|
-
# insert = GetMore.new "moped", "people", 29301021, 0
|
8
|
-
#
|
9
|
-
# @example Get more results using custom limit
|
10
|
-
# insert = Insert.new "moped", "people", 29301021, 10
|
11
|
-
#
|
12
|
-
# @example Setting the request id
|
13
|
-
# insert = Insert.new "moped", "people", 29301021, 10,
|
14
|
-
# request_id: 123
|
6
|
+
# @since 1.0.0
|
15
7
|
class GetMore
|
16
8
|
include Message
|
17
9
|
|
@@ -29,54 +21,118 @@ module Moped
|
|
29
21
|
# @return [Number] the operation code of this message
|
30
22
|
int32 :op_code
|
31
23
|
|
32
|
-
int32
|
24
|
+
int32 :reserved # reserved for future use
|
33
25
|
|
34
26
|
# @attribute
|
35
27
|
# @return [String] the namespaced collection name
|
36
|
-
cstring
|
28
|
+
cstring :full_collection_name
|
37
29
|
|
38
30
|
# @attribute
|
39
31
|
# @return [Number] the number of documents to return
|
40
|
-
int32
|
32
|
+
int32 :limit
|
41
33
|
|
42
34
|
# @attribute
|
43
35
|
# @return [Number] the id of the cursor to get more documents from
|
44
|
-
int64
|
36
|
+
int64 :cursor_id
|
45
37
|
|
46
38
|
finalize
|
47
39
|
|
48
|
-
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
40
|
+
# @!attribute collection
|
41
|
+
# @return [ String ] The collection to query.
|
42
|
+
# @!attribute database
|
43
|
+
# @return [ String ] The database to query
|
44
|
+
attr_reader :collection, :database
|
53
45
|
|
54
|
-
#
|
55
|
-
|
46
|
+
# Determine if the provided reply message is a failure with respect to a
|
47
|
+
# get more operation.
|
48
|
+
#
|
49
|
+
# @example Is the reply a query failure?
|
50
|
+
# get_more.failure?(reply)
|
51
|
+
#
|
52
|
+
# @param [ Reply ] reply The reply to the get more.
|
53
|
+
#
|
54
|
+
# @return [ true, false ] If the reply is a failure.
|
55
|
+
#
|
56
|
+
# @since 2.0.0
|
57
|
+
def failure?(reply)
|
58
|
+
reply.cursor_not_found? || reply.query_failure?
|
59
|
+
end
|
56
60
|
|
57
|
-
#
|
58
|
-
|
61
|
+
# Get the exception specific to a failure of this particular operation.
|
62
|
+
#
|
63
|
+
# @example Get the failure exception.
|
64
|
+
# get_more.failure_exception(document)
|
65
|
+
#
|
66
|
+
# @param [ Moped::Protocol::Reply ] reply The reply from the database.
|
67
|
+
#
|
68
|
+
# @return [ Moped::Errors::CursorNotFound ] The failure exception.
|
69
|
+
#
|
70
|
+
# @since 2.0.0
|
71
|
+
def failure_exception(reply)
|
72
|
+
if reply.cursor_not_found?
|
73
|
+
Errors::CursorNotFound.new(self, cursor_id)
|
74
|
+
else
|
75
|
+
Errors::QueryFailure.new(self, reply.documents.first)
|
76
|
+
end
|
77
|
+
end
|
59
78
|
|
60
|
-
# Create a new
|
61
|
-
# are joined together to set the
|
79
|
+
# Create a new GetMore command. The database and collection arguments
|
80
|
+
# are joined together to set the full_collection_name.
|
81
|
+
#
|
82
|
+
# @example Get more results using database default limit.
|
83
|
+
# GetMore.new("moped", "people", 29301021, 0)
|
62
84
|
#
|
63
|
-
# @example
|
64
|
-
# GetMore.new
|
85
|
+
# @example Get more results using custom limit.
|
86
|
+
# GetMore.new("moped", "people", 29301021, 10)
|
87
|
+
#
|
88
|
+
# @example Get more with a request id.
|
89
|
+
# GetMore.new("moped", "people", 29301021, 10, request_id: 123)
|
90
|
+
#
|
91
|
+
# @param [ String ] database The database name.
|
92
|
+
# @param [ String ] collection The collection name.
|
93
|
+
# @param [ Integer ] cursor_id The id of the cursor.
|
94
|
+
# @param [ Integer ] limit The number of documents to limit.
|
95
|
+
# @param [ Hash ] options The get more options.
|
96
|
+
#
|
97
|
+
# @option options [ Integer ] :request_id The operation's request id.
|
98
|
+
#
|
99
|
+
# @since 1.0.0
|
65
100
|
def initialize(database, collection, cursor_id, limit, options = {})
|
66
|
-
@database
|
101
|
+
@database = database
|
67
102
|
@collection = collection
|
68
|
-
|
69
103
|
@full_collection_name = "#{database}.#{collection}"
|
70
|
-
@cursor_id
|
71
|
-
@limit
|
72
|
-
@request_id
|
104
|
+
@cursor_id = cursor_id
|
105
|
+
@limit = limit
|
106
|
+
@request_id = options[:request_id]
|
73
107
|
end
|
74
108
|
|
109
|
+
# Provide the value that will be logged when the get more runs.
|
110
|
+
#
|
111
|
+
# @example Provide the log inspection.
|
112
|
+
# get_more.log_inspect
|
113
|
+
#
|
114
|
+
# @return [ String ] The string value for logging.
|
115
|
+
#
|
116
|
+
# @since 1.0.0
|
75
117
|
def log_inspect
|
76
118
|
type = "GET_MORE"
|
77
119
|
"%-12s database=%s collection=%s limit=%s cursor_id=%s" % [type, database, collection, limit, cursor_id]
|
78
120
|
end
|
79
121
|
|
122
|
+
undef op_code
|
123
|
+
|
124
|
+
# Get the code for a get more operation.
|
125
|
+
#
|
126
|
+
# @example Get the operation code.
|
127
|
+
# get_more.op_code
|
128
|
+
#
|
129
|
+
# @return [ Integer ] OP_GETMORE operation code (2005).
|
130
|
+
#
|
131
|
+
# @since 1.0.0
|
132
|
+
def op_code
|
133
|
+
2005
|
134
|
+
end
|
135
|
+
|
80
136
|
# Receive replies to the message.
|
81
137
|
#
|
82
138
|
# @example Receive replies.
|
@@ -90,6 +146,21 @@ module Moped
|
|
90
146
|
def receive_replies(connection)
|
91
147
|
connection.read
|
92
148
|
end
|
149
|
+
|
150
|
+
# Take the provided reply and return the expected results to api
|
151
|
+
# consumers.
|
152
|
+
#
|
153
|
+
# @example Get the expected results of the reply.
|
154
|
+
# get_more.results(reply)
|
155
|
+
#
|
156
|
+
# @param [ Moped::Protocol::Reply ] reply The reply from the database.
|
157
|
+
#
|
158
|
+
# @return [ Moped::Protocol::Reply ] The reply.
|
159
|
+
#
|
160
|
+
# @since 2.0.0
|
161
|
+
def results(reply)
|
162
|
+
reply
|
163
|
+
end
|
93
164
|
end
|
94
165
|
end
|
95
166
|
end
|
@@ -90,6 +90,23 @@ module Moped
|
|
90
90
|
|
91
91
|
"%-12s database=%s collection=%s documents=%s flags=%s" % [type, database, collection, documents.inspect, flags.inspect]
|
92
92
|
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# Duplicate the attributes in the insert that need to be.
|
97
|
+
#
|
98
|
+
# @api private
|
99
|
+
#
|
100
|
+
# @example Clone the insert.
|
101
|
+
# insert.clone
|
102
|
+
#
|
103
|
+
# @param [ Insert ] The insert that was cloned from.
|
104
|
+
#
|
105
|
+
# @since 2.0.0
|
106
|
+
def initialize_copy(_)
|
107
|
+
@documents = documents.dup
|
108
|
+
@flags = flags.dup
|
109
|
+
end
|
93
110
|
end
|
94
111
|
end
|
95
112
|
end
|