mongo 2.0.6 → 2.1.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo.rb +2 -0
  5. data/lib/mongo/bulk_write.rb +1 -0
  6. data/lib/mongo/bulk_write/bulk_writable.rb +87 -31
  7. data/lib/mongo/bulk_write/deletable.rb +8 -7
  8. data/lib/mongo/bulk_write/insertable.rb +4 -3
  9. data/lib/mongo/bulk_write/ordered_bulk_write.rb +6 -6
  10. data/lib/mongo/bulk_write/replacable.rb +4 -3
  11. data/lib/mongo/bulk_write/result.rb +138 -0
  12. data/lib/mongo/bulk_write/unordered_bulk_write.rb +5 -8
  13. data/lib/mongo/bulk_write/updatable.rb +8 -7
  14. data/lib/mongo/client.rb +36 -4
  15. data/lib/mongo/cluster.rb +39 -4
  16. data/lib/mongo/cluster/topology/replica_set.rb +20 -4
  17. data/lib/mongo/cluster/topology/sharded.rb +1 -1
  18. data/lib/mongo/collection.rb +282 -29
  19. data/lib/mongo/collection/view/aggregation.rb +32 -4
  20. data/lib/mongo/collection/view/iterable.rb +2 -1
  21. data/lib/mongo/collection/view/map_reduce.rb +3 -1
  22. data/lib/mongo/collection/view/readable.rb +89 -14
  23. data/lib/mongo/collection/view/writable.rb +11 -5
  24. data/lib/mongo/cursor.rb +11 -3
  25. data/lib/mongo/dbref.rb +113 -0
  26. data/lib/mongo/error.rb +6 -2
  27. data/lib/mongo/error/parser.rb +1 -1
  28. data/lib/mongo/event/description_changed.rb +1 -1
  29. data/lib/mongo/grid/file.rb +1 -1
  30. data/lib/mongo/grid/fs.rb +2 -5
  31. data/lib/mongo/monitoring.rb +199 -0
  32. data/lib/mongo/monitoring/command_log_subscriber.rb +88 -0
  33. data/lib/mongo/monitoring/event.rb +17 -0
  34. data/lib/mongo/monitoring/event/command_failed.rb +96 -0
  35. data/lib/mongo/monitoring/event/command_started.rb +88 -0
  36. data/lib/mongo/monitoring/event/command_succeeded.rb +96 -0
  37. data/lib/mongo/monitoring/publishable.rb +96 -0
  38. data/lib/mongo/operation.rb +1 -0
  39. data/lib/mongo/operation/executable.rb +1 -1
  40. data/lib/mongo/operation/parallel_scan.rb +76 -0
  41. data/lib/mongo/operation/parallel_scan/result.rb +72 -0
  42. data/lib/mongo/operation/specifiable.rb +18 -0
  43. data/lib/mongo/operation/write/bulk/bulk_delete.rb +1 -1
  44. data/lib/mongo/operation/write/bulk/bulk_insert.rb +1 -1
  45. data/lib/mongo/operation/write/bulk/bulk_mergable.rb +2 -2
  46. data/lib/mongo/operation/write/bulk/bulk_update.rb +1 -1
  47. data/lib/mongo/operation/write/bulk/bulk_update/result.rb +13 -1
  48. data/lib/mongo/protocol/delete.rb +8 -13
  49. data/lib/mongo/protocol/get_more.rb +13 -13
  50. data/lib/mongo/protocol/insert.rb +8 -13
  51. data/lib/mongo/protocol/kill_cursors.rb +7 -11
  52. data/lib/mongo/protocol/query.rb +58 -20
  53. data/lib/mongo/protocol/reply.rb +12 -0
  54. data/lib/mongo/protocol/update.rb +13 -14
  55. data/lib/mongo/server.rb +23 -2
  56. data/lib/mongo/server/connectable.rb +0 -22
  57. data/lib/mongo/server/connection.rb +29 -0
  58. data/lib/mongo/server/description.rb +23 -1
  59. data/lib/mongo/server/monitor.rb +17 -1
  60. data/lib/mongo/server/monitor/connection.rb +24 -0
  61. data/lib/mongo/socket/ssl.rb +28 -16
  62. data/lib/mongo/socket/tcp.rb +1 -1
  63. data/lib/mongo/socket/unix.rb +1 -1
  64. data/lib/mongo/uri.rb +12 -5
  65. data/lib/mongo/version.rb +1 -1
  66. data/spec/mongo/auth/cr_spec.rb +9 -1
  67. data/spec/mongo/auth/ldap_spec.rb +9 -1
  68. data/spec/mongo/auth/scram_spec.rb +9 -1
  69. data/spec/mongo/auth/x509_spec.rb +9 -1
  70. data/spec/mongo/{bulk/bulk_write_spec.rb → bulk_write_spec.rb} +15 -15
  71. data/spec/mongo/client_spec.rb +42 -0
  72. data/spec/mongo/cluster/topology/replica_set_spec.rb +16 -9
  73. data/spec/mongo/cluster/topology/sharded_spec.rb +11 -3
  74. data/spec/mongo/cluster/topology/single_spec.rb +12 -4
  75. data/spec/mongo/cluster_spec.rb +55 -10
  76. data/spec/mongo/collection/view/aggregation_spec.rb +123 -1
  77. data/spec/mongo/collection/view/explainable_spec.rb +1 -1
  78. data/spec/mongo/collection/view/map_reduce_spec.rb +1 -1
  79. data/spec/mongo/collection/view/readable_spec.rb +251 -6
  80. data/spec/mongo/collection/view/writable_spec.rb +4 -4
  81. data/spec/mongo/collection/view_spec.rb +233 -71
  82. data/spec/mongo/collection_spec.rb +905 -9
  83. data/spec/mongo/crud_spec.rb +2 -2
  84. data/spec/mongo/cursor_spec.rb +3 -3
  85. data/spec/mongo/dbref_spec.rb +149 -0
  86. data/spec/mongo/monitoring_spec.rb +168 -0
  87. data/spec/mongo/operation/map_reduce_spec.rb +1 -1
  88. data/spec/mongo/operation/write/bulk/bulk_delete_spec.rb +1 -1
  89. data/spec/mongo/operation/write/bulk/bulk_insert_spec.rb +2 -2
  90. data/spec/mongo/operation/write/bulk/bulk_update_spec.rb +1 -1
  91. data/spec/mongo/operation/write/delete_spec.rb +1 -1
  92. data/spec/mongo/operation/write/insert_spec.rb +2 -2
  93. data/spec/mongo/operation/write/update_spec.rb +1 -1
  94. data/spec/mongo/protocol/query_spec.rb +0 -29
  95. data/spec/mongo/server/connection_pool_spec.rb +18 -6
  96. data/spec/mongo/server/connection_spec.rb +12 -4
  97. data/spec/mongo/server/description_spec.rb +7 -3
  98. data/spec/mongo/server/monitor_spec.rb +30 -0
  99. data/spec/mongo/server_discovery_and_monitoring_spec.rb +11 -4
  100. data/spec/mongo/server_selection_spec.rb +14 -6
  101. data/spec/mongo/server_spec.rb +27 -8
  102. data/spec/mongo/socket/ssl_spec.rb +94 -8
  103. data/spec/mongo/uri_spec.rb +25 -9
  104. data/spec/spec_helper.rb +29 -20
  105. data/spec/support/authorization.rb +19 -4
  106. data/spec/support/certificates/client.pem +4 -4
  107. data/spec/support/crud/read.rb +9 -10
  108. data/spec/support/crud/write.rb +24 -20
  109. data/spec/support/sdam/rs/equal_electionids.yml +45 -0
  110. data/spec/support/sdam/rs/new_primary_new_electionid.yml +98 -0
  111. data/spec/support/sdam/rs/null_election_id.yml +144 -0
  112. data/spec/support/sdam/rs/primary_disconnect_electionid.yml +124 -0
  113. data/spec/support/sdam/sharded/mongos_disconnect.yml +104 -0
  114. data/spec/support/server_discovery_and_monitoring.rb +19 -2
  115. data/spec/support/shared/bulk_write.rb +26 -22
  116. data/spec/support/shared/server_selector.rb +2 -1
  117. metadata +31 -7
  118. metadata.gz.sig +0 -0
  119. data/lib/mongo/error/invalid_uri_option.rb +0 -38
@@ -76,6 +76,11 @@ module Mongo
76
76
  # @since 2.0.0
77
77
  INDEX_NAME = :index_name.freeze
78
78
 
79
+ # The operation id constant.
80
+ #
81
+ # @since 2.1.0
82
+ OPERATION_ID = :operation_id.freeze
83
+
79
84
  # The field for options.
80
85
  #
81
86
  # @since 2.0.0
@@ -287,6 +292,19 @@ module Mongo
287
292
  @spec = spec
288
293
  end
289
294
 
295
+ # Get the operation id for the operation. Used for linking operations in
296
+ # monitoring.
297
+ #
298
+ # @example Get the operation id.
299
+ # specifiable.operation_id
300
+ #
301
+ # @return [ Integer ] The operation id.
302
+ #
303
+ # @since 2.1.0
304
+ def operation_id
305
+ spec[OPERATION_ID]
306
+ end
307
+
290
308
  # Get the options for the operation.
291
309
  #
292
310
  # @example Get the options.
@@ -94,7 +94,7 @@ module Mongo
94
94
  def execute_message(context)
95
95
  replies = messages.map do |m|
96
96
  context.with_connection do |connection|
97
- result = LegacyResult.new(connection.dispatch([ m, gle ].compact))
97
+ result = LegacyResult.new(connection.dispatch([ m, gle ].compact, operation_id))
98
98
  if stop_sending?(result)
99
99
  return result
100
100
  else
@@ -79,7 +79,7 @@ module Mongo
79
79
  replies = []
80
80
  messages.map do |m|
81
81
  context.with_connection do |connection|
82
- result = LegacyResult.new(connection.dispatch([ m, gle ].compact), @ids)
82
+ result = LegacyResult.new(connection.dispatch([ m, gle ].compact, operation_id), @ids)
83
83
  replies << result.reply
84
84
  if stop_sending?(result)
85
85
  return LegacyResult.new(replies, @ids)
@@ -32,7 +32,7 @@ module Mongo
32
32
  def aggregate_write_errors(indexes)
33
33
  @replies.reduce(nil) do |errors, reply|
34
34
  if reply.documents.first['writeErrors']
35
- write_errors = reply.documents.first['writeErrors'].collect do |we|
35
+ write_errors = reply.documents.first[Error::WRITE_ERRORS].collect do |we|
36
36
  we.merge!('index' => indexes[we['index']])
37
37
  end
38
38
  (errors || []) << write_errors if write_errors
@@ -53,7 +53,7 @@ module Mongo
53
53
  # @since 2.0.0
54
54
  def aggregate_write_concern_errors(indexes)
55
55
  @replies.each_with_index.reduce(nil) do |errors, (reply, i)|
56
- if write_concern_errors = reply.documents.first['writeConcernErrors']
56
+ if write_concern_errors = reply.documents.first[Error::WRITE_CONCERN_ERRORS]
57
57
  (errors || []) << write_concern_errors.reduce(nil) do |errs, wce|
58
58
  wce.merge!('index' => indexes[wce['index']])
59
59
  (errs || []) << write_concern_error
@@ -101,7 +101,7 @@ module Mongo
101
101
  def execute_message(context)
102
102
  replies = messages.map do |m|
103
103
  context.with_connection do |connection|
104
- result = LegacyResult.new(connection.dispatch([ m, gle ].compact))
104
+ result = LegacyResult.new(connection.dispatch([ m, gle ].compact, operation_id))
105
105
  if stop_sending?(result)
106
106
  return result
107
107
  else
@@ -89,10 +89,22 @@ module Mongo
89
89
  end
90
90
  end
91
91
 
92
+ # Get the upserted documents.
93
+ #
94
+ # @example Get upserted documents.
95
+ # result.upserted
96
+ #
97
+ # @return [ Array<BSON::Document> ] The upserted document info
98
+ #
99
+ # @since 2.1.0
100
+ def upserted
101
+ reply.documents.first[UPSERTED] || []
102
+ end
103
+
92
104
  private
93
105
 
94
106
  def upsert?(reply)
95
- reply.documents.first[UPSERTED]
107
+ upserted.any?
96
108
  end
97
109
  end
98
110
 
@@ -41,27 +41,22 @@ module Mongo
41
41
  #
42
42
  # Supported flags: +:single_remove+
43
43
  def initialize(database, collection, selector, options = {})
44
+ @database = database
44
45
  @namespace = "#{database}.#{collection}"
45
46
  @selector = selector
46
47
  @flags = options[:flags] || []
47
48
  end
48
49
 
49
- # The log message for a delete operation.
50
+ # Return the event payload for monitoring.
50
51
  #
51
- # @example Get the log message.
52
- # delete.log_message
52
+ # @example Return the event payload.
53
+ # message.payload
53
54
  #
54
- # @return [ String ] The log message
55
+ # @return [ Hash ] The event payload.
55
56
  #
56
- # @since 2.0.0
57
- def log_message
58
- fields = []
59
- fields << ["%s |", "DELETE"]
60
- fields << ["namespace=%s", namespace]
61
- fields << ["selector=%s", selector.inspect]
62
- fields << ["flags=%s", flags.inspect]
63
- f, v = fields.transpose
64
- f.join(" ") % v
57
+ # @since 2.1.0
58
+ def payload
59
+ { command_name: 'delete', database_name: @database, command: selector, request_id: request_id }
65
60
  end
66
61
 
67
62
  private
@@ -37,27 +37,27 @@ module Mongo
37
37
  # @param number_to_return [Integer] The number of documents to return.
38
38
  # @param cursor_id [Integer] The cursor id returned in a reply.
39
39
  def initialize(database, collection, number_to_return, cursor_id)
40
+ @database = database
40
41
  @namespace = "#{database}.#{collection}"
41
42
  @number_to_return = number_to_return
42
43
  @cursor_id = cursor_id
43
44
  end
44
45
 
45
- # The log message for a get more operation.
46
+ # Return the event payload for monitoring.
46
47
  #
47
- # @example Get the log message.
48
- # get_more.log_message
48
+ # @example Return the event payload.
49
+ # message.payload
49
50
  #
50
- # @return [ String ] The log message
51
+ # @return [ Hash ] The event payload.
51
52
  #
52
- # @since 2.0.0
53
- def log_message
54
- fields = []
55
- fields << ["%s |", "GETMORE"]
56
- fields << ["namespace=%s", namespace]
57
- fields << ["number_to_return=%s", number_to_return]
58
- fields << ["cursor_id=%s", cursor_id]
59
- f, v = fields.transpose
60
- f.join(" ") % v
53
+ # @since 2.1.0
54
+ def payload
55
+ {
56
+ command_name: 'getmore',
57
+ database_name: @database,
58
+ command: { cursor_id: cursor_id, number_to_return: number_to_return },
59
+ request_id: request_id
60
+ }
61
61
  end
62
62
 
63
63
  # Get more messages require replies from the database.
@@ -49,27 +49,22 @@ module Mongo
49
49
  #
50
50
  # Supported flags: +:continue_on_error+
51
51
  def initialize(database, collection, documents, options = {})
52
+ @database = database
52
53
  @namespace = "#{database}.#{collection}"
53
54
  @documents = documents
54
55
  @flags = options[:flags] || []
55
56
  end
56
57
 
57
- # The log message for a insert operation.
58
+ # Return the event payload for monitoring.
58
59
  #
59
- # @example Get the log message.
60
- # insert.log_message
60
+ # @example Return the event payload.
61
+ # message.payload
61
62
  #
62
- # @return [ String ] The log message
63
+ # @return [ Hash ] The event payload.
63
64
  #
64
- # @since 2.0.0
65
- def log_message
66
- fields = []
67
- fields << ["%s |", "INSERT"]
68
- fields << ["namespace=%s", namespace]
69
- fields << ["documents=%s", documents.inspect]
70
- fields << ["flags=%s", flags.inspect]
71
- f, v = fields.transpose
72
- f.join(" ") % v
65
+ # @since 2.1.0
66
+ def payload
67
+ { command_name: 'insert', database_name: @database, command: documents, request_id: request_id }
73
68
  end
74
69
 
75
70
  private
@@ -35,20 +35,16 @@ module Mongo
35
35
  @id_count = @cursor_ids.size
36
36
  end
37
37
 
38
- # The log message for a kill cursors operation.
38
+ # Return the event payload for monitoring.
39
39
  #
40
- # @example Get the log message.
41
- # kill_cursors.log_message
40
+ # @example Return the event payload.
41
+ # message.payload
42
42
  #
43
- # @return [ String ] The log message
43
+ # @return [ Hash ] The event payload.
44
44
  #
45
- # @since 2.0.0
46
- def log_message
47
- fields = []
48
- fields << ["%s |", "KILLCURSORS"]
49
- fields << ["cursor_ids=%s", cursor_ids.inspect]
50
- f, v = fields.transpose
51
- f.join(" ") % v
45
+ # @since 2.1.0
46
+ def payload
47
+ { command_name: 'killcursors', command: { cursor_ids: cursor_ids }, request_id: request_id }
52
48
  end
53
49
 
54
50
  private
@@ -64,33 +64,75 @@ module Mongo
64
64
  # Supported flags: +:tailable_cursor+, +:slave_ok+, +:oplog_replay+,
65
65
  # +:no_cursor_timeout+, +:await_data+, +:exhaust+, +:partial+
66
66
  def initialize(database, collection, selector, options = {})
67
+ @database = database
67
68
  @namespace = "#{database}.#{collection}"
68
69
  @selector = selector
70
+ @options = options
69
71
  @project = options[:project]
70
72
  @skip = options[:skip] || 0
71
73
  @limit = options[:limit] || 0
72
74
  @flags = options[:flags] || []
73
75
  end
74
76
 
75
- # The log message for a query operation.
77
+ # Return the event payload for monitoring.
76
78
  #
77
- # @example Get the log message.
78
- # query.log_message
79
+ # @example Return the event payload.
80
+ # message.payload
79
81
  #
80
- # @return [ String ] The log message
82
+ # @return [ Hash ] The event payload.
81
83
  #
82
- # @since 2.0.0
83
- def log_message
84
- fields = []
85
- fields << ["%s |", query_type]
86
- fields << ["namespace=%s", namespace]
87
- fields << ["selector=%s", formatted_selector]
88
- fields << ["flags=%s", flags.inspect]
89
- fields << ["limit=%s", limit.inspect]
90
- fields << ["skip=%s", skip.inspect]
91
- fields << ["project=%s", project.inspect]
92
- f, v = fields.transpose
93
- f.join(" ") % v
84
+ # @since 2.1.0
85
+ def payload
86
+ {
87
+ command_name: command_name,
88
+ database_name: @database,
89
+ command: arguments,
90
+ request_id: request_id
91
+ }
92
+ end
93
+
94
+ # If the message a command?
95
+ #
96
+ # @example Is the message a command?
97
+ # message.command?
98
+ #
99
+ # @return [ true, false ] If the message is a command.
100
+ #
101
+ # @since 2.1.0
102
+ def command?
103
+ namespace.include?(Database::COMMAND)
104
+ end
105
+
106
+ # Returns the name of the command.
107
+ #
108
+ # @example Get the command name.
109
+ # message.command_name
110
+ #
111
+ # @return [ String ] The name of the command, or 'find' if a query.
112
+ #
113
+ # @since 2.1.0
114
+ def command_name
115
+ if command?
116
+ selector.keys.first
117
+ else
118
+ 'find'
119
+ end
120
+ end
121
+
122
+ # Get the command arguments.
123
+ #
124
+ # @example Get the command arguments.
125
+ # message.arguments
126
+ #
127
+ # @return [ Hash ] The command arguments.
128
+ #
129
+ # @since 2.1.0
130
+ def arguments
131
+ if command?
132
+ selector
133
+ else
134
+ { filter: selector }.merge(@options)
135
+ end
94
136
  end
95
137
 
96
138
  # Query messages require replies from the database.
@@ -113,10 +155,6 @@ module Mongo
113
155
  2004
114
156
  end
115
157
 
116
- def query_type
117
- namespace.include?(Database::COMMAND) ? 'COMMAND' : 'QUERY'
118
- end
119
-
120
158
  def formatted_selector
121
159
  ( (str = selector.inspect).length > LOG_STRING_LIMIT ) ?
122
160
  "#{str[0..LOG_STRING_LIMIT]}..." : str
@@ -38,6 +38,18 @@ module Mongo
38
38
  flags.include?(:query_failure)
39
39
  end
40
40
 
41
+ # Return the event payload for monitoring.
42
+ #
43
+ # @example Return the event payload.
44
+ # message.payload
45
+ #
46
+ # @return [ Hash ] The event payload.
47
+ #
48
+ # @since 2.1.0
49
+ def payload
50
+ { reply: documents, request_id: request_id }
51
+ end
52
+
41
53
  private
42
54
 
43
55
  # The operation code required to specify a Reply message.
@@ -52,29 +52,28 @@ module Mongo
52
52
  #
53
53
  # Supported flags: +:upsert+, +:multi_update+
54
54
  def initialize(database, collection, selector, update, options = {})
55
+ @database = database
55
56
  @namespace = "#{database}.#{collection}"
56
57
  @selector = selector
57
58
  @update = update
58
59
  @flags = options[:flags] || []
59
60
  end
60
61
 
61
- # The log message for an update operation.
62
+ # Return the event payload for monitoring.
62
63
  #
63
- # @example Get the log message.
64
- # update.log_message
64
+ # @example Return the event payload.
65
+ # message.payload
65
66
  #
66
- # @return [ String ] The log message
67
+ # @return [ Hash ] The event payload.
67
68
  #
68
- # @since 2.0.0
69
- def log_message
70
- fields = []
71
- fields << ["%s |", "UPDATE"]
72
- fields << ["namespace=%s", namespace]
73
- fields << ["selector=%s", selector.inspect]
74
- fields << ["udpdate=%s", update.inspect]
75
- fields << ["flags=%s", flags.inspect]
76
- f, v = fields.transpose
77
- f.join(" ") % v
69
+ # @since 2.1.0
70
+ def payload
71
+ {
72
+ command_name: 'update',
73
+ database_name: @database,
74
+ command: { filter: selector, update: update },
75
+ request_id: request_id
76
+ }
78
77
  end
79
78
 
80
79
  private
@@ -40,6 +40,9 @@ module Mongo
40
40
  # @return [ Hash ] The options hash.
41
41
  attr_reader :options
42
42
 
43
+ # @return [ Monitoring ] monitoring The monitoring.
44
+ attr_reader :monitoring
45
+
43
46
  # Get the description from the monitor and scan on monitor.
44
47
  def_delegators :monitor, :description, :scan!
45
48
 
@@ -107,18 +110,24 @@ module Mongo
107
110
  # Instantiate a new server object. Will start the background refresh and
108
111
  # subscribe to the appropriate events.
109
112
  #
113
+ # @api private
114
+ #
110
115
  # @example Initialize the server.
111
- # Mongo::Server.new('127.0.0.1:27017', cluster, listeners)
116
+ # Mongo::Server.new('127.0.0.1:27017', cluster, monitoring, listeners)
117
+ #
118
+ # @note Server must never be directly instantiated outside of a Cluster.
112
119
  #
113
120
  # @param [ Address ] address The host:port address to connect to.
114
121
  # @param [ Cluster ] cluster The cluster the server belongs to.
122
+ # @param [ Monitoring ] monitoring The monitoring.
115
123
  # @param [ Event::Listeners ] event_listeners The event listeners.
116
124
  # @param [ Hash ] options The server options.
117
125
  #
118
126
  # @since 2.0.0
119
- def initialize(address, cluster, event_listeners, options = {})
127
+ def initialize(address, cluster, monitoring, event_listeners, options = {})
120
128
  @address = address
121
129
  @cluster = cluster
130
+ @monitoring = monitoring
122
131
  @options = options.freeze
123
132
  @monitor = Monitor.new(address, event_listeners, options)
124
133
  monitor.scan!
@@ -164,5 +173,17 @@ module Mongo
164
173
  tags[k] && tags[k] == tag_set[k]
165
174
  end
166
175
  end
176
+
177
+ # Restart the server monitor.
178
+ #
179
+ # @example Restart the server monitor.
180
+ # server.reconnect!
181
+ #
182
+ # @return [ true ] Always true.
183
+ #
184
+ # @since 2.1.0
185
+ def reconnect!
186
+ monitor.restart! and true
187
+ end
167
188
  end
168
189
  end