@Test void verifyNoCacheIfNoConsumer() throws Exception { ManagedLedgerFactoryConfig config = new ManagedLedgerFactoryConfig(); config.setMaxCacheSize(7 * 10); config.setCacheEvictionWatermark(0.8); factory = new ManagedLedgerFactoryImpl(bkc, bkc.getZkHandle(), config); EntryCacheManager cacheManager = factory.getEntryCacheManager(); ManagedLedgerImpl ledger = (ManagedLedgerImpl) factory.open("ledger"); EntryCache cache1 = ledger.entryCache; for (int i = 0; i < 10; i++) { ledger.addEntry(("entry-" + i).getBytes()); } assertEquals(cache1.getSize(), 0); assertEquals(cacheManager.getSize(), 0); cacheManager.mlFactoryMBean.refreshStats(1, TimeUnit.SECONDS); assertEquals(cacheManager.mlFactoryMBean.getCacheMaxSize(), 7 * 10); assertEquals(cacheManager.mlFactoryMBean.getCacheUsedSize(), 0); assertEquals(cacheManager.mlFactoryMBean.getCacheHitsRate(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getCacheMissesRate(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getCacheHitsThroughput(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getNumberOfCacheEvictions(), 0); }
boolean hasSpaceInCache() { long currentSize = this.currentSize.get(); // Trigger a single eviction in background. While the eviction is running we stop inserting entries in the cache if (currentSize > evictionTriggerThreshold && evictionInProgress.compareAndSet(false, true)) { mlFactory.scheduledExecutor.execute(safeRun(() -> { // Trigger a new cache eviction cycle to bring the used memory below the cacheEvictionWatermark // percentage limit long sizeToEvict = currentSize - (long) (maxSize * cacheEvictionWatermak); long startTime = System.nanoTime(); log.info("Triggering cache eviction. total size: {} Mb -- Need to discard: {} Mb", currentSize / MB, sizeToEvict / MB); try { evictionPolicy.doEviction(Lists.newArrayList(caches.values()), sizeToEvict); long endTime = System.nanoTime(); double durationMs = TimeUnit.NANOSECONDS.toMicros(endTime - startTime) / 1000.0; log.info("Eviction completed. Removed {} Mb in {} ms", (currentSize - this.currentSize.get()) / MB, durationMs); } finally { mlFactoryMBean.recordCacheEviction(); evictionInProgress.set(false); } })); } return currentSize < maxSize; }
manager.mlFactoryMBean.recordCacheHits(entriesToReturn.size(), totalCachedSize); if (log.isDebugEnabled()) { log.debug("[{}] Ledger {} -- Found in cache entries: {}-{}", ml.getName(), ledgerId, firstEntry, manager.mlFactoryMBean.recordCacheMiss(entriesToReturn.size(), totalSize); ml.getMBean().addReadEntriesSample(entriesToReturn.size(), totalSize);
EntryImpl cachedEntry = EntryImpl.create(entry); entry.release(); manager.mlFactoryMBean.recordCacheHit(cachedEntry.getLength()); callback.readEntryComplete(cachedEntry, ctx); } else { EntryImpl returnEntry = EntryImpl.create(ledgerEntry); manager.mlFactoryMBean.recordCacheMiss(1, returnEntry.getLength()); ml.mbean.addReadEntriesSample(1, returnEntry.getLength()); callback.readEntryComplete(returnEntry, ctx);
private synchronized void refreshStats() { long now = System.nanoTime(); long period = now - lastStatTimestamp; mbean.refreshStats(period, TimeUnit.NANOSECONDS); ledgers.values().forEach(mlfuture -> { ManagedLedgerImpl ml = mlfuture.getNow(null); if (ml != null) { ml.mbean.refreshStats(period, TimeUnit.NANOSECONDS); } }); lastStatTimestamp = now; }
private ManagedLedgerFactoryImpl(BookKeeper bookKeeper, boolean isBookkeeperManaged, ZooKeeper zooKeeper, ManagedLedgerFactoryConfig config) throws Exception { scheduledExecutor = OrderedScheduler.newSchedulerBuilder() .numThreads(config.getNumManagedLedgerSchedulerThreads()) .name("bookkeeper-ml-scheduler") .build(); orderedExecutor = OrderedExecutor.newBuilder() .numThreads(config.getNumManagedLedgerWorkerThreads()) .name("bookkeeper-ml-workers") .build(); this.bookKeeper = bookKeeper; this.isBookkeeperManaged = isBookkeeperManaged; this.zookeeper = isBookkeeperManaged ? zooKeeper : null; this.store = new MetaStoreImplZookeeper(zooKeeper, orderedExecutor); this.config = config; this.mbean = new ManagedLedgerFactoryMBeanImpl(this); this.entryCacheManager = new EntryCacheManager(this); this.statsTask = scheduledExecutor.scheduleAtFixedRate(() -> refreshStats(), 0, StatsPeriodSeconds, TimeUnit.SECONDS); }
@Override public void asyncReadEntry(ReadHandle lh, long firstEntry, long lastEntry, boolean isSlowestReader, final ReadEntriesCallback callback, Object ctx) { lh.readAsync(firstEntry, lastEntry).whenComplete( (ledgerEntries, exception) -> { if (exception != null) { callback.readEntriesFailed(createManagedLedgerException(exception), ctx); return; } List<Entry> entries = Lists.newArrayList(); long totalSize = 0; try { for (LedgerEntry e : ledgerEntries) { // Insert the entries at the end of the list (they will be unsorted for now) EntryImpl entry = EntryImpl.create(e); entries.add(entry); totalSize += entry.getLength(); } } finally { ledgerEntries.close(); } mlFactoryMBean.recordCacheMiss(entries.size(), totalSize); ml.mbean.addReadEntriesSample(entries.size(), totalSize); callback.readEntriesComplete(entries, null); }); }
EntryImpl cachedEntry = EntryImpl.create(entry); entry.release(); manager.mlFactoryMBean.recordCacheHit(cachedEntry.getLength()); callback.readEntryComplete(cachedEntry, ctx); } else { manager.mlFactoryMBean.recordCacheMiss(1, returnEntry.getLength()); ml.mbean.addReadEntriesSample(1, returnEntry.getLength());
private synchronized void refreshStats() { long now = System.nanoTime(); long period = now - lastStatTimestamp; mbean.refreshStats(period, TimeUnit.NANOSECONDS); ledgers.values().forEach(mlfuture -> { ManagedLedgerImpl ml = mlfuture.getNow(null); if (ml != null) { ml.mbean.refreshStats(period, TimeUnit.NANOSECONDS); } }); lastStatTimestamp = now; }
public ManagedLedgerFactoryImpl(BookKeeper bookKeeper, ZooKeeper zooKeeper, ManagedLedgerFactoryConfig config) throws Exception { this.bookKeeper = bookKeeper; this.isBookkeeperManaged = false; this.zookeeper = null; this.store = new MetaStoreImplZookeeper(zooKeeper, orderedExecutor); this.config = config; this.mbean = new ManagedLedgerFactoryMBeanImpl(this); this.entryCacheManager = new EntryCacheManager(this); this.statsTask = executor.scheduleAtFixedRate(() -> refreshStats(), 0, StatsPeriodSeconds, TimeUnit.SECONDS); }
public void readComplete(int rc, LedgerHandle lh, Enumeration<LedgerEntry> seq, Object bkctx) { if (rc != BKException.Code.OK) { callback.readEntriesFailed(new ManagedLedgerException(BKException.create(rc)), ctx); return; } List<Entry> entries = Lists.newArrayList(); long totalSize = 0; while (seq.hasMoreElements()) { // Insert the entries at the end of the list (they will be unsorted for now) LedgerEntry ledgerEntry = seq.nextElement(); EntryImpl entry = EntryImpl.create(ledgerEntry); ledgerEntry.getEntryBuffer().release(); entries.add(entry); totalSize += entry.getLength(); } mlFactoryMBean.recordCacheMiss(entries.size(), totalSize); ml.mbean.addReadEntriesSample(entries.size(), totalSize); callback.readEntriesComplete(entries, null); } }, null);
cacheManager.mlFactoryMBean.refreshStats(1, TimeUnit.SECONDS); assertEquals(cacheManager.mlFactoryMBean.getCacheUsedSize(), 70); assertEquals(cacheManager.mlFactoryMBean.getCacheHitsRate(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getCacheMissesRate(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getCacheHitsThroughput(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getNumberOfCacheEvictions(), 0); cacheManager.mlFactoryMBean.refreshStats(1, TimeUnit.SECONDS); assertEquals(cacheManager.mlFactoryMBean.getCacheUsedSize(), 70); assertEquals(cacheManager.mlFactoryMBean.getCacheHitsRate(), 10.0); assertEquals(cacheManager.mlFactoryMBean.getCacheMissesRate(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getCacheHitsThroughput(), 70.0); assertEquals(cacheManager.mlFactoryMBean.getNumberOfCacheEvictions(), 0); cacheManager.mlFactoryMBean.refreshStats(1, TimeUnit.SECONDS); assertEquals(cacheManager.mlFactoryMBean.getCacheUsedSize(), 70); assertEquals(cacheManager.mlFactoryMBean.getCacheHitsRate(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getCacheMissesRate(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getCacheHitsThroughput(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getNumberOfCacheEvictions(), 0); cacheManager.mlFactoryMBean.refreshStats(1, TimeUnit.SECONDS); assertEquals(cacheManager.mlFactoryMBean.getCacheUsedSize(), 70); assertEquals(cacheManager.mlFactoryMBean.getCacheHitsRate(), 10.0); assertEquals(cacheManager.mlFactoryMBean.getCacheMissesRate(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getCacheHitsThroughput(), 70.0); assertEquals(cacheManager.mlFactoryMBean.getNumberOfCacheEvictions(), 0); cacheManager.mlFactoryMBean.refreshStats(1, TimeUnit.SECONDS);
EntryImpl cachedEntry = EntryImpl.create(entry); entry.release(); manager.mlFactoryMBean.recordCacheHit(cachedEntry.getLength()); callback.readEntryComplete(cachedEntry, ctx); } else { EntryImpl returnEntry = EntryImpl.create(ledgerEntry); manager.mlFactoryMBean.recordCacheMiss(1, returnEntry.getLength()); ml.mbean.addReadEntriesSample(1, returnEntry.getLength()); callback.readEntryComplete(returnEntry, ctx);
manager.mlFactoryMBean.recordCacheHits(entriesToReturn.size(), totalCachedSize); if (log.isDebugEnabled()) { log.debug("[{}] Ledger {} -- Found in cache entries: {}-{}", ml.getName(), ledgerId, firstEntry, manager.mlFactoryMBean.recordCacheMiss(entriesToReturn.size(), totalSize); ml.getMBean().addReadEntriesSample(entriesToReturn.size(), totalSize);
private synchronized void refreshStats() { long now = System.nanoTime(); long period = now - lastStatTimestamp; mbean.refreshStats(period, TimeUnit.NANOSECONDS); ledgers.values().forEach(mlfuture -> { ManagedLedgerImpl ml = mlfuture.getNow(null); if (ml != null) { ml.mbean.refreshStats(period, TimeUnit.NANOSECONDS); } }); lastStatTimestamp = now; }
public ManagedLedgerFactoryImpl(ClientConfiguration bkClientConfiguration, ManagedLedgerFactoryConfig config) throws Exception { final CountDownLatch counter = new CountDownLatch(1); final String zookeeperQuorum = checkNotNull(bkClientConfiguration.getZkServers()); zookeeper = new ZooKeeper(zookeeperQuorum, bkClientConfiguration.getZkTimeout(), event -> { if (event.getState().equals(Watcher.Event.KeeperState.SyncConnected)) { log.info("Connected to zookeeper"); counter.countDown(); } else { log.error("Error connecting to zookeeper {}", event); } }); if (!counter.await(bkClientConfiguration.getZkTimeout(), TimeUnit.MILLISECONDS) || zookeeper.getState() != States.CONNECTED) { throw new ManagedLedgerException("Error connecting to ZooKeeper at '" + zookeeperQuorum + "'"); } this.bookKeeper = new BookKeeper(bkClientConfiguration, zookeeper); this.isBookkeeperManaged = true; this.store = new MetaStoreImplZookeeper(zookeeper, orderedExecutor); this.config = config; this.mbean = new ManagedLedgerFactoryMBeanImpl(this); this.entryCacheManager = new EntryCacheManager(this); this.statsTask = executor.scheduleAtFixedRate(() -> refreshStats(), 0, StatsPeriodSeconds, TimeUnit.SECONDS); }
@Override public void asyncReadEntry(ReadHandle lh, long firstEntry, long lastEntry, boolean isSlowestReader, final ReadEntriesCallback callback, Object ctx) { lh.readAsync(firstEntry, lastEntry).whenComplete( (ledgerEntries, exception) -> { if (exception != null) { callback.readEntriesFailed(createManagedLedgerException(exception), ctx); return; } List<Entry> entries = Lists.newArrayList(); long totalSize = 0; try { for (LedgerEntry e : ledgerEntries) { // Insert the entries at the end of the list (they will be unsorted for now) EntryImpl entry = EntryImpl.create(e); entries.add(entry); totalSize += entry.getLength(); } } finally { ledgerEntries.close(); } mlFactoryMBean.recordCacheMiss(entries.size(), totalSize); ml.mbean.addReadEntriesSample(entries.size(), totalSize); callback.readEntriesComplete(entries, null); }); }
boolean hasSpaceInCache() { long currentSize = this.currentSize.get(); // Trigger a single eviction in background. While the eviction is running we stop inserting entries in the cache if (currentSize > evictionTriggerThreshold && evictionInProgress.compareAndSet(false, true)) { mlFactory.executor.execute(safeRun(() -> { // Trigger a new cache eviction cycle to bring the used memory below the cacheEvictionWatermark // percentage limit long sizeToEvict = currentSize - (long) (maxSize * cacheEvictionWatermak); long startTime = System.nanoTime(); log.info("Triggering cache eviction. total size: {} Mb -- Need to discard: {} Mb", currentSize / MB, sizeToEvict / MB); try { evictionPolicy.doEviction(Lists.newArrayList(caches.values()), sizeToEvict); long endTime = System.nanoTime(); double durationMs = TimeUnit.NANOSECONDS.toMicros(endTime - startTime) / 1000.0; log.info("Eviction completed. Removed {} Mb in {} ms", (currentSize - this.currentSize.get()) / MB, durationMs); } finally { mlFactoryMBean.recordCacheEviction(); evictionInProgress.set(false); } })); } return currentSize < maxSize; }
@Test void cacheDisabled() throws Exception { ManagedLedgerFactoryConfig config = new ManagedLedgerFactoryConfig(); config.setMaxCacheSize(0); config.setCacheEvictionWatermark(0.8); factory = new ManagedLedgerFactoryImpl(bkc, bkc.getZkHandle(), config); EntryCacheManager cacheManager = factory.getEntryCacheManager(); EntryCache cache1 = cacheManager.getEntryCache(ml1); EntryCache cache2 = cacheManager.getEntryCache(ml2); assertTrue(cache1 instanceof EntryCacheManager.EntryCacheDisabled); assertTrue(cache2 instanceof EntryCacheManager.EntryCacheDisabled); cache1.insert(EntryImpl.create(1, 1, new byte[4])); cache1.insert(EntryImpl.create(1, 0, new byte[3])); assertEquals(cache1.getSize(), 0); assertEquals(cacheManager.getSize(), 0); cacheManager.mlFactoryMBean.refreshStats(1, TimeUnit.SECONDS); assertEquals(cacheManager.mlFactoryMBean.getCacheMaxSize(), 0); assertEquals(cacheManager.mlFactoryMBean.getCacheUsedSize(), 0); assertEquals(cacheManager.mlFactoryMBean.getCacheHitsRate(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getCacheMissesRate(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getCacheHitsThroughput(), 0.0); assertEquals(cacheManager.mlFactoryMBean.getNumberOfCacheEvictions(), 0); cache2.insert(EntryImpl.create(2, 0, new byte[1])); cache2.insert(EntryImpl.create(2, 1, new byte[1])); cache2.insert(EntryImpl.create(2, 2, new byte[1])); assertEquals(cache2.getSize(), 0); assertEquals(cacheManager.getSize(), 0); }
manager.mlFactoryMBean.recordCacheHits(entriesToReturn.size(), totalCachedSize); if (log.isDebugEnabled()) { log.debug("[{}] Ledger {} -- Found in cache entries: {}-{}", ml.getName(), ledgerId, firstEntry, manager.mlFactoryMBean.recordCacheMiss(entriesToReturn.size(), totalSize); ml.getMBean().addReadEntriesSample(entriesToReturn.size(), totalSize);