mongo 2.0.6 → 2.1.0.beta

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