protected void asyncReadEntry(ReadHandle ledger, long firstEntry, long lastEntry, boolean isSlowestReader, OpReadEntry opReadEntry, Object ctx) { long timeout = config.getReadEntryTimeoutSeconds(); boolean checkTimeout = timeout > 0; if (checkTimeout) { // set readOpCount to uniquely validate if ReadEntryCallbackWrapper is already recycled long readOpCount = READ_OP_COUNT_UPDATER.incrementAndGet(this); ReadEntryCallbackWrapper readCallback = ReadEntryCallbackWrapper.create(name, ledger.getId(), firstEntry, opReadEntry, readOpCount, ctx); final ScheduledFuture<?> task = scheduledExecutor.schedule(() -> { // validate ReadEntryCallbackWrapper object is not recycled by bk-client callback (by validating // readOpCount) and fail the callback if read is not completed yet if (readCallback.readOpCount == readOpCount && ReadEntryCallbackWrapper.READ_COMPLETED_UPDATER.get(readCallback) == FALSE) { log.warn("[{}]-{} read entry timeout for {}-{} after {} sec", this.name, ledger.getId(), firstEntry, lastEntry, timeout); readCallback.readEntriesFailed(createManagedLedgerException(BKException.Code.TimeoutException), readOpCount); } }, timeout, TimeUnit.SECONDS); readCallback.task = task; entryCache.asyncReadEntry(ledger, firstEntry, lastEntry, isSlowestReader, readCallback, readOpCount); } else { entryCache.asyncReadEntry(ledger, firstEntry, lastEntry, isSlowestReader, opReadEntry, ctx); } }
protected void asyncReadEntry(ReadHandle ledger, PositionImpl position, ReadEntryCallback callback, Object ctx) { long timeout = config.getReadEntryTimeoutSeconds(); boolean checkTimeout = timeout > 0; if (checkTimeout) { // set readOpCount to uniquely validate if ReadEntryCallbackWrapper is already recycled long readOpCount = READ_OP_COUNT_UPDATER.incrementAndGet(this); ReadEntryCallbackWrapper readCallback = ReadEntryCallbackWrapper.create(name, position.getLedgerId(), position.getEntryId(), callback, readOpCount, ctx); final ScheduledFuture<?> task = scheduledExecutor.schedule(() -> { // validate ReadEntryCallbackWrapper object is not recycled by bk-client callback (by validating // readOpCount) and fail the callback if read is not completed yet if (readCallback.readOpCount == readOpCount && ReadEntryCallbackWrapper.READ_COMPLETED_UPDATER.get(readCallback) == FALSE) { log.warn("[{}]-{} read entry timeout for {} after {} sec", this.name, ledger.getId(), position, timeout); readCallback.readEntryFailed(createManagedLedgerException(BKException.Code.TimeoutException), readOpCount); } }, timeout, TimeUnit.SECONDS); readCallback.task = task; entryCache.asyncReadEntry(ledger, position, readCallback, readOpCount); } else { entryCache.asyncReadEntry(ledger, position, callback, ctx); } }
@Test(timeOut = 5000) void testReadMissingBefore() throws Exception { ReadHandle lh = getLedgerHandle(); when(lh.getId()).thenReturn((long) 0); EntryCacheManager cacheManager = factory.getEntryCacheManager(); EntryCache entryCache = cacheManager.getEntryCache(ml); byte[] data = new byte[10]; for (int i = 3; i < 10; i++) { entryCache.insert(EntryImpl.create(0, i, data)); } final CountDownLatch counter = new CountDownLatch(1); entryCache.asyncReadEntry(lh, 0, 9, false, new ReadEntriesCallback() { public void readEntriesComplete(List<Entry> entries, Object ctx) { assertEquals(entries.size(), 10); counter.countDown(); } public void readEntriesFailed(ManagedLedgerException exception, Object ctx) { Assert.fail("should not have failed"); } }, null); counter.await(); }
@Test(timeOut = 5000) void testReadMissingAfter() throws Exception { ReadHandle lh = getLedgerHandle(); when(lh.getId()).thenReturn((long) 0); EntryCacheManager cacheManager = factory.getEntryCacheManager(); EntryCache entryCache = cacheManager.getEntryCache(ml); byte[] data = new byte[10]; for (int i = 0; i < 8; i++) { entryCache.insert(EntryImpl.create(0, i, data)); } final CountDownLatch counter = new CountDownLatch(1); entryCache.asyncReadEntry(lh, 0, 9, false, new ReadEntriesCallback() { public void readEntriesComplete(List<Entry> entries, Object ctx) { assertEquals(entries.size(), 10); counter.countDown(); } public void readEntriesFailed(ManagedLedgerException exception, Object ctx) { Assert.fail("should not have failed"); } }, null); counter.await(); }
@Test(timeOut = 5000) void testRead() throws Exception { ReadHandle lh = getLedgerHandle(); when(lh.getId()).thenReturn((long) 0); EntryCacheManager cacheManager = factory.getEntryCacheManager(); EntryCache entryCache = cacheManager.getEntryCache(ml); byte[] data = new byte[10]; for (int i = 0; i < 10; i++) { entryCache.insert(EntryImpl.create(0, i, data)); } final CountDownLatch counter = new CountDownLatch(1); entryCache.asyncReadEntry(lh, 0, 9, false, new ReadEntriesCallback() { public void readEntriesComplete(List<Entry> entries, Object ctx) { assertEquals(entries.size(), 10); entries.forEach(e -> e.release()); counter.countDown(); } public void readEntriesFailed(ManagedLedgerException exception, Object ctx) { Assert.fail("should not have failed"); } }, null); counter.await(); // Verify no entries were read from bookkeeper verify(lh, never()).readAsync(anyLong(), anyLong()); }
@Test(timeOut = 5000) void testReadWithError() throws Exception { final ReadHandle lh = getLedgerHandle(); when(lh.getId()).thenReturn((long) 0); doAnswer((invocation) -> { CompletableFuture<LedgerEntries> future = new CompletableFuture<>(); future.completeExceptionally(new BKNoSuchLedgerExistsException()); return future; }).when(lh).readAsync(anyLong(), anyLong()); EntryCacheManager cacheManager = factory.getEntryCacheManager(); EntryCache entryCache = cacheManager.getEntryCache(ml); byte[] data = new byte[10]; entryCache.insert(EntryImpl.create(0, 2, data)); final CountDownLatch counter = new CountDownLatch(1); entryCache.asyncReadEntry(lh, 0, 9, false, new ReadEntriesCallback() { public void readEntriesComplete(List<Entry> entries, Object ctx) { Assert.fail("should not complete"); } public void readEntriesFailed(ManagedLedgerException exception, Object ctx) { counter.countDown(); } }, null); counter.await(); }
@Test(timeOut = 5000) void testReadMissingMiddle() throws Exception { ReadHandle lh = getLedgerHandle(); when(lh.getId()).thenReturn((long) 0); EntryCacheManager cacheManager = factory.getEntryCacheManager(); EntryCache entryCache = cacheManager.getEntryCache(ml); byte[] data = new byte[10]; entryCache.insert(EntryImpl.create(0, 0, data)); entryCache.insert(EntryImpl.create(0, 1, data)); entryCache.insert(EntryImpl.create(0, 8, data)); entryCache.insert(EntryImpl.create(0, 9, data)); final CountDownLatch counter = new CountDownLatch(1); entryCache.asyncReadEntry(lh, 0, 9, false, new ReadEntriesCallback() { public void readEntriesComplete(List<Entry> entries, Object ctx) { assertEquals(entries.size(), 10); counter.countDown(); } public void readEntriesFailed(ManagedLedgerException exception, Object ctx) { Assert.fail("should not have failed"); } }, null); counter.await(); }
@Test(timeOut = 5000) void testReadMissingMultiple() throws Exception { ReadHandle lh = getLedgerHandle(); when(lh.getId()).thenReturn((long) 0); EntryCacheManager cacheManager = factory.getEntryCacheManager(); EntryCache entryCache = cacheManager.getEntryCache(ml); byte[] data = new byte[10]; entryCache.insert(EntryImpl.create(0, 0, data)); entryCache.insert(EntryImpl.create(0, 2, data)); entryCache.insert(EntryImpl.create(0, 5, data)); entryCache.insert(EntryImpl.create(0, 8, data)); final CountDownLatch counter = new CountDownLatch(1); entryCache.asyncReadEntry(lh, 0, 9, false, new ReadEntriesCallback() { public void readEntriesComplete(List<Entry> entries, Object ctx) { assertEquals(entries.size(), 10); counter.countDown(); } public void readEntriesFailed(ManagedLedgerException exception, Object ctx) { Assert.fail("should not have failed"); } }, null); counter.await(); }
@Override void asyncReadEntry(PositionImpl position, AsyncCallbacks.ReadEntryCallback callback, Object ctx) { this.getLedgerHandle(position.getLedgerId()).thenAccept((ledger) -> { this.entryCache.asyncReadEntry(ledger, position, callback, ctx); }).exceptionally((ex) -> { log.error("[{}] Error opening ledger for reading at position {} - {}", new Object[]{this.name, position, ex.getMessage()}); callback.readEntryFailed(ManagedLedgerException.getManagedLedgerException(ex.getCause()), ctx); return null; }); }
void asyncReadEntry(PositionImpl position, ReadEntryCallback callback, Object ctx) { LedgerHandle currentLedger = this.currentLedger; if (log.isDebugEnabled()) { log.debug("[{}] Reading entry ledger {}: {}", name, position.getLedgerId(), position.getEntryId()); } if (position.getLedgerId() == currentLedger.getId()) { LedgerHandle ledger = currentLedger; entryCache.asyncReadEntry(ledger, position, callback, ctx); } else { getLedgerHandle(position.getLedgerId()).thenAccept(ledger -> { entryCache.asyncReadEntry(ledger, position, callback, ctx); }).exceptionally(ex -> { log.error("[{}] Error opening ledger for reading at position {} - {}", name, position, ex.getMessage()); callback.readEntryFailed(ManagedLedgerException.getManagedLedgerException(ex.getCause()), ctx); return null; }); } }
void asyncReadEntry(PositionImpl position, ReadEntryCallback callback, Object ctx) { LedgerHandle currentLedger = this.currentLedger; if (log.isDebugEnabled()) { log.debug("[{}] Reading entry ledger {}: {}", name, position.getLedgerId(), position.getEntryId()); } if (position.getLedgerId() == currentLedger.getId()) { LedgerHandle ledger = currentLedger; entryCache.asyncReadEntry(ledger, position, callback, ctx); } else { getLedgerHandle(position.getLedgerId()).thenAccept(ledger -> { entryCache.asyncReadEntry(ledger, position, callback, ctx); }).exceptionally(ex -> { log.error("[{}] Error opening ledger for reading at position {} - {}", name, position, ex.getMessage()); callback.readEntryFailed(new ManagedLedgerException(ex), ctx); return null; }); } }
lastEntry); entryCache.asyncReadEntry(ledger, firstEntry, lastEntry, false, opReadEntry, opReadEntry.ctx);
lastEntry); entryCache.asyncReadEntry(ledger, firstEntry, lastEntry, false, opReadEntry, opReadEntry.ctx);