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/10/20 13:20:51 UTC
(pulsar) 13/19: [fix][broker] Remove the sticky key hashes of a sparse replay prefix when the mark-delete position moves (#26976)
This is an automated email from the ASF dual-hosted git repository.
lhotari pushed a commit to branch branch-4.2-cherry-picks-2026-10-20
in repository https://gitbox.apache.org/repos/asf/pulsar.git
commit 7efe7a4637ea60b567b716e7725a0feb9b3b2e15
Author: Lari Hotari <lh...@users.noreply.github.com>
AuthorDate: Sun Oct 18 22:59:00 2026 +0300
[fix][broker] Remove the sticky key hashes of a sparse replay prefix when the mark-delete position moves (#26976)
(cherry picked from commit d137d35fba8ef57c47641fb4ed03a71edca9b72c)
---
.../utils/ConcurrentBitmapSortedLongPairSet.java | 3 ++-
.../persistent/MessageRedeliveryControllerTest.java | 18 ++++++++++++++++++
.../utils/ConcurrentBitmapSortedLongPairSetTest.java | 13 +++++++++++++
3 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/utils/ConcurrentBitmapSortedLongPairSet.java b/pulsar-broker/src/main/java/org/apache/pulsar/utils/ConcurrentBitmapSortedLongPairSet.java
index 70437d07dbee..281dd445fff5 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/utils/ConcurrentBitmapSortedLongPairSet.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/utils/ConcurrentBitmapSortedLongPairSet.java
@@ -94,7 +94,8 @@ public class ConcurrentBitmapSortedLongPairSet {
} else {
RoaringBitmap bitSet = firstEntry.getValue();
if (bitSet != null) {
- bitsCleared |= bitSet.contains(0, item2);
+ // any bit below item2, not every one: a sparse prefix has gaps
+ bitsCleared |= bitSet.intersects(0, item2);
bitSet.remove(0, item2);
if (bitSet.isEmpty()) {
map.remove(firstEntry.getKey(), bitSet);
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/persistent/MessageRedeliveryControllerTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/persistent/MessageRedeliveryControllerTest.java
index 03c7e6cf439e..2f9b22f98c98 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/persistent/MessageRedeliveryControllerTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/persistent/MessageRedeliveryControllerTest.java
@@ -144,6 +144,24 @@ public class MessageRedeliveryControllerTest {
}
}
+ @Test(dataProvider = "allowOutOfOrderDelivery", timeOut = 10000)
+ public void testRemoveAllUpToASparsePrefixRemovesItsHashes(boolean allowOutOfOrderDelivery) {
+ MessageRedeliveryController controller = new MessageRedeliveryController(allowOutOfOrderDelivery);
+ // a gap between the positions removed and the one kept, in the same ledger
+ controller.add(1, 5, 100);
+ controller.add(1, 100, 200);
+
+ controller.removeAllUpTo(1, 10);
+
+ assertEquals(controller.size(), 1);
+ assertNull(controller.getHash(1, 5));
+ assertEquals(controller.getHash(1, 100), Long.valueOf(200));
+ assertFalse(controller.containsStickyKeyHash(100));
+ if (!allowOutOfOrderDelivery) {
+ assertTrue(controller.containsStickyKeyHash(200));
+ }
+ }
+
@Test(timeOut = 10000)
public void testOutOfOrderSentinelHashDoesNotInitializePositionHashMap() {
MessageRedeliveryController controller = new MessageRedeliveryController(true);
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/utils/ConcurrentBitmapSortedLongPairSetTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/utils/ConcurrentBitmapSortedLongPairSetTest.java
index 29e5ae5e735e..923e669ccc9c 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/utils/ConcurrentBitmapSortedLongPairSetTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/utils/ConcurrentBitmapSortedLongPairSetTest.java
@@ -128,6 +128,19 @@ public class ConcurrentBitmapSortedLongPairSetTest {
assertTrue(set.isEmpty());
}
+ @Test
+ public void testRemoveUpToReportsASparsePrefix() {
+ ConcurrentBitmapSortedLongPairSet set = new ConcurrentBitmapSortedLongPairSet();
+ set.add(1, 5);
+ set.add(1, 100);
+
+ // removes 1:5 although 1:0 to 1:4 and 1:6 to 1:10 were never there
+ assertTrue(set.removeUpTo(1, 11));
+ assertFalse(set.contains(1, 5));
+ assertTrue(set.contains(1, 100));
+ assertFalse(set.removeUpTo(1, 11));
+ }
+
@Test
public void testItems() {
ConcurrentBitmapSortedLongPairSet set = new ConcurrentBitmapSortedLongPairSet();