You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by lh...@apache.org on 2026/09/09 15:15:00 UTC
(pulsar) 06/14: [improve][ml] Parse message metadata at entry cache insert time instead of under the wrapper write lock (#26463)
This is an automated email from the ASF dual-hosted git repository.
lhotari pushed a commit to branch branch-4.2
in repository https://gitbox.apache.org/repos/asf/pulsar.git
commit 2d600cfc2c154f2960b2ac7693cc79b9cd285e8b
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Tue Sep 8 04:10:18 2026 -0700
[improve][ml] Parse message metadata at entry cache insert time instead of under the wrapper write lock (#26463)
(cherry picked from commit ce6079887474043f4055ee6c22d2c72e456ac40f)
---
.../mledger/impl/cache/RangeCacheEntryWrapper.java | 3 +++
.../mledger/impl/cache/RangeEntryCacheImpl.java | 6 ++++++
.../impl/cache/RangeEntryCacheImplTest.java | 25 ++++++++++++++++++++++
3 files changed, 34 insertions(+)
diff --git a/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/cache/RangeCacheEntryWrapper.java b/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/cache/RangeCacheEntryWrapper.java
index 02d148504baa..569a5135c344 100644
--- a/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/cache/RangeCacheEntryWrapper.java
+++ b/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/cache/RangeCacheEntryWrapper.java
@@ -65,6 +65,9 @@ class RangeCacheEntryWrapper {
entryWrapper.key = key;
entryWrapper.value = value;
entryWrapper.size = size;
+ // When the value already carries parsed message metadata, there's no need to lazily initialize it
+ // under the write lock on the first read
+ entryWrapper.messageMetadataInitialized = value.getMessageMetadata() != null;
// Set the timestamp to the current time in nanoseconds
// This is used for time-based eviction of entries
entryWrapper.timestampNanos = System.nanoTime();
diff --git a/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/cache/RangeEntryCacheImpl.java b/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/cache/RangeEntryCacheImpl.java
index 352ac341e560..a68ba55eeb25 100644
--- a/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/cache/RangeEntryCacheImpl.java
+++ b/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/cache/RangeEntryCacheImpl.java
@@ -151,6 +151,12 @@ public class RangeEntryCacheImpl implements EntryCache {
cachedData = entry.getDataBuffer().retain();
}
+ // Parse the message metadata once at insert time so that cache reads don't have to do it lazily while
+ // holding the RangeCacheEntryWrapper write lock
+ if (entry instanceof EntryImpl entryImpl) {
+ entryImpl.initializeMessageMetadataIfNeeded(ml.getName());
+ }
+
Position position = entry.getPosition();
ReferenceCountedEntry cacheEntry =
EntryImpl.createWithRetainedDuplicate(position, cachedData, entry.getReadCountHandler(),
diff --git a/managed-ledger/src/test/java/org/apache/bookkeeper/mledger/impl/cache/RangeEntryCacheImplTest.java b/managed-ledger/src/test/java/org/apache/bookkeeper/mledger/impl/cache/RangeEntryCacheImplTest.java
index 42ae262e8ddb..813ecc8b6d46 100644
--- a/managed-ledger/src/test/java/org/apache/bookkeeper/mledger/impl/cache/RangeEntryCacheImplTest.java
+++ b/managed-ledger/src/test/java/org/apache/bookkeeper/mledger/impl/cache/RangeEntryCacheImplTest.java
@@ -27,7 +27,9 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -45,6 +47,8 @@ import org.apache.bookkeeper.mledger.impl.EntryImpl;
import org.apache.bookkeeper.mledger.impl.ManagedLedgerFactoryMBeanImpl;
import org.apache.bookkeeper.mledger.impl.ManagedLedgerImpl;
import org.apache.bookkeeper.mledger.impl.ManagedLedgerMBeanImpl;
+import org.apache.pulsar.common.api.proto.MessageMetadata;
+import org.apache.pulsar.common.protocol.Commands;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -94,6 +98,27 @@ public class RangeEntryCacheImplTest {
expectedReadCount = () -> 1;
}
+ @Test
+ public void testInsertParsesMessageMetadata() {
+ MessageMetadata metadata = new MessageMetadata()
+ .setProducerName("producer")
+ .setSequenceId(7)
+ .setPublishTime(123456789L);
+ ByteBuf headersAndPayload = Commands.serializeMetadataAndPayload(Commands.ChecksumType.Crc32c, metadata,
+ Unpooled.copiedBuffer("payload", StandardCharsets.UTF_8));
+ EntryImpl entry = EntryImpl.create(1, 50, headersAndPayload);
+ headersAndPayload.release();
+ assertThat(entry.getMessageMetadata()).isNull();
+
+ assertThat(rangeEntryCache.insert(entry)).isTrue();
+
+ // the metadata is parsed once at insert time instead of lazily on the first cache read
+ assertThat(entry.getMessageMetadata()).isNotNull();
+ assertThat(entry.getMessageMetadata().getProducerName()).isEqualTo("producer");
+ assertThat(entry.getMessageMetadata().getSequenceId()).isEqualTo(7);
+ entry.release();
+ }
+
@Test
public void testPartialCachingWithMiddleEntryInCache() {
Entry entry = EntryImpl.create(1, 50, Unpooled.EMPTY_BUFFER);