package org.warp.jcwdb; import java.io.IOException; import java.lang.ref.WeakReference; import java.nio.channels.ClosedChannelException; import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry; public class Cleaner { public static final boolean DISABLE_CLEANER = false; public static final boolean ENABLE_CLEANER_LOGGING = false; private static final double MAXIMUM_SLEEP_INTERVAL = 8d * 1000d; // 8 seconds private static final double MINIMUM_SLEEP_INTERVAL = 1d * 1000d; // 1 second private static final double NORMAL_REMOVED_ITEMS = 2500l; private static final double REMOVED_ITEMS_RATIO = 2.5d; // 250% private final Cleanable[] objectsToClean; private final Thread cleanerThread; private int sleepInterval = (int) MINIMUM_SLEEP_INTERVAL; private volatile boolean stopRequest = false; public Cleaner(Cleanable... objectsToClean) { this.objectsToClean = objectsToClean; this.cleanerThread = new Thread(new CleanLoop()); this.cleanerThread.setName("Cleaner thread"); this.cleanerThread.setDaemon(true); } public void start() { if (!DISABLE_CLEANER) { this.cleanerThread.start(); } } /** * Clean * @return number of removed items */ private long clean() { long cleanedItems = 0; for (Cleanable cleanable : objectsToClean) { cleanedItems += cleanable.clean(); } //System.gc(); return cleanedItems; } public void stop() { if (cleanerThread != null) { stopRequest = true; while (cleanerThread.isAlive()) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } private class CleanLoop implements Runnable { @Override public void run() { while(!stopRequest) { try { if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] Waiting " + sleepInterval + "ms."); sleepFor(sleepInterval); final long time1 = System.currentTimeMillis(); final double removedItems = clean(); final long time2 = System.currentTimeMillis(); if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] CLEAN_TIME " + (time2 - time1)); double suggestedExecutionTimeByItemsCalculations = (sleepInterval + MAXIMUM_SLEEP_INTERVAL) / 2; if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] REMOVED_ITEMS: " + removedItems); if (removedItems > 0) { final double removedItemsRatio = removedItems / NORMAL_REMOVED_ITEMS; if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] REMOVED_ITEMS_RATIO: " + removedItemsRatio); if (removedItemsRatio < 1d / REMOVED_ITEMS_RATIO || removedItemsRatio >= REMOVED_ITEMS_RATIO) { suggestedExecutionTimeByItemsCalculations = sleepInterval / removedItemsRatio; } } if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] Items: SUGGESTING SLEEP_INTERVAL FROM " + sleepInterval + "ms TO " + suggestedExecutionTimeByItemsCalculations + "ms"); double newSleepInterval = suggestedExecutionTimeByItemsCalculations; if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] Total: SUGGESTING SLEEP_INTERVAL FROM " + sleepInterval + "ms TO " + newSleepInterval + "ms"); if (newSleepInterval > MAXIMUM_SLEEP_INTERVAL) { sleepInterval = (int) MAXIMUM_SLEEP_INTERVAL; } else if (newSleepInterval < MINIMUM_SLEEP_INTERVAL) { sleepInterval = (int) MINIMUM_SLEEP_INTERVAL; } else { if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] CHANGED SLEEP_INTERVAL FROM " + sleepInterval + "ms TO " + newSleepInterval + "ms"); sleepInterval = (int) newSleepInterval; } if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] Cleaned " + removedItems + " items."); }catch (InterruptedException e) { } } } private void sleepFor(int sleepInterval) throws InterruptedException { int lastI = (int) Math.ceil(((double) sleepInterval) / 1000d); for (int i = 0; i < lastI; i++) { if (stopRequest) { return; } if (i == lastI) { Thread.sleep(sleepInterval % 1000); } else { Thread.sleep(lastI); } Thread.sleep(sleepInterval); } } } }