This is an automated email from the ASF dual-hosted git repository.
merlimat pushed a commit to branch branch-4.2
in repository https://gitbox.apache.org/repos/asf/pulsar.git
The following commit(s) were added to refs/heads/branch-4.2 by this push:
new 3a2cfe6dbb88 [fix][metadata] Fix orphaned UR parent nodes not cleaned
up with Oxia metadata backend (#26158)
3a2cfe6dbb88 is described below
commit 3a2cfe6dbb8899a90c8140155dc2aaa69c23d23a
Author: Eugene Polozhenkov <[email protected]>
AuthorDate: Tue Jul 7 15:50:12 2026 -0400
[fix][metadata] Fix orphaned UR parent nodes not cleaned up with Oxia
metadata backend (#26158)
Co-authored-by: ievgenpolozhenkov <[email protected]>
(cherry picked from commit 8d5cac607646ccda183373ad7b31e6ffb7e13836)
Assisted-by: Claude Code (Opus 4.8)
---
.../pulsar/metadata/api/MetadataStoreException.java | 8 ++++++++
.../PulsarLedgerUnderreplicationManager.java | 18 ++++++++++++------
.../pulsar/metadata/impl/oxia/OxiaMetadataStore.java | 2 +-
.../bookkeeper/LedgerUnderreplicationManagerTest.java | 4 ++--
4 files changed, 23 insertions(+), 9 deletions(-)
diff --git
a/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/api/MetadataStoreException.java
b/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/api/MetadataStoreException.java
index 2e2b13a26665..5ddf9a253d8e 100644
---
a/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/api/MetadataStoreException.java
+++
b/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/api/MetadataStoreException.java
@@ -156,6 +156,14 @@ public class MetadataStoreException extends IOException {
}
}
+ public static class NotEmptyException extends MetadataStoreException {
+ private static final long serialVersionUID = 1L;
+
+ public NotEmptyException(String path) {
+ super("Key '" + path + "' has children");
+ }
+ }
+
public static MetadataStoreException unwrap(Throwable t) {
if (t instanceof MetadataStoreException) {
return (MetadataStoreException) t;
diff --git
a/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java
b/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java
index a299f664e376..f56f6e10f829 100644
---
a/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java
+++
b/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java
@@ -71,6 +71,7 @@ import org.apache.pulsar.metadata.api.extended.CreateOption;
import org.apache.pulsar.metadata.api.extended.MetadataStoreExtended;
import org.apache.pulsar.metadata.impl.DualMetadataStore;
import org.apache.pulsar.metadata.impl.ZKMetadataStore;
+import org.apache.pulsar.metadata.impl.oxia.OxiaMetadataStore;
import org.apache.zookeeper.KeeperException;
@Slf4j
@@ -444,7 +445,8 @@ public class PulsarLedgerUnderreplicationManager implements
LedgerUnderreplicati
store.delete(getUrLedgerPath(ledgerId),
Optional.of(l.getLedgerNodeVersion()))
.get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);
if (store instanceof ZKMetadataStore
- || store instanceof DualMetadataStore) {
+ || store instanceof DualMetadataStore
+ || store instanceof OxiaMetadataStore) {
try {
// clean up the hierarchy
String[] parts = getUrLedgerPath(ledgerId).split("/");
@@ -462,11 +464,15 @@ public class PulsarLedgerUnderreplicationManager
implements LedgerUnderreplicati
// It's safe to ignore, it simply means another
// ledger in the same hierarchy has been marked as
// underreplicated.
- if (ee.getCause() instanceof MetadataStoreException &&
ee.getCause().getCause()
- instanceof KeeperException.NotEmptyException) {
- //do nothing.
- } else {
- log.warn("Error deleting underrepcalited ledger
parent node", ee);
+ // Oxia raises NotEmptyException directly; ZK wraps
+ // KeeperException.NotEmptyException inside a
MetadataStoreException.
+ boolean isNotEmpty =
+ ee.getCause() instanceof
MetadataStoreException.NotEmptyException
+ || (ee.getCause() instanceof
MetadataStoreException
+ && ee.getCause().getCause()
+ instanceof
KeeperException.NotEmptyException);
+ if (!isNotEmpty) {
+ log.warn("Error deleting underreplicated ledger
parent node", ee);
}
}
}
diff --git
a/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/impl/oxia/OxiaMetadataStore.java
b/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/impl/oxia/OxiaMetadataStore.java
index 1bbec3be80c4..675f3dbf1ad6 100644
---
a/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/impl/oxia/OxiaMetadataStore.java
+++
b/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/impl/oxia/OxiaMetadataStore.java
@@ -181,7 +181,7 @@ public class OxiaMetadataStore extends
AbstractMetadataStore {
children -> {
if (!children.isEmpty()) {
return CompletableFuture.failedFuture(
- new MetadataStoreException("Key '" +
path + "' has children"));
+ new
MetadataStoreException.NotEmptyException(path));
} else {
Set<DeleteOption> delOption =
expectedVersion
diff --git
a/pulsar-metadata/src/test/java/org/apache/pulsar/metadata/bookkeeper/LedgerUnderreplicationManagerTest.java
b/pulsar-metadata/src/test/java/org/apache/pulsar/metadata/bookkeeper/LedgerUnderreplicationManagerTest.java
index ac73491a81c6..6508e6943eec 100644
---
a/pulsar-metadata/src/test/java/org/apache/pulsar/metadata/bookkeeper/LedgerUnderreplicationManagerTest.java
+++
b/pulsar-metadata/src/test/java/org/apache/pulsar/metadata/bookkeeper/LedgerUnderreplicationManagerTest.java
@@ -300,8 +300,8 @@ public class LedgerUnderreplicationManagerTest extends
BaseMetadataStoreTest {
assertEquals(l, lB.get(), "Should be the ledger I marked");
}
- @Test(dataProvider = "zkImpls", timeOut = 10000)
- public void testZkMetasStoreMarkReplicatedDeleteEmptyParentNodes(String
provider, Supplier<String> urlSupplier)
+ @Test(dataProvider = "distributedImpl", timeOut = 10000)
+ public void testMarkReplicatedDeletesEmptyParentNodes(String provider,
Supplier<String> urlSupplier)
throws Exception {
methodSetup(urlSupplier);