This is an automated email from the ASF dual-hosted git repository.
reschke pushed a commit to branch 1.22
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/1.22 by this push:
new 503569c43a OAK-10127: Log warn message when MongoDB document is big
(backport to 1.22) (#2748)
503569c43a is described below
commit 503569c43a4eb352d17908b8f7f62202cc6f890c
Author: Julian Reschke <[email protected]>
AuthorDate: Fri Feb 20 10:11:09 2026 +0100
OAK-10127: Log warn message when MongoDB document is big (backport to 1.22)
(#2748)
---
.../plugins/document/mongo/MongoDocumentStore.java | 21 +++
.../document/mongo/MongoDBExceptionTest.java | 142 +++++++++++++++++++++
2 files changed, 163 insertions(+)
diff --git
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
index 2ea202891d..4b42d3f53b 100644
---
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
+++
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
@@ -45,6 +45,9 @@ import
com.google.common.util.concurrent.UncheckedExecutionException;
import com.mongodb.Block;
import com.mongodb.DBObject;
import com.mongodb.MongoBulkWriteException;
+import com.mongodb.MongoWriteException;
+import com.mongodb.MongoCommandException;
+import com.mongodb.WriteError;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.ReadPreference;
@@ -74,6 +77,7 @@ import
org.apache.jackrabbit.oak.plugins.document.locks.StripedNodeDocumentLocks
import org.apache.jackrabbit.oak.plugins.document.util.Utils;
import org.apache.jackrabbit.oak.stats.Clock;
import org.apache.jackrabbit.oak.commons.PerfLogger;
+import org.bson.BsonMaximumSizeExceededException;
import org.bson.conversions.Bson;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -1009,6 +1013,15 @@ public class MongoDocumentStore implements DocumentStore
{
}
}
return oldDoc;
+ } catch (MongoWriteException e) {
+ WriteError werr = e.getError();
+ LOG.error("Failed to update the document with Id={} with
MongoWriteException message = '{}'.",
+ updateOp.getId(), werr.getMessage());
+ throw handleException(e, collection, updateOp.getId());
+ } catch (MongoCommandException e) {
+ LOG.error("Failed to update the document with Id={} with
MongoCommandException message ='{}'. ",
+ updateOp.getId(), e.getMessage());
+ throw handleException(e, collection, updateOp.getId());
} catch (Exception e) {
throw handleException(e, collection, updateOp.getId());
} finally {
@@ -1364,6 +1377,14 @@ public class MongoDocumentStore implements DocumentStore
{
}
insertSuccess = true;
return true;
+ } catch (BsonMaximumSizeExceededException e) {
+ for (T doc : docs) {
+ LOG.error("Failed to create one of the documents " +
+ "with BsonMaximumSizeExceededException
message = '{}'. " +
+ "The document id={} has estimated size={}
in VM.",
+ e.getMessage(), doc.getId(),
doc.getMemory());
+ }
+ return false;
} catch (MongoException e) {
LOG.warn("Encountered MongoException while inserting
documents: {} - exception: {}",
ids, e.getMessage());
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDBExceptionTest.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDBExceptionTest.java
index 73a1d9d49d..7fa9766c35 100644
---
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDBExceptionTest.java
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDBExceptionTest.java
@@ -25,17 +25,23 @@ import org.apache.jackrabbit.oak.plugins.document.Path;
import org.apache.jackrabbit.oak.plugins.document.Revision;
import org.apache.jackrabbit.oak.plugins.document.UpdateOp;
import org.apache.jackrabbit.oak.plugins.document.util.Utils;
+import org.apache.jackrabbit.oak.commons.junit.LogCustomizer;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
import static java.util.Collections.singletonList;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assert.assertFalse;
public class MongoDBExceptionTest {
@@ -132,8 +138,144 @@ public class MongoDBExceptionTest {
}
}
+ @Test
+ public void createOrUpdate16MBDoc() {
+ LogCustomizer customizer =
LogCustomizer.forLogger(MongoDocumentStore.class.getName()).create();
+ customizer.starting();
+ String id = "/foo";
+ UpdateOp updateOp = new UpdateOp(id, true);
+ updateOp = create16MBProp(updateOp);
+ exceptionMsg = "Document to upsert is larger than 16777216";
+ try {
+ store.createOrUpdate(Collection.NODES, updateOp);
+ fail("DocumentStoreException expected");
+ } catch (DocumentStoreException e) {
+ assertThat(e.getMessage(), containsString(exceptionMsg));
+ String log = customizer.getLogs().toString();
+ assertTrue("Message doesn't contain the id", log.contains(id));
+ }
+ customizer.finished();
+ }
+
+ @Test
+ public void update16MBDoc() {
+
+ String docName = "/foo";
+ UpdateOp updateOp = new UpdateOp(docName, true);
+ updateOp = create1MBProp(updateOp);
+ store.createOrUpdate(Collection.NODES, updateOp);
+ updateOp = create16MBProp(updateOp);
+ exceptionMsg = "Resulting document after update is larger than
16777216";
+ try {
+ store.createOrUpdate(Collection.NODES, updateOp);
+ fail("DocumentStoreException expected");
+ } catch (DocumentStoreException e) {
+ assertThat(e.getMessage(), containsString(exceptionMsg));
+ assertThat(e.getMessage(), containsString(docName));
+ }
+ }
+
+ @Test
+ public void multiCreateOrUpdate16MBDoc() {
+
+ List<UpdateOp> updateOps = new ArrayList<>();
+ LogCustomizer customizer =
LogCustomizer.forLogger(MongoDocumentStore.class.getName()).create();
+ customizer.starting();
+ String id1 = "/test";
+ String id2 = "/foo";
+
+ UpdateOp op = new UpdateOp(id1, true);
+ op = create1MBProp(op);
+
+ store.createOrUpdate(Collection.NODES, op);
+
+ UpdateOp op1 = new UpdateOp(id2, true);
+ op1 = create16MBProp(op1);
+
+ // Updating both doc with 16MB
+ op = create16MBProp(op);
+ updateOps.add(op);
+ updateOps.add(op1);
+ exceptionMsg = "Resulting document after update is larger than
16777216";
+
+ try {
+ store.createOrUpdate(Collection.NODES, updateOps);
+ fail("DocumentStoreException expected");
+ } catch (DocumentStoreException e) {
+ assertThat(e.getMessage(), containsString(exceptionMsg));
+ String log = customizer.getLogs().toString();
+ assertTrue("Message doesn't contain the id", log.contains(id1));
+ }
+ customizer.finished();
+ }
+
+ @Test
+ public void create16MBDoc() {
+
+ List<UpdateOp> updateOps = new ArrayList<>();
+ LogCustomizer customizer =
LogCustomizer.forLogger(MongoDocumentStore.class.getName()).create();
+ customizer.starting();
+ String id1 = "/test";
+ String id2 = "/foo";
+ UpdateOp op1 = new UpdateOp(id1, true);
+ op1 = create1MBProp(op1);
+
+ UpdateOp op2 = new UpdateOp(id2, false);
+ op2 = create1MBProp(op2);
+ op2 = create16MBProp(op2);
+
+ updateOps.add(op1);
+ updateOps.add(op2);
+ assertFalse(store.create(Collection.NODES, updateOps));
+ String log = customizer.getLogs().toString();
+ assertTrue("Message doesn't contain the id", log.contains(id2));
+ }
+
+ @Test
+ public void findAndUpdate16MBDoc() throws Exception {
+ String id = "/foo";
+ UpdateOp op = new UpdateOp(id, true);
+ op = create1MBProp(op);
+ store.createOrUpdate(Collection.NODES, op);
+ op = create16MBProp(op);
+ exceptionMsg = "Resulting document after update is larger than
16777216";
+ try {
+ store.findAndUpdate(Collection.NODES, op);
+ fail("DocumentStoreException expected");
+ } catch (DocumentStoreException e) {
+ assertThat(e.getMessage(), containsString(exceptionMsg));
+ assertThat(e.getMessage(), containsString(id));
+ }
+ }
+
private void setExceptionMsg() {
client.setExceptionBeforeUpdate(exceptionMsg);
client.setExceptionBeforeQuery(exceptionMsg);
}
+
+ private UpdateOp create1MBProp(UpdateOp op) {
+ // create a 1 MB property
+ String content = create1MBContent();
+ op.set("property0", content);
+ return op;
+ }
+
+ private UpdateOp create16MBProp(UpdateOp op) {
+ // create a 1 MB property
+ String content = create1MBContent();
+
+ //create 16MB property
+ for (int i = 0; i < 16; i++) {
+ op.set("property"+ i, content);
+ }
+ return op;
+ }
+
+ private String create1MBContent() {
+ char[] chars = new char[1024 * 1024];
+ Arrays.fill(chars, '0');
+ String content = new String(chars);
+ return content;
+ }
}
+