Skip to content

Commit ef7edbc

Browse files
committed
JAVA-981, JAVA 1040: Implemented bulk write API using the new write commands from MongoDB 2.6. Also supports emulation of those commands on pre-2.6 servers using the existing opcode-based writes. Also fixed the existing support for JAVA-981 in response to changes in the write commands coming in 2.5.5.
1 parent 22df8bc commit ef7edbc

41 files changed

Lines changed: 3373 additions & 451 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

config/clirr-exclude.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ members:
1010
com.mongodb.DBPortPool:
1111
- getStatistics()
1212
- memSize(com.mongodb.DBPort)
13+
com.mongodb.DBApiLayer:
14+
- doGetCollection(java.lang.String)
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright (c) 2008 - 2013 MongoDB Inc. <http://10gen.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb;
18+
19+
import java.util.Collections;
20+
import java.util.List;
21+
22+
import static org.bson.util.Assertions.notNull;
23+
24+
class AcknowledgedBulkWriteResult extends BulkWriteResult {
25+
private int insertedCount;
26+
private int updatedCount;
27+
private int removedCount;
28+
private int modifiedCount;
29+
private final List<BulkWriteUpsert> upserts;
30+
31+
AcknowledgedBulkWriteResult(final int insertedCount, final int updatedCount, final int removedCount,
32+
final int modifiedCount, final List<BulkWriteUpsert> upserts) {
33+
this.insertedCount = insertedCount;
34+
this.updatedCount = updatedCount;
35+
this.removedCount = removedCount;
36+
this.modifiedCount = modifiedCount;
37+
this.upserts = Collections.unmodifiableList(notNull("upserts", upserts));
38+
}
39+
40+
AcknowledgedBulkWriteResult(final WriteRequest.Type type, final int count, final List<BulkWriteUpsert> upserts) {
41+
this(type, count, 0, upserts);
42+
}
43+
44+
AcknowledgedBulkWriteResult(final WriteRequest.Type type, final int count, final int modifiedCount,
45+
final List<BulkWriteUpsert> upserts) {
46+
this(type == WriteRequest.Type.INSERT ? count : 0,
47+
(type == WriteRequest.Type.UPDATE || type == WriteRequest.Type.REPLACE) ? count : 0,
48+
type == WriteRequest.Type.REMOVE ? count : 0,
49+
modifiedCount, upserts);
50+
}
51+
52+
@Override
53+
public boolean isAcknowledged() {
54+
return true;
55+
}
56+
57+
@Override
58+
public int getInsertedCount() {
59+
return insertedCount;
60+
}
61+
62+
@Override
63+
public int getUpdatedCount() {
64+
return updatedCount;
65+
}
66+
67+
@Override
68+
public int getRemovedCount() {
69+
return removedCount;
70+
}
71+
72+
@Override
73+
public int getModifiedCount() {
74+
return modifiedCount;
75+
}
76+
77+
@Override
78+
public List<BulkWriteUpsert> getUpserts() {
79+
return upserts;
80+
}
81+
82+
@Override
83+
public boolean equals(final Object o) {
84+
if (this == o) {
85+
return true;
86+
}
87+
if (o == null || getClass() != o.getClass()) {
88+
return false;
89+
}
90+
91+
AcknowledgedBulkWriteResult that = (AcknowledgedBulkWriteResult) o;
92+
93+
if (insertedCount != that.insertedCount) {
94+
return false;
95+
}
96+
if (modifiedCount != that.modifiedCount) {
97+
return false;
98+
}
99+
if (removedCount != that.removedCount) {
100+
return false;
101+
}
102+
if (updatedCount != that.updatedCount) {
103+
return false;
104+
}
105+
if (!upserts.equals(that.upserts)) {
106+
return false;
107+
}
108+
109+
return true;
110+
}
111+
112+
@Override
113+
public int hashCode() {
114+
int result = upserts.hashCode();
115+
result = 31 * result + insertedCount;
116+
result = 31 * result + updatedCount;
117+
result = 31 * result + removedCount;
118+
result = 31 * result + modifiedCount;
119+
return result;
120+
}
121+
122+
@Override
123+
public String toString() {
124+
return "AcknowledgedBulkWriteResult{"
125+
+ "insertedCount=" + insertedCount
126+
+ ", updatedCount=" + updatedCount
127+
+ ", removedCount=" + removedCount
128+
+ ", modifiedCount=" + modifiedCount
129+
+ ", upserts=" + upserts
130+
+ '}';
131+
}
132+
}

src/main/com/mongodb/BaseWriteCommandMessage.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,14 @@ protected boolean maximumCommandDocumentSizeExceeded(final OutputBuffer buffer,
9292
return buffer.getPosition() - commandStartPosition > getSettings().getMaxDocumentSize() + HEADROOM - 2;
9393
}
9494

95+
public abstract int getItemCount();
96+
9597
private void writeCommandPrologue(final BSONBinaryWriter writer) {
9698
writer.writeString(getCommandName(), getWriteNamespace().getCollectionName());
9799
writer.writeBoolean("ordered", !getWriteConcern().getContinueOnError());
98-
if (getWriteConcern().callGetLastError()) {
99-
DBObject writeConcernDocument = getWriteConcern().getCommand();
100-
writeConcernDocument.removeField("getlasterror");
100+
if (!getWriteConcern().useServerDefault()) {
101101
writer.writeName("writeConcern");
102-
writer.encodeDocument(getCommandEncoder(), writeConcernDocument);
102+
writer.encodeDocument(getCommandEncoder(), getWriteConcern().asDBObject());
103103
}
104104
}
105-
106105
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (c) 2008 - 2013 MongoDB Inc. <http://10gen.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb;
18+
19+
/**
20+
* A builder for a single update request.
21+
*
22+
* @since 2.12
23+
*/
24+
public class BulkUpdateRequestBuilder {
25+
private final BulkWriteOperation operationBuilder;
26+
private final DBObject query;
27+
private final boolean upsert;
28+
29+
BulkUpdateRequestBuilder(final BulkWriteOperation operationBuilder, final DBObject query, final boolean upsert) {
30+
this.operationBuilder = operationBuilder;
31+
this.query = query;
32+
this.upsert = upsert;
33+
}
34+
35+
/**
36+
* Adds an update request to replace one matching document to the bulk operation.
37+
*
38+
* @param document the replacement document
39+
*/
40+
public void replaceOne(final DBObject document) {
41+
operationBuilder.addRequest(new ReplaceRequest(query, upsert, document));
42+
}
43+
44+
/**
45+
* Adds an update request to update all matching documents to the bulk operation.
46+
*
47+
* @param update the update criteria
48+
*/
49+
public void update(final DBObject update) {
50+
operationBuilder.addRequest(new UpdateRequest(query, upsert, update, true));
51+
}
52+
53+
/**
54+
* Adds an update request to update one matching document to the bulk operation.
55+
*
56+
* @param update the update criteria
57+
*/
58+
public void updateOne(final DBObject update) {
59+
operationBuilder.addRequest(new UpdateRequest(query, upsert, update, false));
60+
}
61+
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Copyright (c) 2008 - 2013 MongoDB Inc. <http://10gen.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb;
18+
19+
import java.util.ArrayList;
20+
import java.util.Comparator;
21+
import java.util.List;
22+
import java.util.Set;
23+
import java.util.TreeSet;
24+
25+
import static java.util.Arrays.asList;
26+
import static org.bson.util.Assertions.notNull;
27+
28+
class BulkWriteBatchCombiner {
29+
private final ServerAddress serverAddress;
30+
private final boolean ordered;
31+
private final WriteConcern writeConcern;
32+
33+
private int insertedCount;
34+
private int updatedCount;
35+
private int removedCount;
36+
private int modifiedCount;
37+
private final Set<BulkWriteUpsert> writeUpserts = new TreeSet<BulkWriteUpsert>(new Comparator<BulkWriteUpsert>() {
38+
@Override
39+
public int compare(final BulkWriteUpsert o1, final BulkWriteUpsert o2) {
40+
return (o1.getIndex() < o2.getIndex()) ? -1 : ((o1.getIndex() == o2.getIndex()) ? 0 : 1);
41+
}
42+
});
43+
private final Set<BulkWriteError> writeErrors = new TreeSet<BulkWriteError>(new Comparator<BulkWriteError>() {
44+
@Override
45+
public int compare(final BulkWriteError o1, final BulkWriteError o2) {
46+
return (o1.getIndex() < o2.getIndex()) ? -1 : ((o1.getIndex() == o2.getIndex()) ? 0 : 1);
47+
}
48+
});
49+
private final List<WriteConcernError> writeConcernErrors = new ArrayList<WriteConcernError>();
50+
51+
public BulkWriteBatchCombiner(final ServerAddress serverAddress, final WriteConcern writeConcern) {
52+
this.writeConcern = notNull("writeConcern", writeConcern);
53+
this.ordered = !writeConcern.getContinueOnError();
54+
this.serverAddress = notNull("serverAddress", serverAddress);
55+
}
56+
57+
public void addResult(final BulkWriteResult result, final IndexMap indexMap) {
58+
insertedCount += result.getInsertedCount();
59+
updatedCount += result.getUpdatedCount();
60+
removedCount += result.getRemovedCount();
61+
modifiedCount += result.getModifiedCount();
62+
mergeUpserts(result.getUpserts(), indexMap);
63+
}
64+
65+
public void addErrorResult(final BulkWriteException exception, final IndexMap indexMap) {
66+
addResult(exception.getWriteResult(), indexMap);
67+
mergeWriteErrors(exception.getWriteErrors(), indexMap);
68+
mergeWriteConcernError(exception.getWriteConcernError());
69+
}
70+
71+
public void addWriteErrorResult(final BulkWriteError writeError, final IndexMap indexMap) {
72+
notNull("writeError", writeError);
73+
mergeWriteErrors(asList(writeError), indexMap);
74+
}
75+
76+
public void addWriteConcernErrorResult(final WriteConcernError writeConcernError) {
77+
notNull("writeConcernError", writeConcernError);
78+
mergeWriteConcernError(writeConcernError);
79+
}
80+
81+
public void addErrorResult(final List<BulkWriteError> writeErrors,
82+
final WriteConcernError writeConcernError, final IndexMap indexMap) {
83+
mergeWriteErrors(writeErrors, indexMap);
84+
mergeWriteConcernError(writeConcernError);
85+
}
86+
87+
private void mergeWriteConcernError(final WriteConcernError writeConcernError) {
88+
if (writeConcernError != null) {
89+
if (writeConcernErrors.isEmpty()) {
90+
writeConcernErrors.add(writeConcernError);
91+
} else if (!writeConcernError.equals(writeConcernErrors.get(writeConcernErrors.size() - 1))) {
92+
writeConcernErrors.add(writeConcernError);
93+
}
94+
}
95+
}
96+
97+
private void mergeWriteErrors(final List<BulkWriteError> newWriteErrors, final IndexMap indexMap) {
98+
for (BulkWriteError cur : newWriteErrors) {
99+
this.writeErrors.add(new BulkWriteError(cur.getCode(), cur.getMessage(), cur.getDetails(), indexMap.map(cur.getIndex())
100+
));
101+
}
102+
}
103+
104+
private void mergeUpserts(final List<BulkWriteUpsert> upserts, final IndexMap indexMap) {
105+
for (BulkWriteUpsert bulkWriteUpsert : upserts) {
106+
writeUpserts.add(new BulkWriteUpsert(indexMap.map(bulkWriteUpsert.getIndex()), bulkWriteUpsert.getId()));
107+
}
108+
}
109+
110+
public BulkWriteResult getResult() {
111+
throwOnError();
112+
return createResult();
113+
}
114+
115+
public boolean shouldStopSendingMoreBatches() {
116+
return ordered && hasWriteErrors();
117+
}
118+
119+
private void throwOnError() {
120+
if (!writeErrors.isEmpty() || !writeConcernErrors.isEmpty()) {
121+
throw new BulkWriteException(createResult(),
122+
new ArrayList<BulkWriteError>(writeErrors),
123+
writeConcernErrors.isEmpty() ? null : writeConcernErrors.get(writeConcernErrors.size() - 1),
124+
serverAddress);
125+
}
126+
}
127+
128+
private BulkWriteResult createResult() {
129+
return writeConcern.callGetLastError()
130+
? new AcknowledgedBulkWriteResult(insertedCount, updatedCount, removedCount, modifiedCount,
131+
new ArrayList<BulkWriteUpsert>(writeUpserts))
132+
: new UnacknowledgedBulkWriteResult();
133+
}
134+
135+
private boolean hasWriteErrors() {
136+
return !writeErrors.isEmpty();
137+
}
138+
}

0 commit comments

Comments
 (0)