This is an automated email from the ASF dual-hosted git repository.

eolivelli pushed a commit to branch branch-4.14
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git


The following commit(s) were added to refs/heads/branch-4.14 by this push:
     new c4b944218a [branch-4.14] Fix ByteBuf memory leak problem when 
setExplicitLac (#3617)
c4b944218a is described below

commit c4b944218a46505e1fac1416a162b812e3d72e9a
Author: wenbingshen <[email protected]>
AuthorDate: Mon Nov 7 15:51:02 2022 +0800

    [branch-4.14] Fix ByteBuf memory leak problem when setExplicitLac (#3617)
---
 .../java/org/apache/bookkeeper/bookie/Bookie.java  |  12 ++-
 .../org/apache/bookkeeper/bookie/BookieTest.java   | 102 +++++++++++++++++++++
 2 files changed, 112 insertions(+), 2 deletions(-)

diff --git 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
index 28c76f6329..0c5af7f6f0 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
@@ -37,6 +37,7 @@ import io.netty.buffer.PooledByteBufAllocator;
 import io.netty.buffer.Unpooled;
 import io.netty.buffer.UnpooledByteBufAllocator;
 
+import io.netty.util.ReferenceCountUtil;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FilenameFilter;
@@ -1387,7 +1388,8 @@ public class Bookie extends BookieCriticalThread {
         }
     }
 
-    private ByteBuf createExplicitLACEntry(long ledgerId, ByteBuf explicitLac) 
{
+    @VisibleForTesting
+    public ByteBuf createExplicitLACEntry(long ledgerId, ByteBuf explicitLac) {
         ByteBuf bb = allocator.directBuffer(8 + 8 + 4 + 
explicitLac.capacity());
         bb.writeLong(ledgerId);
         bb.writeLong(METAENTRY_ID_LEDGER_EXPLICITLAC);
@@ -1398,6 +1400,7 @@ public class Bookie extends BookieCriticalThread {
 
     public void setExplicitLac(ByteBuf entry, WriteCallback writeCallback, 
Object ctx, byte[] masterKey)
             throws IOException, InterruptedException, BookieException {
+        ByteBuf explicitLACEntry = null;
         try {
             long ledgerId = entry.getLong(entry.readerIndex());
             LedgerDescriptor handle = handles.getHandle(ledgerId, masterKey);
@@ -1405,12 +1408,17 @@ public class Bookie extends BookieCriticalThread {
                 entry.markReaderIndex();
                 handle.setExplicitLac(entry);
                 entry.resetReaderIndex();
-                ByteBuf explicitLACEntry = createExplicitLACEntry(ledgerId, 
entry);
+                explicitLACEntry = createExplicitLACEntry(ledgerId, entry);
                 getJournal(ledgerId).logAddEntry(explicitLACEntry, false /* 
ackBeforeSync */, writeCallback, ctx);
             }
         } catch (NoWritableLedgerDirException e) {
             stateManager.transitionToReadOnlyMode();
             throw new IOException(e);
+        }  finally {
+            ReferenceCountUtil.safeRelease(entry);
+            if (explicitLACEntry != null) {
+                ReferenceCountUtil.safeRelease(explicitLACEntry);
+            }
         }
     }
 
diff --git 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieTest.java 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieTest.java
new file mode 100644
index 0000000000..d4663b4870
--- /dev/null
+++ 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieTest.java
@@ -0,0 +1,102 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.bookkeeper.bookie;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.UnsafeByteOperations;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.buffer.UnpooledByteBufAllocator;
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import org.apache.bookkeeper.client.BookKeeper;
+import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.conf.TestBKConfiguration;
+import org.apache.bookkeeper.proto.checksum.DigestManager;
+import org.apache.bookkeeper.test.BookKeeperClusterTestCase;
+import org.apache.bookkeeper.util.ByteBufList;
+import org.apache.bookkeeper.util.PortManager;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The tests for {@link Bookie}.
+ */
+public class BookieTest extends BookKeeperClusterTestCase {
+    private static final Logger log = 
LoggerFactory.getLogger(BookieTest.class);
+
+    private static final int bookiePort = PortManager.nextFreePort();
+
+    public BookieTest() {
+        super(0);
+    }
+
+    @Test
+    public void testWriteLac() throws Exception {
+        final String metadataServiceUri = zkUtil.getMetadataServiceUri();
+        File ledgerDir = createTempDir("bkLacTest", ".dir");
+
+        ServerConfiguration conf = 
TestBKConfiguration.newServerConfiguration();
+        conf.setMetadataServiceUri(metadataServiceUri)
+                .setBookiePort(bookiePort)
+                .setJournalDirName(ledgerDir.toString())
+                .setLedgerDirNames(new String[]{ledgerDir.getAbsolutePath()});
+
+        Bookie b = new Bookie(conf);
+        b.start();
+
+        final Bookie spyBookie = spy(b);
+
+        final long ledgerId = 10;
+        final long lac = 23;
+
+        DigestManager digestManager = DigestManager.instantiate(ledgerId, 
"".getBytes(StandardCharsets.UTF_8),
+                
BookKeeper.DigestType.toProtoDigestType(BookKeeper.DigestType.CRC32), 
UnpooledByteBufAllocator.DEFAULT,
+                baseClientConf.getUseV2WireProtocol());
+
+        final ByteBufList toSend = 
digestManager.computeDigestAndPackageForSendingLac(lac);
+        ByteString body = UnsafeByteOperations.unsafeWrap(toSend.array(), 
toSend.arrayOffset(), toSend.readableBytes());
+
+        final ByteBuf lacToAdd = 
Unpooled.wrappedBuffer(body.asReadOnlyByteBuffer());
+        final byte[] masterKey = 
ByteString.copyFrom("masterKey".getBytes()).toByteArray();
+
+        final ByteBuf explicitLACEntry = b.createExplicitLACEntry(ledgerId, 
lacToAdd);
+        lacToAdd.resetReaderIndex();
+
+        doReturn(explicitLACEntry)
+                .when(spyBookie)
+                .createExplicitLACEntry(eq(ledgerId), eq(lacToAdd));
+
+        spyBookie.setExplicitLac(lacToAdd, null, null, masterKey);
+
+        assertEquals(0, lacToAdd.refCnt());
+        assertEquals(0, explicitLACEntry.refCnt());
+
+        b.shutdown();
+
+    }
+}
\ No newline at end of file

Reply via email to