@@ -171,9 +171,6 @@ def deliver(message, client, options = {})
171
171
end
172
172
173
173
def serialize ( message , client , buffer = BSON ::ByteBuffer . new )
174
- start_size = 0
175
- final_message = message . maybe_compress ( compressor , options [ :zlib_compression_level ] )
176
-
177
174
# Driver specifications only mandate the fixed 16MiB limit for
178
175
# serialized BSON documents. However, the server returns its
179
176
# active serialized BSON document size limit in the ismaster response,
@@ -198,12 +195,41 @@ def serialize(message, client, buffer = BSON::ByteBuffer.new)
198
195
max_bson_size += MAX_BSON_COMMAND_OVERHEAD
199
196
end
200
197
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
206
224
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
+
207
233
buffer
208
234
end
209
235
end
0 commit comments