Copilot commented on code in PR #4873:
URL: https://github.com/apache/bookkeeper/pull/4873#discussion_r3974730230


##########
bookkeeper-server/src/main/java/org/apache/bookkeeper/replication/AuditorTask.java:
##########
@@ -88,24 +88,47 @@ protected CompletableFuture<?> 
publishSuspectedLedgersAsync(Collection<String> m
                 .attr("ledgers", ledgers)
                 .attr("missingBookies", missingBookies)
                 .log("Following ledgers are identified as underreplicated");
-        
auditorStats.getNumUnderReplicatedLedger().registerSuccessfulValue(ledgers.size());
+        LongAdder publishedLedgers = new LongAdder();
         LongAdder underReplicatedSize = new LongAdder();
-        FutureUtils.processList(
+        CompletableFuture<List<Void>> publishFuture = FutureUtils.processList(
                 Lists.newArrayList(ledgers),
-                ledgerId ->
-                        
ledgerManager.readLedgerMetadata(ledgerId).whenComplete((metadata, exception) 
-> {
-                            if (exception == null) {
-                                
underReplicatedSize.add(metadata.getValue().getLength());
-                            }
-                        }), null).whenComplete((res, e) -> {
+                ledgerId -> 
ledgerManager.readLedgerMetadata(ledgerId).handle((metadata, exception) -> {
+                    if (exception != null) {
+                        if (BKException.getExceptionCode(exception)
+                                == 
BKException.Code.NoSuchLedgerExistsOnMetadataServerException) {
+                            log.info()
+                                    .attr("ledgerId", ledgerId)
+                                    .log("Ledger was deleted before publishing 
underreplicated mark");
+                            return FutureUtils.Void();
+                        }
+                        log.warn()
+                                .attr("ledgerId", ledgerId)
+                                .exception(exception)
+                                .log("Unable to read ledger metadata; 
publishing underreplicated mark fail-open");
+                    } else if (metadata == null || metadata.getValue() == 
null) {
+                        log.warn()
+                                .attr("ledgerId", ledgerId)
+                                .log("Ledger metadata was empty; publishing 
underreplicated mark fail-open");
+                    } else if (metadata.getValue().getWriteQuorumSize() == 1) {
+                        auditorStats.getNumSingleReplicaLedgersSkipped().inc();
+                        log.info()
+                                .attr("ledgerId", ledgerId)
+                                .attr("writeQuorumSize", 
metadata.getValue().getWriteQuorumSize())
+                                .attr("reason", "single-replica-ledger")
+                                .attr("action", "skip-publish")
+                                .log("Skipping underreplicated mark");
+                        return FutureUtils.Void();
+                    } else {
+                        
underReplicatedSize.add(metadata.getValue().getLength());
+                    }
+
+                    publishedLedgers.increment();
+                    return 
ledgerUnderreplicationManager.markLedgerUnderreplicatedAsync(ledgerId, 
missingBookies);
+                }).thenCompose(markFuture -> markFuture), 
null).whenComplete((res, e) -> {

Review Comment:
   `CompletableFuture.handle(...)` produces a value, but this lambda returns a 
mix of `Void` (via `FutureUtils.Void()`) and `CompletableFuture<?>` (from 
`markLedgerUnderreplicatedAsync`). That makes the `handle` result type 
inconsistent and causes `.thenCompose(markFuture -> markFuture)` to receive a 
non-`CompletionStage` in the skip/delete branches, which should fail to compile 
(or throw at runtime if it compiles via raw types). Make the `handle` lambda 
always return a `CompletableFuture<Void>` (e.g., return a completed future for 
the skip/delete branches) and flatten with `thenCompose(Function.identity())` 
(or equivalent) only when the lambda consistently returns futures.



##########
site3/website/docs/admin/autorecovery.md:
##########
@@ -102,7 +102,11 @@ Both of these components run as threads in the 
[`AutoRecoveryMain`]({{site.javad
 
 The auditor watches all bookies in the cluster that are registered with 
ZooKeeper. Bookies register with ZooKeeper at startup. If the bookie crashes or 
is killed, the bookie's registration in ZooKeeper disappears and the auditor is 
notified of the change in the list of registered bookies.
 
-When the auditor sees that a bookie has disappeared, it immediately scans the 
complete ledger list to find ledgers that have data stored on the failed 
bookie. Once it has a list of ledgers for that bookie, the auditor will publish 
a rereplication task for each ledger under the `/underreplicated/` 
[znode](https://zookeeper.apache.org/doc/current/zookeeperOver.html) in 
ZooKeeper.
+When the auditor sees that a bookie has disappeared, it immediately scans the 
complete ledger list to find ledgers that have data stored on the failed 
bookie. For ledgers with `writeQuorumSize > 1`, the auditor publishes a 
rereplication task under the `/underreplicated/` 
[znode](https://zookeeper.apache.org/doc/current/zookeeperOver.html) in 
ZooKeeper.
+
+The auditor does not publish failed-bookie tasks for ledgers with 
`writeQuorumSize == 1`. Each entry in such a ledger has only one data source, 
so if that source Bookie is permanently lost, AutoRecovery cannot reconstruct 
the data. The replication worker also removes matching historical failed-bookie 
tasks created before an upgrade. This behavior does not apply to 
placement-policy repair tasks, which have no failed Bookie in their replica 
list and may still migrate data from an available source.
+
+Skipped ledgers are reported by the `NUM_SINGLE_REPLICA_LEDGERS_SKIPPED` 
Auditor counter and the `NUM_SINGLE_REPLICA_UNDERREPLICATED_LEDGERS_SKIPPED` 
replication-worker counter. These counters indicate possible data loss, not 
successful recovery. Operators should alert on them and use the original Bookie 
disk, backups, or application-specific recovery procedures when the data must 
be restored.

Review Comment:
   The doc names the counters without their full metric paths/scopes, which can 
make them hard to locate in common stats backends. Consider documenting the 
fully qualified names (e.g., `auditor.NUM_SINGLE_REPLICA_LEDGERS_SKIPPED` and 
`replication_worker.NUM_SINGLE_REPLICA_UNDERREPLICATED_LEDGERS_SKIPPED`) to 
match the operational notes in the PR description and reduce ambiguity for 
operators.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to