diff --git a/htroot/PerformanceMemory_p.html b/htroot/PerformanceMemory_p.html index e0fac875b..bc7b2cfb6 100644 --- a/htroot/PerformanceMemory_p.html +++ b/htroot/PerformanceMemory_p.html @@ -184,19 +184,51 @@ - + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeAmountSizeHitMissInsertDelete
DNSCache#[namecache.hit]##[namecacheHit.size]#
DNSCache#[namecacheMiss.size]#
DNSNoCache #[namecache.noCache]#
HashBlacklistedCache #[blacklistcache.size]#
Search Event Cache#[searchevent.size]##[searchevent.hit]##[searchevent.miss]##[searchevent.insert]##[searchevent.delete]#
diff --git a/htroot/PerformanceMemory_p.java b/htroot/PerformanceMemory_p.java index 0b874e7a7..49c01b95a 100644 --- a/htroot/PerformanceMemory_p.java +++ b/htroot/PerformanceMemory_p.java @@ -38,6 +38,7 @@ import net.yacy.kelondro.util.FileUtils; import net.yacy.kelondro.util.Formatter; import net.yacy.kelondro.util.MemoryControl; +import de.anomic.search.SearchEventCache; import de.anomic.search.Switchboard; import de.anomic.server.serverObjects; import de.anomic.server.serverSwitch; @@ -187,12 +188,15 @@ public class PerformanceMemory_p { prop.putNum("objectMissCacheTotalMem", totalmissmem / (1024 * 1024d)); // other caching structures - long amount = Domains.nameCacheHitSize(); - prop.putNum("namecache.hit", amount); - amount = Domains.nameCacheNoCachingListSize(); - prop.putNum("namecache.noCache", amount); - amount = Switchboard.urlBlacklist.blacklistCacheSize(); - prop.putNum("blacklistcache.size", amount); + prop.putNum("namecacheHit.size", Domains.nameCacheHitSize()); + prop.putNum("namecacheMiss.size", Domains.nameCacheMissSize()); + prop.putNum("namecache.noCache", Domains.nameCacheNoCachingListSize()); + prop.putNum("blacklistcache.size", Switchboard.urlBlacklist.blacklistCacheSize()); + prop.putNum("searchevent.size", SearchEventCache.size()); + prop.putNum("searchevent.hit", SearchEventCache.cacheHit); + prop.putNum("searchevent.miss", SearchEventCache.cacheMiss); + prop.putNum("searchevent.insert", SearchEventCache.cacheInsert); + prop.putNum("searchevent.delete", SearchEventCache.cacheDelete); // return rewrite values for templates return prop; } diff --git a/source/de/anomic/search/SearchEventCache.java b/source/de/anomic/search/SearchEventCache.java index dbd51edda..3effceecb 100644 --- a/source/de/anomic/search/SearchEventCache.java +++ b/source/de/anomic/search/SearchEventCache.java @@ -26,10 +26,14 @@ package de.anomic.search; -import java.util.Iterator; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.TreeMap; -import java.util.concurrent.ConcurrentHashMap; +import net.yacy.cora.storage.ARC; +import net.yacy.cora.storage.ConcurrentARC; +import net.yacy.kelondro.util.MemoryControl; import net.yacy.repository.LoaderDispatcher; import de.anomic.crawler.ResultURLs; @@ -37,33 +41,43 @@ import de.anomic.yacy.yacySeedDB; public class SearchEventCache { - private static ConcurrentHashMap lastEvents = new ConcurrentHashMap(); // a cache for objects from this class: re-use old search requests - public static final long eventLifetime = 60000; // the time an event will stay in the cache, 1 Minute - + private static ARC lastEvents = new ConcurrentARC(1000, Runtime.getRuntime().availableProcessors() * 4); // a cache for objects from this class: re-use old search requests + public static final long eventLifetime = 600000; // the time an event will stay in the cache, 10 Minutes + public static final long memlimit = 100 * 1024 * 1024; // 100 MB public static String lastEventID = ""; + public static long cacheInsert = 0, cacheHit = 0, cacheMiss = 0, cacheDelete = 0; + + public static int size() { + return lastEvents.size(); + } public static void put(String eventID, SearchEvent event) { lastEventID = eventID; - lastEvents.put(eventID, event); + SearchEvent oldEvent = lastEvents.put(eventID, event); + if (oldEvent == null) cacheInsert++; } public static void cleanupEvents(final boolean all) { // remove old events in the event cache - final Iterator i = lastEvents.values().iterator(); - SearchEvent event; - while (i.hasNext()) { - event = i.next(); - if (all || event.getEventTime() + eventLifetime < System.currentTimeMillis()) { - event.cleanup(); - - // remove the event - i.remove(); + List delete = new ArrayList(); + // the less memory is there, the less time is acceptable for elements in the cache + long memx = MemoryControl.available(); + long acceptTime = memx > memlimit ? eventLifetime : memx * eventLifetime / memlimit; + for (Map.Entry event: lastEvents) { + if (all || event.getValue().getEventTime() + acceptTime < System.currentTimeMillis()) { + event.getValue().cleanup(); + delete.add(event.getKey()); } } + // remove the events + cacheDelete += delete.size(); + for (String k: delete) lastEvents.remove(k); } public static SearchEvent getEvent(final String eventID) { - return lastEvents.get(eventID); + SearchEvent event = lastEvents.get(eventID); + if (event == null) cacheMiss++; else cacheHit++; + return event; } public static SearchEvent getEvent( @@ -76,11 +90,13 @@ public class SearchEventCache { String id = query.id(false); SearchEvent event = SearchEventCache.lastEvents.get(id); + if (event == null) cacheMiss++; else cacheHit++; if (Switchboard.getSwitchboard() != null && !Switchboard.getSwitchboard().crawlQueues.noticeURL.isEmpty() && event != null && System.currentTimeMillis() - event.getEventTime() > 60000) { // if a local crawl is ongoing, don't use the result from the cache to use possibly more results that come from the current crawl // to prevent that this happens during a person switches between the different result pages, a re-search happens no more than // once a minute SearchEventCache.lastEvents.remove(id); + cacheDelete++; event = null; } else { if (event != null) {