@@ -171,9 +171,6 @@ def deliver(message, client, options = {})
171171 end
172172
173173 def serialize ( message , client , buffer = BSON ::ByteBuffer . new )
174- start_size = 0
175- final_message = message . maybe_compress ( compressor , options [ :zlib_compression_level ] )
176-
177174 # Driver specifications only mandate the fixed 16MiB limit for
178175 # serialized BSON documents. However, the server returns its
179176 # active serialized BSON document size limit in the ismaster response,
@@ -198,12 +195,41 @@ def serialize(message, client, buffer = BSON::ByteBuffer.new)
198195 max_bson_size += MAX_BSON_COMMAND_OVERHEAD
199196 end
200197
201- final_message . serialize ( buffer , max_bson_size )
202- if max_message_size &&
203- ( buffer . length - start_size ) > max_message_size
204- then
205- raise Error ::MaxMessageSize . new ( max_message_size )
198+ # RUBY-2234: It is necessary to check that the message size does not
199+ # exceed the maximum bson object size before compressing and serializing
200+ # the final message.
201+ #
202+ # This is to avoid the case where the user performs a bulk write
203+ # larger than 16MiB which, when compressed, becomes smaller than 16MiB.
204+ # If the driver does not split the bulk writes prior to compression,
205+ # the entire operation will be sent to the server, which will raise an
206+ # error because the uncompressed operation exceeds the maximum bson size.
207+ #
208+ # To address this problem, we serialize the message prior to compression
209+ # and raise an exception if the serialized message exceeds the maximum
210+ # bson size.
211+ if max_message_size
212+ # Create a separate buffer that contains the un-compressed message
213+ # for the purpose of checking its size. Write any pre-existing contents
214+ # from the original buffer into the temporary one.
215+ temp_buffer = BSON ::ByteBuffer . new
216+
217+ # TODO: address the fact that this line mutates the buffer.
218+ temp_buffer . put_bytes ( buffer . get_bytes ( buffer . length ) )
219+
220+ message . serialize ( temp_buffer , max_bson_size )
221+ if temp_buffer . length > max_message_size
222+ raise Error ::MaxMessageSize . new ( max_message_size )
223+ end
206224 end
225+
226+ # RUBY-2335: When the un-compressed message is smaller than the maximum
227+ # bson size limit, the message will be serialized twice. The operations
228+ # layer should be refactored to allow compression on an already-
229+ # serialized message.
230+ final_message = message . maybe_compress ( compressor , options [ :zlib_compression_level ] )
231+ final_message . serialize ( buffer , max_bson_size )
232+
207233 buffer
208234 end
209235 end
0 commit comments