/** * Indicates that this write completed successfully. This will set the final result on the externalCompletion future. */ Timer complete() { Preconditions.checkState(this.entryId.get() >= 0, "entryId not set; cannot complete Write."); this.failureCause.set(null); this.result.complete(new LedgerAddress(this.writeLedger.get().metadata, this.entryId.get())); return endAttempt(); }
@Override public boolean equals(Object obj) { if (obj instanceof LedgerAddress) { return this.compareTo((LedgerAddress) obj) == 0; } return false; }
@Override public String toString() { return String.format("Version = %d, Epoch = %d, LedgerCount = %d, Truncate = (%d-%d)", this.updateVersion.get(), this.epoch, this.ledgers.size(), this.truncationAddress.getLedgerId(), this.truncationAddress.getEntryId()); }
if (address.getLedgerSequence() < firstLedger.getSequence()) { result = new LedgerAddress(firstLedger, 0); } else if (address.getEntryId() < lastEntryId) { result = new LedgerAddress(address.getLedgerSequence(), address.getLedgerId(), address.getEntryId() + 1); } else { int index = getLedgerMetadataIndex(address.getLedgerId()) + 1; if (index > 0) { if (lm.getLedgerId() > address.getLedgerId()) { ledgerMetadata = lm; break; result = new LedgerAddress(ledgerMetadata, 0); if (result != null && result.compareTo(this.truncationAddress) < 0) { result = this.truncationAddress;
private void assertEquals(LedgerAddress a, int ledgerSeq, long ledgerId, long entryId) { Assert.assertEquals("Unexpected ledger sequence.", ledgerSeq, a.getLedgerSequence()); Assert.assertEquals("Unexpected ledger id.", ledgerId, a.getLedgerId()); Assert.assertEquals("Unexpected entry id.", entryId, a.getEntryId()); } }
private void write00(LogMetadata m, RevisionDataOutput output) throws IOException { output.writeBoolean(m.isEnabled()); output.writeCompactLong(m.getEpoch()); output.writeCompactLong(m.truncationAddress.getSequence()); output.writeCompactLong(m.truncationAddress.getLedgerId()); output.writeCollection(m.ledgers, this::writeLedger00); }
/** * Tests the various properties as well as translation from the encoded sequence and back. */ @Test(timeout = 5000) public void testSequence() { for (int ledgerSeq = 0; ledgerSeq < LEDGER_COUNT; ledgerSeq++) { long ledgerId = (ledgerSeq + 1) * 31; for (long entryId = 0; entryId < ENTRY_COUNT; entryId++) { val a = new LedgerAddress(ledgerSeq, ledgerId, entryId); assertEquals(a, ledgerSeq, ledgerId, entryId); val a2 = new LedgerAddress(a.getSequence(), ledgerId); assertEquals(a2, ledgerSeq, ledgerId, entryId); } } }
/** * Tests the Compare method. */ @Test(timeout = 5000) public void testCompare() { val addresses = new ArrayList<LedgerAddress>(); for (int ledgerSeq = 0; ledgerSeq < LEDGER_COUNT; ledgerSeq++) { long ledgerId = (ledgerSeq + 1) * 31; for (long entryId = 0; entryId < ENTRY_COUNT; entryId++) { addresses.add(new LedgerAddress(ledgerSeq, ledgerId, entryId)); } } for (int i = 0; i < addresses.size() / 2; i++) { val a1 = addresses.get(i); val a2 = addresses.get(addresses.size() - i - 1); val result1 = a1.compareTo(a2); val result2 = a2.compareTo(a1); AssertExtensions.assertLessThan("Unexpected when comparing smaller to larger.", 0, result1); AssertExtensions.assertGreaterThan("Unexpected when comparing larger to smaller.", 0, result2); Assert.assertEquals("Unexpected when comparing to itself.", 0, a1.compareTo(a1)); } }
/** * Gets a Sequence number identifying the Ledger inside the log. This is different from getSequence (which identifies * a particular write inside the entire log. It is also different from LedgerId, which is a BookKeeper assigned id. * * @return The result. */ int getLedgerSequence() { return (int) (getSequence() >>> 32); }
@Override public String toString() { return String.format("%s, LedgerId = %d, EntryId = %d", super.toString(), this.ledgerId, getEntryId()); }
/** * Creates a new instance of the LogMetadata class which contains all the ledgers after (and including) the given address. * * @param upToAddress The address to truncate to. * @return A new instance of the LogMetadata class. */ LogMetadata truncate(LedgerAddress upToAddress) { Preconditions.checkState(this.enabled, "Log is not enabled. Cannot perform any modifications on it."); // Exclude all those Ledgers that have a LedgerId less than the one we are given. An optimization to this would // involve trimming out the ledger which has a matching ledger id and the entry is is the last one, but that would // involve opening the Ledger in BookKeeper and inspecting it, which would take too long. val newLedgers = this.ledgers.stream().filter(lm -> lm.getLedgerId() >= upToAddress.getLedgerId()).collect(Collectors.toList()); return new LogMetadata(this.epoch, this.enabled, Collections.unmodifiableList(newLedgers), upToAddress, this.updateVersion.get()); }
/** * Creates a new instance of the LedgerAddress class. * * @param ledgerSequence The sequence of the Ledger (This is different from the Entry Sequence). * @param ledgerId The Id of the Ledger that this Address corresponds to. * @param entryId The Entry Id inside the Ledger that this Address corresponds to. */ LedgerAddress(int ledgerSequence, long ledgerId, long entryId) { this(calculateAppendSequence(ledgerSequence, entryId), ledgerId); }
val empty = new LogMetadata(1).truncate(new LedgerAddress(2, 2, 2)); Assert.assertNull("Unexpected result from empty metadata", empty.getNextAddress(new LedgerAddress(1, 1, 0), Long.MAX_VALUE)); LedgerAddress a = m.getNextAddress(new LedgerAddress(firstLedgerSeq - 1, firstLedgerId - 1, 1234), Long.MAX_VALUE); Assert.assertEquals("Unexpected ledger id when input address less than first ledger.", firstLedgerId, a.getLedgerId()); Assert.assertEquals("Unexpected entry id when input address less than first ledger.", 0, a.getEntryId()); LedgerAddress truncationAddress = new LedgerAddress(secondLedgerSeq, secondLedgerId, 1); val m2 = m.truncate(truncationAddress); a = m2.getNextAddress(new LedgerAddress(firstLedgerSeq, firstLedgerId, 0), Long.MAX_VALUE); Assert.assertEquals("Unexpected result when input address less than truncation address.", 0, truncationAddress.compareTo(a)); a = m.getNextAddress(new LedgerAddress(firstLedgerSeq, firstLedgerId, 0), 2); Assert.assertEquals("Unexpected ledger id when result should be in the same ledger.", firstLedgerId, a.getLedgerId()); Assert.assertEquals("Unexpected entry id when result should be in the same ledger.", 1, a.getEntryId()); a = m.getNextAddress(new LedgerAddress(lm.getSequence(), lm.getLedgerId(), 3), 3); if (i == m.getLedgers().size() - 1) { Assert.assertNull("Unexpected result when reached the end of the log.", a); } else { val nextLm = m.getLedgers().get(i + 1); Assert.assertEquals("Unexpected ledger id when result should be in the next ledger.", nextLm.getLedgerId(), a.getLedgerId()); Assert.assertEquals("Unexpected entry id when result should be in the next ledger.", 0, a.getEntryId()); a = m.getNextAddress(new LedgerAddress(firstLedgerSeq + 1, firstLedgerId + 1, 3), 3); Assert.assertEquals("Unexpected ledger id when result should be in the next ledger.", secondLedgerId, a.getLedgerId()); Assert.assertEquals("Unexpected entry id when result should be in the next ledger.", 0, a.getEntryId());
/** * 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()); }
/** * Gets a value representing the BookKeeper-assigned Entry id of this address. This entry id is unique per ledger, but * is likely duplicated across ledgers (since it grows sequentially from 0 in each ledger). * * @return The result. */ long getEntryId() { return getSequence() & INT_MASK; }
/** * Creates a new instance of the LedgerAddress class. * * @param metadata The LedgerMetadata for the ledger. * @param entryId The Entry Id inside the Ledger that this Address corresponds to. */ LedgerAddress(LedgerMetadata metadata, long entryId) { this(calculateAppendSequence(metadata.getSequence(), entryId), metadata.getLedgerId()); }
LedgerMetadata metadata = this.metadata.getLedger(address.getLedgerId()); assert metadata != null : "no LedgerMetadata could be found with valid LedgerAddress " + address; val allMetadatas = this.metadata.getLedgers(); if (lastEntryId < address.getEntryId()) { try { val reader = Exceptions.handleInterruptedCall( () -> ledger.readEntries(address.getEntryId(), lastEntryId)); previousLedger = this.currentLedger; this.currentLedger = new ReadLedger(metadata, ledger, reader);
@Override protected LogAddress createLogAddress(long seqNo) { return new LedgerAddress(seqNo, seqNo); }
@Override public int compareTo(LedgerAddress address) { return Long.compare(getSequence(), address.getSequence()); }
@SneakyThrows(IOException.class) ReadItem(LedgerEntry entry, LedgerMetadata ledgerMetadata) { this.address = new LedgerAddress(ledgerMetadata, entry.getEntryId()); this.payload = entry.getEntryInputStream(); this.length = this.payload.available(); }