From 4110a0e843120e480f7682036bdca2964ed7cab1 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Fri, 18 Sep 2026 11:35:19 +0300 Subject: [PATCH] [#1071] Wrap the sources of the large values PDBStorageTest writes, so that four copies of a 63 MB value are not live at once testCanAddLargeValues built each source with ByteString.valueOfBytes(), which copies, and a value on its way into Persistit is copied twice more - toByteArray() in bytesToValue() and the value buffer of the exchange, which doubles up to 64 MB. With the 63 MB value that is four copies live at once on top of the buffer pool and the server: about 310 MB after a collection in the 512 MB of the test JVM, and build-maven (ubuntu-latest, 17) of #1069 ran out of heap on the 32 MB put. Wrapping the sources leaves about 165 MB. Measured under JDK 17 with -Xlog:gc*: the worst pause goes from 436M->311M with 300->177 humongous regions to 471M->165M with 328->31. Splitting the three puts over three writes does not help - the value buffer grows again for each - so they stay in one transaction. --- .../opends/server/backends/pdb/PDBStorageTest.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/pdb/PDBStorageTest.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/pdb/PDBStorageTest.java index f633849bb5..91c30fb063 100644 --- a/opendj-server-legacy/src/test/java/org/opends/server/backends/pdb/PDBStorageTest.java +++ b/opendj-server-legacy/src/test/java/org/opends/server/backends/pdb/PDBStorageTest.java @@ -137,6 +137,14 @@ private void reopenWithReplayBounds(int maxRetries, long retryWindowNanos) throw storage.open(AccessMode.READ_WRITE); } + /** + * The sources are wrapped rather than copied: a value on its way into Persistit is copied twice more - + * {@code toByteArray()} and the value buffer of the exchange, which doubles up to 64 MB - so with a copy + * here as well the 63 MB value had four copies of itself live at once, on top of the buffer pool and the + * server: about 310 MB left after a collection, in a JVM of 512 MB, which one CI leg ran out of. Wrapped, + * about 165 MB. The three values stay in one transaction on purpose: the value buffer the 32 MB one + * grew fits the 63 MB one without growing again. + */ @Test public void testCanAddLargeValues() throws Exception { @@ -148,10 +156,10 @@ public void testCanAddLargeValues() throws Exception public void run(WriteableTransaction txn) throws Exception { txn.openTree(treeName, true); - txn.put(treeName, valueOfUtf8("4mb"), valueOfBytes(new byte[4 * MB])); - txn.put(treeName, valueOfUtf8("32mb"), valueOfBytes(new byte[32 * MB])); + txn.put(treeName, valueOfUtf8("4mb"), wrap(new byte[4 * MB])); + txn.put(treeName, valueOfUtf8("32mb"), wrap(new byte[32 * MB])); // 64Mb is the maximum allowed for value size. But Persistit has header reducing the payload. - txn.put(treeName, valueOfUtf8("64mb"), valueOfBytes(new byte[63 * MB])); + txn.put(treeName, valueOfUtf8("64mb"), wrap(new byte[63 * MB])); } }); }