@@ -186,9 +186,6 @@ def deliver(message, client, options = {})
186
186
end
187
187
188
188
def serialize ( message , client , buffer = BSON ::ByteBuffer . new )
189
- start_size = 0
190
- final_message = message . maybe_compress ( compressor , options [ :zlib_compression_level ] )
191
-
192
189
# Driver specifications only mandate the fixed 16MiB limit for
193
190
# serialized BSON documents. However, the server returns its
194
191
# active serialized BSON document size limit in the ismaster response,
@@ -213,12 +210,41 @@ def serialize(message, client, buffer = BSON::ByteBuffer.new)
213
210
max_bson_size += MAX_BSON_COMMAND_OVERHEAD
214
211
end
215
212
216
- final_message . serialize ( buffer , max_bson_size )
217
- if max_message_size &&
218
- ( buffer . length - start_size ) > max_message_size
219
- then
220
- raise Error ::MaxMessageSize . new ( max_message_size )
213
+ # RUBY-2234: It is necessary to check that the message size does not
214
+ # exceed the maximum bson object size before compressing and serializing
215
+ # the final message.
216
+ #
217
+ # This is to avoid the case where the user performs a bulk write
218
+ # larger than 16MiB which, when compressed, becomes smaller than 16MiB.
219
+ # If the driver does not split the bulk writes prior to compression,
220
+ # the entire operation will be sent to the server, which will raise an
221
+ # error because the uncompressed operation exceeds the maximum bson size.
222
+ #
223
+ # To address this problem, we serialize the message prior to compression
224
+ # and raise an exception if the serialized message exceeds the maximum
225
+ # bson size.
226
+ if max_message_size
227
+ # Create a separate buffer that contains the un-compressed message
228
+ # for the purpose of checking its size. Write any pre-existing contents
229
+ # from the original buffer into the temporary one.
230
+ temp_buffer = BSON ::ByteBuffer . new
231
+
232
+ # TODO: address the fact that this line mutates the buffer.
233
+ temp_buffer . put_bytes ( buffer . get_bytes ( buffer . length ) )
234
+
235
+ message . serialize ( temp_buffer , max_bson_size )
236
+ if temp_buffer . length > max_message_size
237
+ raise Error ::MaxMessageSize . new ( max_message_size )
238
+ end
221
239
end
240
+
241
+ # RUBY-2335: When the un-compressed message is smaller than the maximum
242
+ # bson size limit, the message will be serialized twice. The operations
243
+ # layer should be refactored to allow compression on an already-
244
+ # serialized message.
245
+ final_message = message . maybe_compress ( compressor , options [ :zlib_compression_level ] )
246
+ final_message . serialize ( buffer , max_bson_size )
247
+
222
248
buffer
223
249
end
224
250
end
0 commit comments