public PageCache getPageCache(final long pageId) { try { boolean needToRead = false; PageCache cache = null; synchronized (softCache) { if (pageId > pagingStore.getCurrentWritingPage()) { return null; } cache = softCache.get(pageId); if (cache == null) { if (!pagingStore.checkPageFileExists((int) pageId)) { return null; } cache = createPageCache(pageId); needToRead = true; // anyone reading from this cache will have to wait reading to finish first // we also want only one thread reading this cache cache.lock(); if (isTrace) { HornetQServerLogger.LOGGER.trace( "adding " + pageId + " into cursor = " + this.pagingStore.getAddress()); } softCache.put(pageId, cache); } } // Reading is done outside of the synchronized block, however // the page stays locked until the entire reading is finished if (needToRead) { Page page = null; try { page = pagingStore.createPage((int) pageId); storageManager.beforePageRead(); page.open(); List<PagedMessage> pgdMessages = page.read(storageManager); cache.setMessages(pgdMessages.toArray(new PagedMessage[pgdMessages.size()])); } finally { try { if (page != null) { page.close(); } } catch (Throwable ignored) { } storageManager.afterPageRead(); cache.unlock(); } } return cache; } catch (Exception e) { throw new RuntimeException( "Couldn't complete paging due to an IO Exception on Paging - " + e.getMessage(), e); } }
@Test public void testEvictOldestElement() { Value one = new Value(new byte[100]); Value two = new Value(new byte[100]); Value three = new Value(new byte[100]); SoftValueHashMap<Integer, Value> softCache = new SoftValueHashMap<Integer, Value>(2); softCache.put(3, three); softCache.put(2, two); softCache.put(1, one); assertNull(softCache.get(3)); assertEquals(two, softCache.get(2)); assertEquals(one, softCache.get(1)); }
@Test public void testEvictions() { forceGC(); long maxMemory = Runtime.getRuntime().maxMemory() - Runtime.getRuntime().freeMemory(); // each buffer will be 1/10th of the maxMemory int bufferSize = (int) (maxMemory / 100); SoftValueHashMap<Long, Value> softCache = new SoftValueHashMap<Long, Value>(100); final int MAX_ELEMENTS = 1000; for (long i = 0; i < MAX_ELEMENTS; i++) { softCache.put(i, new Value(new byte[bufferSize])); } assertTrue(softCache.size() < MAX_ELEMENTS); System.out.println("SoftCache.size " + softCache.size()); System.out.println("Soft cache has " + softCache.size() + " elements"); }
@Test public void testEvictionsLeastUsed() { forceGC(); SoftValueHashMap<Long, Value> softCache = new SoftValueHashMap<Long, Value>(200); for (long i = 0; i < 100; i++) { Value v = new Value(new byte[1]); v.setLive(true); softCache.put(i, v); } for (long i = 100; i < 200; i++) { Value v = new Value(new byte[1]); softCache.put(i, v); } assertNotNull(softCache.get(100l)); softCache.put(300l, new Value(new byte[1])); // these are live, so they shouldn't go for (long i = 0; i < 100; i++) { assertNotNull(softCache.get(i)); } // this was accessed, so it shouldn't go assertNotNull(softCache.get(100l)); // this is the next one, so it should go assertNull(softCache.get(101l)); System.out.println("SoftCache.size " + softCache.size()); System.out.println("Soft cache has " + softCache.size() + " elements"); }
public void printDebug() { System.out.println("Debug information for PageCursorProviderImpl:"); for (PageCache cache : softCache.values()) { System.out.println("Cache " + cache); } }
public void cleanup() { ArrayList<Page> depagedPages = new ArrayList<Page>(); while (true) { if (pagingStore.lock(100)) { break; } if (!pagingStore.isStarted()) return; } synchronized (this) { try { if (!pagingStore.isStarted()) { return; } if (pagingStore.getNumberOfPages() == 0) { return; } if (log.isDebugEnabled()) { log.debug("Asserting cleanup for address " + this.pagingStore.getAddress()); } ArrayList<PageSubscription> cursorList = new ArrayList<PageSubscription>(); cursorList.addAll(activeCursors.values()); long minPage = checkMinPage(cursorList); if (minPage == pagingStore.getCurrentWritingPage() && pagingStore.getCurrentPage().getNumberOfMessages() > 0) { boolean complete = true; for (PageSubscription cursor : cursorList) { if (!cursor.isComplete(minPage)) { if (log.isDebugEnabled()) { log.debug("Cursor " + cursor + " was considered incomplete at page " + minPage); } complete = false; break; } else { if (log.isDebugEnabled()) { log.debug("Cursor " + cursor + "was considered **complete** at page " + minPage); } } } if (!pagingStore.isStarted()) { return; } if (complete) { if (log.isDebugEnabled()) { log.debug( "Address " + pagingStore.getAddress() + " is leaving page mode as all messages are consumed and acknowledged from the page store"); } pagingStore.forceAnotherPage(); Page currentPage = pagingStore.getCurrentPage(); storePositions(cursorList, currentPage); pagingStore.stopPaging(); // This has to be called after we stopped paging for (PageSubscription cursor : cursorList) { cursor.scheduleCleanupCheck(); } } } for (long i = pagingStore.getFirstPage(); i < minPage; i++) { Page page = pagingStore.depage(); if (page == null) { break; } depagedPages.add(page); } if (pagingStore.getNumberOfPages() == 0 || pagingStore.getNumberOfPages() == 1 && pagingStore.getCurrentPage().getNumberOfMessages() == 0) { pagingStore.stopPaging(); } else { if (log.isTraceEnabled()) { log.trace( "Couldn't cleanup page on address " + this.pagingStore.getAddress() + " as numberOfPages == " + pagingStore.getNumberOfPages() + " and currentPage.numberOfMessages = " + pagingStore.getCurrentPage().getNumberOfMessages()); } } } catch (Exception ex) { log.warn("Couldn't complete cleanup on paging", ex); return; } finally { pagingStore.unlock(); } } try { for (Page depagedPage : depagedPages) { PageCache cache; PagedMessage[] pgdMessages; synchronized (softCache) { cache = softCache.get((long) depagedPage.getPageId()); } if (isTrace) { log.trace("Removing page " + depagedPage.getPageId() + " from page-cache"); } if (cache == null) { // The page is not on cache any more // We need to read the page-file before deleting it // to make sure we remove any large-messages pending storageManager.beforePageRead(); List<PagedMessage> pgdMessagesList = null; try { depagedPage.open(); pgdMessagesList = depagedPage.read(storageManager); } finally { try { depagedPage.close(); } catch (Exception e) { } storageManager.afterPageRead(); } depagedPage.close(); pgdMessages = pgdMessagesList.toArray(new PagedMessage[pgdMessagesList.size()]); } else { pgdMessages = cache.getMessages(); } depagedPage.delete(pgdMessages); synchronized (softCache) { softCache.remove((long) depagedPage.getPageId()); } } } catch (Exception ex) { log.warn("Couldn't complete cleanup on paging", ex); return; } }
public int getCacheSize() { synchronized (softCache) { return softCache.size(); } }
public void setCacheMaxSize(final int size) { softCache.setMaxElements(size); }
public int getCacheMaxSize() { return softCache.getMaxEelements(); }
public void addPageCache(PageCache cache) { synchronized (softCache) { softCache.put(cache.getPageId(), cache); } }
public void cleanup() { ArrayList<Page> depagedPages = new ArrayList<Page>(); while (true) { if (pagingStore.lock(100)) { break; } if (!pagingStore.isStarted()) return; } synchronized (this) { try { if (!pagingStore.isStarted()) { return; } if (pagingStore.getNumberOfPages() == 0) { return; } if (HornetQServerLogger.LOGGER.isDebugEnabled()) { HornetQServerLogger.LOGGER.debug( "Asserting cleanup for address " + this.pagingStore.getAddress()); } ArrayList<PageSubscription> cursorList = cloneSubscriptions(); long minPage = checkMinPage(cursorList); // if the current page is being written... // on that case we need to move to verify it in a different way if (minPage == pagingStore.getCurrentWritingPage() && pagingStore.getCurrentPage().getNumberOfMessages() > 0) { boolean complete = true; for (PageSubscription cursor : cursorList) { if (!cursor.isComplete(minPage)) { if (HornetQServerLogger.LOGGER.isDebugEnabled()) { HornetQServerLogger.LOGGER.debug( "Cursor " + cursor + " was considered incomplete at page " + minPage); } complete = false; break; } else { if (HornetQServerLogger.LOGGER.isDebugEnabled()) { HornetQServerLogger.LOGGER.debug( "Cursor " + cursor + "was considered **complete** at page " + minPage); } } } if (!pagingStore.isStarted()) { return; } // All the pages on the cursor are complete.. so we will cleanup everything and store a // bookmark if (complete) { if (HornetQServerLogger.LOGGER.isDebugEnabled()) { HornetQServerLogger.LOGGER.debug( "Address " + pagingStore.getAddress() + " is leaving page mode as all messages are consumed and acknowledged from the page store"); } pagingStore.forceAnotherPage(); Page currentPage = pagingStore.getCurrentPage(); storeBookmark(cursorList, currentPage); pagingStore.stopPaging(); } } for (long i = pagingStore.getFirstPage(); i < minPage; i++) { Page page = pagingStore.depage(); if (page == null) { break; } depagedPages.add(page); } if (pagingStore.getNumberOfPages() == 0 || pagingStore.getNumberOfPages() == 1 && pagingStore.getCurrentPage().getNumberOfMessages() == 0) { pagingStore.stopPaging(); } else { if (HornetQServerLogger.LOGGER.isTraceEnabled()) { HornetQServerLogger.LOGGER.trace( "Couldn't cleanup page on address " + this.pagingStore.getAddress() + " as numberOfPages == " + pagingStore.getNumberOfPages() + " and currentPage.numberOfMessages = " + pagingStore.getCurrentPage().getNumberOfMessages()); } } } catch (Exception ex) { HornetQServerLogger.LOGGER.problemCleaningPageAddress(ex, pagingStore.getAddress()); return; } finally { pagingStore.unlock(); } } try { for (Page depagedPage : depagedPages) { PageCache cache; PagedMessage[] pgdMessages; synchronized (softCache) { cache = softCache.get((long) depagedPage.getPageId()); } if (isTrace) { HornetQServerLogger.LOGGER.trace( "Removing page " + depagedPage.getPageId() + " from page-cache"); } if (cache == null) { // The page is not on cache any more // We need to read the page-file before deleting it // to make sure we remove any large-messages pending storageManager.beforePageRead(); List<PagedMessage> pgdMessagesList = null; try { depagedPage.open(); pgdMessagesList = depagedPage.read(storageManager); } finally { try { depagedPage.close(); } catch (Exception e) { } storageManager.afterPageRead(); } depagedPage.close(); pgdMessages = pgdMessagesList.toArray(new PagedMessage[pgdMessagesList.size()]); } else { pgdMessages = cache.getMessages(); } depagedPage.delete(pgdMessages); onDeletePage(depagedPage); synchronized (softCache) { softCache.remove((long) depagedPage.getPageId()); } } } catch (Exception ex) { HornetQServerLogger.LOGGER.problemCleaningPageAddress(ex, pagingStore.getAddress()); return; } }
public void clearCache() { synchronized (softCache) { softCache.clear(); } }