Skip to content

Commit 9f1e62b

Browse files
committed
Added BsonReader.peekBinarySubType as a more efficient alternative to BsonReader.mark/reset, to avoid
a double copy of the byte array.
1 parent 5193ecd commit 9f1e62b

File tree

7 files changed

+81
-6
lines changed

7 files changed

+81
-6
lines changed

bson/src/main/org/bson/AbstractBsonReader.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ protected boolean isClosed() {
112112
*/
113113
protected abstract BsonBinary doReadBinaryData();
114114

115+
/**
116+
* Handles the logic to peek at the binary subtype.
117+
*
118+
* @return the binary subtype
119+
*/
120+
protected abstract byte doPeekBinarySubType();
115121

116122
/**
117123
* Handles the logic to read booleans
@@ -261,6 +267,12 @@ public BsonBinary readBinaryData() {
261267
return doReadBinaryData();
262268
}
263269

270+
@Override
271+
public byte peekBinarySubType() {
272+
checkPreconditions("readBinaryData", BsonType.BINARY);
273+
return doPeekBinarySubType();
274+
}
275+
264276
@Override
265277
public boolean readBoolean() {
266278
checkPreconditions("readBoolean", BsonType.BOOLEAN);

bson/src/main/org/bson/BsonBinaryReader.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ protected BsonBinary doReadBinaryData() {
130130
return new BsonBinary(type, bytes);
131131
}
132132

133+
@Override
134+
protected byte doPeekBinarySubType() {
135+
mark();
136+
bsonInput.readInt32();
137+
byte type = bsonInput.readByte();
138+
reset();
139+
return type;
140+
}
141+
133142
@Override
134143
protected boolean doReadBoolean() {
135144
return bsonInput.readByte() == 0x1;

bson/src/main/org/bson/BsonDocumentReader.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ protected BsonBinary doReadBinaryData() {
3636
return currentValue.asBinary();
3737
}
3838

39+
@Override
40+
protected byte doPeekBinarySubType() {
41+
return currentValue.asBinary().getType();
42+
}
43+
3944
@Override
4045
protected boolean doReadBoolean() {
4146
return currentValue.asBoolean().getValue();

bson/src/main/org/bson/BsonReader.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ public interface BsonReader {
4343
*/
4444
BsonBinary readBinaryData();
4545

46+
/**
47+
* Peeks the subtype of the binary data that the reader is positioned at. This operation is not permitted if the mark is already set.
48+
*
49+
* @return the subtype
50+
* @see #mark()
51+
*/
52+
byte peekBinarySubType();
53+
4654
/**
4755
* Reads a BSON Binary data element from the reader.
4856
*
@@ -358,5 +366,4 @@ public interface BsonReader {
358366
* @throws org.bson.BSONException if no mark has been set
359367
*/
360368
void reset();
361-
362369
}

bson/src/main/org/bson/json/JsonReader.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ protected BsonBinary doReadBinaryData() {
8080
return (BsonBinary) currentValue;
8181
}
8282

83+
@Override
84+
protected byte doPeekBinarySubType() {
85+
return doReadBinaryData().getType();
86+
}
87+
8388
@Override
8489
protected boolean doReadBoolean() {
8590
return (Boolean) currentValue;

bson/src/test/org/bson/LimitedLookaheadMarkSpecification.groovy

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,44 @@ class LimitedLookaheadMarkSpecification extends Specification {
241241
new JsonWriter(new StringWriter())
242242
]
243243
}
244+
245+
def 'should peek binary subtype'(BsonWriter writer) {
246+
given:
247+
writer.with {
248+
writeStartDocument()
249+
writeBinaryData('binary', new BsonBinary(BsonBinarySubType.UUID_LEGACY, new byte[16]))
250+
writeInt64('int64', 52L)
251+
writeEndDocument()
252+
}
253+
254+
when:
255+
BsonReader reader
256+
if (writer instanceof BsonDocumentWriter) {
257+
reader = new BsonDocumentReader(writer.document)
258+
} else if (writer instanceof BsonBinaryWriter) {
259+
BasicOutputBuffer buffer = (BasicOutputBuffer) writer.getBsonOutput();
260+
reader = new BsonBinaryReader(new ByteBufferBsonInput(buffer.getByteBuffers().get(0)), true)
261+
} else if (writer instanceof JsonWriter) {
262+
reader = new JsonReader(writer.writer.toString())
263+
}
264+
265+
reader.readStartDocument()
266+
reader.readName()
267+
def subType = reader.peekBinarySubType()
268+
def binary = reader.readBinaryData()
269+
def longValue = reader.readInt64('int64')
270+
reader.readEndDocument()
271+
272+
then:
273+
subType == BsonBinarySubType.UUID_LEGACY.value
274+
binary == new BsonBinary(BsonBinarySubType.UUID_LEGACY, new byte[16])
275+
longValue == 52L
276+
277+
where:
278+
writer << [
279+
new BsonDocumentWriter(new BsonDocument()),
280+
new BsonBinaryWriter(new BasicOutputBuffer(), false),
281+
new JsonWriter(new StringWriter())
282+
]
283+
}
244284
}

driver-core/src/main/com/mongodb/codecs/DocumentCodec.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,8 @@ private Object readValue(final BsonReader reader, final DecoderContext decoderCo
178178
reader.readNull();
179179
return null;
180180
} else if (bsonType == BsonType.BINARY) {
181-
reader.mark();
182-
byte bsonSubType = reader.readBinaryData().getType();
183-
reader.reset();
184-
if (bsonSubType == BsonBinarySubType.UUID_STANDARD.getValue()
185-
|| bsonSubType == BsonBinarySubType.UUID_LEGACY.getValue()) {
181+
byte bsonSubType = reader.peekBinarySubType();
182+
if (bsonSubType == BsonBinarySubType.UUID_STANDARD.getValue() || bsonSubType == BsonBinarySubType.UUID_LEGACY.getValue()) {
186183
return registry.get(UUID.class).decode(reader, decoderContext);
187184
}
188185
}

0 commit comments

Comments
 (0)