Skip to content

Commit d43b83d

Browse files
committed
Merge branch 'refs/heads/main' into string-read-optm
2 parents 7199945 + 1c3fdc8 commit d43b83d

File tree

12 files changed

+823
-41
lines changed

12 files changed

+823
-41
lines changed

.evergreen/.evg.yml

+4
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,8 @@ tasks:
15421542
# Do not rename this task – renaming resets the performance time series
15431543
- name: "perf"
15441544
tags: ["perf"]
1545+
# Benchmark could exceed 1 hour of execution.
1546+
exec_timeout_secs: 7200
15451547
commands:
15461548
- func: "bootstrap mongo-orchestration"
15471549
vars:
@@ -1554,6 +1556,8 @@ tasks:
15541556

15551557
- name: "perf-netty"
15561558
tags: [ "perf" ]
1559+
# Benchmark could exceed 1 hour of execution.
1560+
exec_timeout_secs: 7200
15571561
commands:
15581562
- func: "bootstrap mongo-orchestration"
15591563
vars:

bson/src/main/org/bson/BsonBinaryWriter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ public void doWriteNull() {
289289
public void doWriteObjectId(final ObjectId value) {
290290
bsonOutput.writeByte(BsonType.OBJECT_ID.getValue());
291291
writeCurrentName();
292-
bsonOutput.writeBytes(value.toByteArray());
292+
bsonOutput.writeObjectId(value);
293293
}
294294

295295
@Override

bson/src/main/org/bson/ByteBuf.java

+48
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,54 @@ public interface ByteBuf {
106106
*/
107107
ByteBuf put(byte b);
108108

109+
/**
110+
* Writes the given int value into this buffer at the current position,
111+
* using the current byte order, and increments the position by 4.
112+
*
113+
* @param b the int value to be written
114+
* @return this buffer
115+
* @throws java.nio.BufferOverflowException if there are fewer than 4 bytes remaining in this buffer
116+
* @throws java.nio.ReadOnlyBufferException if this buffer is read-only
117+
* @since 5.4
118+
*/
119+
ByteBuf putInt(int b);
120+
121+
/**
122+
* Writes the given int value into this buffer at the current position,
123+
* using the current byte order, and increments the position by 4.
124+
*
125+
* @param b the int value to be written
126+
* @return this buffer
127+
* @throws java.nio.BufferOverflowException if there are fewer than 4 bytes remaining in this buffer
128+
* @throws java.nio.ReadOnlyBufferException if this buffer is read-only
129+
* @since 5.4
130+
*/
131+
ByteBuf putInt(int index, int b);
132+
133+
/**
134+
* Writes the given double value into this buffer at the current position,
135+
* using the current byte order, and increments the position by 8.
136+
*
137+
* @param b the double value to be written
138+
* @return this buffer
139+
* @throws java.nio.BufferOverflowException if there are fewer than 8 bytes remaining in this buffer
140+
* @throws java.nio.ReadOnlyBufferException if this buffer is read-only
141+
* @since 5.4
142+
*/
143+
ByteBuf putDouble(double b);
144+
145+
/**
146+
* Writes the given long value into this buffer at the current position,
147+
* using the current byte order, and increments the position by 8.
148+
*
149+
* @param b the long value to be written
150+
* @return this buffer
151+
* @throws java.nio.BufferOverflowException if there are fewer than 8 bytes remaining in this buffer
152+
* @throws java.nio.ReadOnlyBufferException if this buffer is read-only
153+
* @since 5.4
154+
*/
155+
ByteBuf putLong(long b);
156+
109157
/**
110158
* <p>Flips this buffer. The limit is set to the current position and then the position is set to zero. If the mark is defined then it
111159
* is discarded.</p>

bson/src/main/org/bson/ByteBufNIO.java

+31-2
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,30 @@ public ByteBuf put(final byte b) {
9797
return this;
9898
}
9999

100+
@Override
101+
public ByteBuf putInt(final int b) {
102+
buf.putInt(b);
103+
return this;
104+
}
105+
106+
@Override
107+
public ByteBuf putInt(final int index, final int b) {
108+
buf.putInt(index, b);
109+
return this;
110+
}
111+
112+
@Override
113+
public ByteBuf putDouble(final double b) {
114+
buf.putDouble(b);
115+
return this;
116+
}
117+
118+
@Override
119+
public ByteBuf putLong(final long b) {
120+
buf.putLong(b);
121+
return this;
122+
}
123+
100124
@Override
101125
public ByteBuf flip() {
102126
((Buffer) buf).flip();
@@ -170,8 +194,13 @@ public ByteBuf get(final byte[] bytes, final int offset, final int length) {
170194

171195
@Override
172196
public ByteBuf get(final int index, final byte[] bytes, final int offset, final int length) {
173-
for (int i = 0; i < length; i++) {
174-
bytes[offset + i] = buf.get(index + i);
197+
if (buf.hasArray()) {
198+
System.arraycopy(buf.array(), index, bytes, offset, length);
199+
} else {
200+
// Fallback to per-byte copying if no backing array is available.
201+
for (int i = 0; i < length; i++) {
202+
bytes[offset + i] = buf.get(index + i);
203+
}
175204
}
176205
return this;
177206
}

bson/src/main/org/bson/io/BasicOutputBuffer.java

+79-29
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818

1919
import org.bson.ByteBuf;
2020
import org.bson.ByteBufNIO;
21+
import org.bson.types.ObjectId;
2122

2223
import java.io.IOException;
2324
import java.io.OutputStream;
25+
import java.nio.Buffer;
2426
import java.nio.ByteBuffer;
2527
import java.util.Arrays;
28+
import java.util.Collections;
2629
import java.util.List;
2730

2831
import static java.lang.String.format;
@@ -32,8 +35,12 @@
3235
* A BSON output stream that stores the output in a single, un-pooled byte array.
3336
*/
3437
public class BasicOutputBuffer extends OutputBuffer {
35-
private byte[] buffer;
36-
private int position;
38+
39+
/**
40+
* This ByteBuffer allows us to write ObjectIDs without allocating a temporary array per object, and enables us
41+
* to leverage JVM intrinsics for writing little-endian numeric values.
42+
*/
43+
private ByteBuffer buffer;
3744

3845
/**
3946
* Construct an instance with a default initial byte array size.
@@ -48,7 +55,8 @@ public BasicOutputBuffer() {
4855
* @param initialSize the initial size of the byte array
4956
*/
5057
public BasicOutputBuffer(final int initialSize) {
51-
buffer = new byte[initialSize];
58+
// Allocate heap buffer to ensure we can access underlying array
59+
buffer = ByteBuffer.allocate(initialSize).order(LITTLE_ENDIAN);
5260
}
5361

5462
/**
@@ -58,50 +66,76 @@ public BasicOutputBuffer(final int initialSize) {
5866
* @since 3.3
5967
*/
6068
public byte[] getInternalBuffer() {
61-
return buffer;
69+
return buffer.array();
6270
}
6371

6472
@Override
6573
public void write(final byte[] b) {
74+
writeBytes(b, 0, b.length);
75+
}
76+
77+
@Override
78+
public byte[] toByteArray() {
79+
ensureOpen();
80+
return Arrays.copyOf(buffer.array(), buffer.position());
81+
}
82+
83+
@Override
84+
public void writeInt32(final int value) {
85+
ensureOpen();
86+
ensure(4);
87+
buffer.putInt(value);
88+
}
89+
90+
@Override
91+
public void writeInt32(final int position, final int value) {
92+
ensureOpen();
93+
checkPosition(position, 4);
94+
buffer.putInt(position, value);
95+
}
96+
97+
@Override
98+
public void writeInt64(final long value) {
99+
ensureOpen();
100+
ensure(8);
101+
buffer.putLong(value);
102+
}
103+
104+
@Override
105+
public void writeObjectId(final ObjectId value) {
66106
ensureOpen();
67-
write(b, 0, b.length);
107+
ensure(12);
108+
value.putToByteBuffer(buffer);
68109
}
69110

70111
@Override
71112
public void writeBytes(final byte[] bytes, final int offset, final int length) {
72113
ensureOpen();
73114

74115
ensure(length);
75-
System.arraycopy(bytes, offset, buffer, position, length);
76-
position += length;
116+
buffer.put(bytes, offset, length);
77117
}
78118

79119
@Override
80120
public void writeByte(final int value) {
81121
ensureOpen();
82122

83123
ensure(1);
84-
buffer[position++] = (byte) (0xFF & value);
124+
buffer.put((byte) (0xFF & value));
85125
}
86126

87127
@Override
88128
protected void write(final int absolutePosition, final int value) {
89129
ensureOpen();
130+
checkPosition(absolutePosition, 1);
90131

91-
if (absolutePosition < 0) {
92-
throw new IllegalArgumentException(format("position must be >= 0 but was %d", absolutePosition));
93-
}
94-
if (absolutePosition > position - 1) {
95-
throw new IllegalArgumentException(format("position must be <= %d but was %d", position - 1, absolutePosition));
96-
}
97-
98-
buffer[absolutePosition] = (byte) (0xFF & value);
132+
buffer.put(absolutePosition, (byte) (0xFF & value));
99133
}
100134

101135
@Override
102136
public int getPosition() {
103137
ensureOpen();
104-
return position;
138+
return buffer.position();
105139
}
106140

107141
/**
@@ -110,29 +144,32 @@ public int getPosition() {
110144
@Override
111145
public int getSize() {
112146
ensureOpen();
113-
return position;
147+
return buffer.position();
114148
}
115149

116150
@Override
117151
public int pipe(final OutputStream out) throws IOException {
118152
ensureOpen();
119-
out.write(buffer, 0, position);
120-
return position;
153+
out.write(buffer.array(), 0, buffer.position());
154+
return buffer.position();
121155
}
122156

123157
@Override
124158
public void truncateToPosition(final int newPosition) {
125159
ensureOpen();
126-
if (newPosition > position || newPosition < 0) {
160+
if (newPosition > buffer.position() || newPosition < 0) {
127161
throw new IllegalArgumentException();
128162
}
129-
position = newPosition;
163+
// The cast is required for compatibility with JDK 9+ where ByteBuffer's position method is inherited from Buffer.
164+
((Buffer) buffer).position(newPosition);
130165
}
131166

132167
@Override
133168
public List<ByteBuf> getByteBuffers() {
134169
ensureOpen();
135-
return Arrays.asList(new ByteBufNIO(ByteBuffer.wrap(buffer, 0, position).duplicate().order(LITTLE_ENDIAN)));
170+
// Create a flipped copy of the buffer for reading. Note that ByteBufNIO overwrites the endian-ness.
171+
ByteBuffer flipped = ByteBuffer.wrap(buffer.array(), 0, buffer.position());
172+
return Collections.singletonList(new ByteBufNIO(flipped));
136173
}
137174

138175
@Override
@@ -147,19 +184,32 @@ private void ensureOpen() {
147184
}
148185

149186
private void ensure(final int more) {
150-
int need = position + more;
151-
if (need <= buffer.length) {
187+
int length = buffer.position();
188+
int need = length + more;
189+
if (need <= buffer.capacity()) {
152190
return;
153191
}
154192

155-
int newSize = buffer.length * 2;
193+
int newSize = length * 2;
156194
if (newSize < need) {
157195
newSize = need + 128;
158196
}
159197

160-
byte[] n = new byte[newSize];
161-
System.arraycopy(buffer, 0, n, 0, position);
162-
buffer = n;
198+
ByteBuffer tmp = ByteBuffer.allocate(newSize).order(LITTLE_ENDIAN);
199+
tmp.put(buffer.array(), 0, length); // Avoids covariant call to flip on jdk8
200+
this.buffer = tmp;
163201
}
164202

203+
/**
204+
* Ensures that `absolutePosition` is a valid index in `this.buffer` and there is room to write at
205+
* least `bytesToWrite` bytes.
206+
*/
207+
private void checkPosition(final int absolutePosition, final int bytesToWrite) {
208+
if (absolutePosition < 0) {
209+
throw new IllegalArgumentException(format("position must be >= 0 but was %d", absolutePosition));
210+
}
211+
if (absolutePosition > buffer.position() - bytesToWrite) {
212+
throw new IllegalArgumentException(format("position must be <= %d but was %d", buffer.position() - bytesToWrite, absolutePosition));
213+
}
214+
}
165215
}

bson/src/main/org/bson/io/OutputBuffer.java

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public void writeInt32(final int value) {
7070
}
7171

7272
@Override
73+
@Deprecated
7374
public void writeInt32(final int position, final int value) {
7475
write(position, value >> 0);
7576
write(position + 1, value >> 8);

0 commit comments

Comments
 (0)