Skip to content

Commit f2a67c8

Browse files
authored
OAK-12109: MongoDocumentStore: improve diagnostics for too large docs in bulk request payloads (#2764)
1 parent a4b6d55 commit f2a67c8

File tree

2 files changed

+89
-3
lines changed

2 files changed

+89
-3
lines changed

oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,7 +1651,33 @@ private <T extends Document> BulkRequestResult sendBulkRequest(final Collection<
16511651
for (BulkWriteError err : e.getWriteErrors()) {
16521652
failedUpdates.add(bulkIds[err.getIndex()]);
16531653
}
1654+
} catch (BSONException bsonException) {
1655+
LOG.error("bulkUpdate of size {} failed with: {}", updateOps.size(),
1656+
bsonException.getMessage(), bsonException);
1657+
1658+
// add diagnostics
1659+
String idOfbiggestUpdate = "";
1660+
int estimatedSizeOfBiggestUpdate = 0;
1661+
1662+
for (UpdateOp updateOp : updateOps) {
1663+
String id = updateOp.getId();
1664+
// this could be made more precise my measuring the BSON serialization of
1665+
// conditions and updates
1666+
int estimatedSize = updateOp.toString().length();
1667+
LOG.debug("after bulk write: string serialization of changes for id={} had an approximate size of {}",
1668+
id, estimatedSize);
1669+
if (estimatedSize > estimatedSizeOfBiggestUpdate) {
1670+
idOfbiggestUpdate = id;
1671+
estimatedSizeOfBiggestUpdate = estimatedSize;
1672+
}
1673+
}
1674+
LOG.error("bulkUpdate of size {} failed with: {}; biggest update was for i={} with approximate size of {}",
1675+
updateOps.size(), bsonException.getMessage(), idOfbiggestUpdate, estimatedSizeOfBiggestUpdate,
1676+
bsonException);
1677+
// rethrow
1678+
throw bsonException;
16541679
}
1680+
16551681
for (BulkWriteUpsert upsert : bulkResult.getUpserts()) {
16561682
upserts.add(bulkIds[upsert.getIndex()]);
16571683
}

oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDBExceptionTest.java

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
package org.apache.jackrabbit.oak.plugins.document.mongo;
1818

19+
import org.apache.commons.lang3.RandomStringUtils;
1920
import org.apache.jackrabbit.oak.plugins.document.Collection;
2021
import org.apache.jackrabbit.oak.plugins.document.DocumentMK;
2122
import org.apache.jackrabbit.oak.plugins.document.DocumentStoreException;
@@ -26,22 +27,25 @@
2627
import org.apache.jackrabbit.oak.plugins.document.UpdateOp;
2728
import org.apache.jackrabbit.oak.plugins.document.util.Utils;
2829
import org.apache.jackrabbit.oak.commons.junit.LogCustomizer;
30+
import org.bson.BSONException;
2931
import org.junit.After;
3032
import org.junit.Assume;
3133
import org.junit.Before;
3234
import org.junit.BeforeClass;
3335
import org.junit.Test;
36+
import org.slf4j.event.Level;
3437

3538
import java.util.ArrayList;
3639
import java.util.Arrays;
3740
import java.util.List;
3841

3942
import static java.util.Collections.singletonList;
43+
import static org.hamcrest.MatcherAssert.assertThat;
4044
import static org.hamcrest.Matchers.containsString;
41-
import static org.junit.Assert.assertThat;
45+
import static org.junit.Assert.assertEquals;
46+
import static org.junit.Assert.assertFalse;
4247
import static org.junit.Assert.assertTrue;
4348
import static org.junit.Assert.fail;
44-
import static org.junit.Assert.assertFalse;
4549

4650
public class MongoDBExceptionTest {
4751

@@ -157,6 +161,61 @@ public void createOrUpdate16MBDoc() {
157161
customizer.finished();
158162
}
159163

164+
@Test
165+
public void createOrUpdate16MBBatchWithMultiDocs() {
166+
LogCustomizer log = LogCustomizer.forLogger(MongoDocumentStore.class.getName()).
167+
enable(Level.ERROR).
168+
matchesRegex("bulkUpdate.*biggest update.*approximate.*").
169+
create();
170+
171+
try {
172+
log.starting();
173+
List<String> ids = new ArrayList<>();
174+
List<UpdateOp> updateOps = new ArrayList<>();
175+
176+
String idOfReallyBig = "foo-really-big";
177+
178+
{
179+
String id = "/foo-1MB";
180+
ids.add(id);
181+
UpdateOp updateOp = new UpdateOp(id, true);
182+
updateOp = create1MBProp(updateOp);
183+
updateOps.add(updateOp);
184+
}
185+
{
186+
String id = idOfReallyBig;
187+
ids.add(id);
188+
UpdateOp updateOp = new UpdateOp(id, true);
189+
updateOp.set("big", RandomStringUtils.secure().next(20 * 1024 * 1024));
190+
updateOps.add(updateOp);
191+
}
192+
{
193+
String id = "/foo-small";
194+
ids.add(id);
195+
UpdateOp updateOp = new UpdateOp(id, true);
196+
updateOps.add(updateOp);
197+
}
198+
199+
store.remove(Collection.NODES, ids);
200+
201+
try {
202+
store.createOrUpdate(Collection.NODES, updateOps);
203+
fail("createOrUpdate(many with one >16MB) should have failed");
204+
} catch (BSONException expected) {
205+
// currently expected but incorrect -> OAK-12113
206+
List<String> messages = log.getLogs();
207+
assertEquals("only 1 message expected, but got: " + messages.size(),
208+
1, messages.size());
209+
String message = messages.get(0);
210+
assertTrue("log message should contain id " + idOfReallyBig + "/foo-really.big, got: " + message,
211+
message.contains(idOfReallyBig));
212+
}
213+
214+
} finally {
215+
log.finished();
216+
}
217+
}
218+
160219
@Test
161220
public void update16MBDoc() {
162221

@@ -263,7 +322,7 @@ private UpdateOp create1MBProp(UpdateOp op) {
263322
private UpdateOp create16MBProp(UpdateOp op) {
264323
// create a 1 MB property
265324
String content = create1MBContent();
266-
325+
267326

268327
//create 16MB property
269328
for (int i = 0; i < 16; i++) {
@@ -272,6 +331,7 @@ private UpdateOp create16MBProp(UpdateOp op) {
272331
return op;
273332
}
274333

334+
// RED ALERT: OAK-12114
275335
private String create1MBContent() {
276336
char[] chars = new char[1024 * 1024];
277337
Arrays.fill(chars, '0');

0 commit comments

Comments
 (0)