if (isClosed()) {
// TODO: make ledger metadata immutable
// Although the metadata is already closed, we don't need to proceed zookeeper metadata update, but
// we still need to error out the pending add ops.
//
// There is a race condition a pending add op is enqueued, after a close op reset ledger metadata state
// to unclosed to resolve metadata conflicts. If we don't error out these pending add ops, they would be
// leak and never callback.
//
// The race condition happen in following sequence:
// a) ledger L is fenced
// b) write entry E encountered LedgerFencedException, trigger ledger close procedure
// c) ledger close encountered metadata version exception and set ledger metadata back to open
// d) writer tries to write entry E+1, since ledger metadata is still open (reset by c))
// e) the close procedure in c) resolved the metadata conflicts and set ledger metadata to closed
// f) writing entry E+1 encountered LedgerFencedException which will enter ledger close procedure
// g) it would find that ledger metadata is closed, then it callbacks immediately without erroring out any pendings
synchronized (LedgerHandle.this) {
pendingAdds = drainPendingAddsToErrorOut();
}
errorOutPendingAdds(rc, pendingAdds);
cb.closeComplete(BKException.Code.OK, LedgerHandle.this, ctx);
return;
}