-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ByteBufBsonDocument remains a ByteBuf #1119
Conversation
3d439c8
to
183edf6
Compare
* Ensure that ByteBufBsonDocument never hydrates itself into a HashMap * Add ByteBufBsonArray and ensure it never hydrates itself into an ArrayList JAVA-4917
@@ -237,7 +237,7 @@ public int hashCode() { | |||
@Override | |||
public String toString() { | |||
return "BsonArray{" | |||
+ "values=" + values |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To allow subclasses to override #getValues
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To simplify the design, this class was merged into the only actual subclass, `ByteBufBsonDocument``
|
||
import static com.mongodb.internal.connection.ByteBufBsonHelper.readBsonValue; | ||
|
||
public class ByteBufBsonArray extends BsonArray { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of the implementation of the overridden methods in this class were adapted from the JDKs abstract collection classes. Unfortunately, we can't just call the existing methods directly due to the fact that we have to extend BsonArray rather than, say, AbstractList. This is due to a design flaw in the driver. Really, BsonArray and BsonDocument should have been interfaces, but because they are classes we are forced to extend them rather than implement them, and the subclasses (like this one) have to do a lot of work to ensure that the base class implementations are not used (effectively treating them as interfaces or pure abstract classes.
|
||
@Override | ||
public ListIterator<BsonValue> listIterator(final int index) { | ||
// Not the most efficient way to do this, but unlikely anyone will notice in practice |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's worth investing in a more efficient ListIterator
implementation. Ultimately, it's going to have to hydrate the array, so it's not going to be much better than this for most use cases.
private static final long serialVersionUID = 2L; | ||
|
||
private final transient ByteBuf byteBuf; | ||
|
||
static List<ByteBufBsonDocument> createList(final ResponseBuffers responseBuffers) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused method
byteBuf.get(byteBuf.position(), clonedBytes); | ||
return new RawBsonDocument(clonedBytes); | ||
} | ||
|
||
@Nullable | ||
<T> T findInDocument(final Finder<T> finder) { | ||
ByteBuf duplicateByteBuf = byteBuf.duplicate(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The double duplication of the byte buf was unintentional, but caused a bug once the hydration behavior was changed
bsonReader.readStartDocument(); | ||
while (bsonReader.readBsonType() != BsonType.END_OF_DOCUMENT) { | ||
T found = finder.find(bsonReader); | ||
T found = finder.find(duplicateByteBuf, bsonReader); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now we need the byte buf sent to the finder to avoid hydration of nested documents/arrays
return values; | ||
} | ||
|
||
private static final String READ_ONLY_MESSAGE = "This BsonArray instance is read-only"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: static final can be moved to the top of the class
|
||
@Override | ||
public int size() { | ||
int size = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the ByteBufBsonArray
is read-only and its size doesn't change after initialization, we can consider storing the size
value after first call to avoid additional computations during each size()
call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's true, and I did consider a few optimizations like this but decided to keep it simple.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Could / should RawBsonDocument now delegate to ByteBufBsonDocument internally?
Would save two very similar document types.
@SuppressWarnings("unchecked") | ||
public <T> T[] toArray(final T[] a) { | ||
int size = size(); | ||
T[] retVal = a.length >= size ? a : (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow - that's gnarly
Added JAVA-5023 to consider this |
This one got a bit complicated. The root cause of the bug is that
ByteBufBsonDocument#entrySet
hydrates its byte buffer into the base class's hash map instead of implementing the entry set via iterating over the raw BSON. To avoid this hydration completely, including for nested documents and arrays, requires quite a few code changes, including the introduction of a new class,ByteBufBsonArray
, that does the same job for nested arrays.JAVA-4917