/** * Removes LedgerMetadata instances for those Ledgers that are known to be empty. * * @param skipCountFromEnd The number of Ledgers to spare, counting from the end of the LedgerMetadata list. * @return A new instance of LogMetadata with the updated ledger list. */ LogMetadata removeEmptyLedgers(int skipCountFromEnd) { val newLedgers = new ArrayList<LedgerMetadata>(); int cutoffIndex = this.ledgers.size() - skipCountFromEnd; for (int i = 0; i < cutoffIndex; i++) { LedgerMetadata lm = this.ledgers.get(i); if (lm.getStatus() != LedgerMetadata.Status.Empty) { // Not Empty or Unknown: keep it! newLedgers.add(lm); } } // Add the ones from the end, as instructed. for (int i = cutoffIndex; i < this.ledgers.size(); i++) { newLedgers.add(this.ledgers.get(i)); } return new LogMetadata(this.epoch, this.enabled, Collections.unmodifiableList(newLedgers), this.truncationAddress, this.updateVersion.get()); }
/** * Updates the LastAddConfirmed on individual LedgerMetadata instances based on the provided argument. * * @param lastAddConfirmed A Map of LedgerId to LastAddConfirmed based on which we can update the status. * @return This (unmodified) instance if lastAddConfirmed.isEmpty() or a new instance of the LogMetadata class with * the updated LedgerMetadata instances. */ LogMetadata updateLedgerStatus(Map<Long, Long> lastAddConfirmed) { if (lastAddConfirmed.isEmpty()) { // Nothing to change. return this; } val newLedgers = this.ledgers.stream() .map(lm -> { long lac = lastAddConfirmed.getOrDefault(lm.getLedgerId(), Long.MIN_VALUE); if (lm.getStatus() == LedgerMetadata.Status.Unknown && lac != Long.MIN_VALUE) { LedgerMetadata.Status e = lac == Ledgers.NO_ENTRY_ID ? LedgerMetadata.Status.Empty : LedgerMetadata.Status.NotEmpty; lm = new LedgerMetadata(lm.getLedgerId(), lm.getSequence(), e); } return lm; }) .collect(Collectors.toList()); return new LogMetadata(this.epoch, this.enabled, Collections.unmodifiableList(newLedgers), this.truncationAddress, this.updateVersion.get()); }
if (ledgerMetadata.getStatus() == LedgerMetadata.Status.Unknown) {
private void writeLedger00(RevisionDataOutput output, LedgerMetadata m) throws IOException { output.writeCompactLong(m.getLedgerId()); output.writeCompactInt(m.getSequence()); output.writeByte(m.getStatus().getValue()); }
for (long ledgerId : expectedLedgerIds) { Assert.assertEquals("markEmptyLedgers modified base metadata", LedgerMetadata.Status.Unknown, metadata.getLedger(ledgerId).getStatus()); long lac = lacs.getOrDefault(ledgerId, Long.MIN_VALUE); LedgerMetadata.Status expectedStatus = lac == Long.MIN_VALUE : (lac == -1 ? LedgerMetadata.Status.Empty : LedgerMetadata.Status.NotEmpty); Assert.assertEquals("markEmptyLedgers did not return an updated metadata.", expectedStatus, m.getLedger(ledgerId).getStatus()); .filter(lm -> lm.getStatus() != LedgerMetadata.Status.Empty) .map(LedgerMetadata::getLedgerId) .forEach(expectedLedgerIds::add);
val bkLm = context.bkAdmin.getLedgerMetadata(lh); output("\tLedger %d: Seq=%d, Status=%s, LAC=%d, Length=%d, Bookies=%d, Frags=%d, E/W/A=%d/%d/%d, Ensembles=%s.", lm.getLedgerId(), lm.getSequence(), lm.getStatus(), lh.getLastAddConfirmed(), lh.getLength(), lh.getNumBookies(), lh.getNumFragments(), bkLm.getEnsembleSize(), bkLm.getWriteQuorumSize(), bkLm.getAckQuorumSize(), getEnsembleDescription(bkLm)); } catch (Exception ex) { output("\tLedger %d: Seq = %d, Status = %s. BK: %s", lm.getLedgerId(), lm.getSequence(), lm.getStatus(), ex.getMessage()); } finally { if (lh != null) {
/** * Tests serialization/deserialization. */ @Test(timeout = 5000) public void testSerialization() throws Exception { Supplier<Long> nextLedgerId = new AtomicLong()::incrementAndGet; LogMetadata m1 = null; val lacs = new HashMap<Long, Long>(); for (int i = 0; i < LEDGER_COUNT; i++) { long ledgerId = nextLedgerId.get() * 2; if (m1 == null) { m1 = new LogMetadata(ledgerId).withUpdateVersion(i); } else { m1 = m1.addLedger(ledgerId).withUpdateVersion(i); } if (i % 2 == 0) { // Every other Ledger, update the LastAddConfirmed. lacs.put((long) i, (long) i + 1); } } m1 = m1.updateLedgerStatus(lacs); val serialization = LogMetadata.SERIALIZER.serialize(m1); val m2 = LogMetadata.SERIALIZER.deserialize(serialization); Assert.assertEquals("Unexpected epoch.", m1.getEpoch(), m2.getEpoch()); Assert.assertEquals("Unexpected TruncationAddress.", m1.getTruncationAddress().getSequence(), m2.getTruncationAddress().getSequence()); Assert.assertEquals("Unexpected TruncationAddress.", m1.getTruncationAddress().getLedgerId(), m2.getTruncationAddress().getLedgerId()); AssertExtensions.assertListEquals("Unexpected ledgers.", m1.getLedgers(), m2.getLedgers(), (l1, l2) -> l1.getSequence() == l2.getSequence() && l1.getLedgerId() == l2.getLedgerId() && l1.getStatus() == l2.getStatus()); }