2018-11-27 17:47:19 +01:00
package org.warp.jcwdb ;
2018-12-06 12:30:04 +01:00
import java.io.IOException ;
2018-11-27 17:47:19 +01:00
import java.lang.ref.WeakReference ;
2018-12-06 12:30:04 +01:00
import java.nio.channels.ClosedChannelException ;
2018-11-27 17:47:19 +01:00
import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry ;
public class Cleaner {
2019-01-06 00:31:52 +01:00
public static final boolean DISABLE_CLEANER = false ;
public static final boolean ENABLE_CLEANER_LOGGING = false ;
2018-12-19 12:19:03 +01:00
private static final double MAXIMUM_SLEEP_INTERVAL = 8d * 1000d ; // 8 seconds
2018-12-05 02:39:41 +01:00
private static final double MINIMUM_SLEEP_INTERVAL = 1d * 1000d ; // 1 second
2018-12-21 10:03:30 +01:00
private static final double NORMAL_REMOVED_ITEMS = 2500l ;
2018-12-05 02:39:41 +01:00
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 ;
2018-12-06 12:30:04 +01:00
private volatile boolean stopRequest = false ;
2018-11-27 17:47:19 +01:00
public Cleaner ( Cleanable . . . objectsToClean ) {
this . objectsToClean = objectsToClean ;
2018-12-05 02:39:41 +01:00
this . cleanerThread = new Thread ( new CleanLoop ( ) ) ;
this . cleanerThread . setName ( " Cleaner thread " ) ;
this . cleanerThread . setDaemon ( true ) ;
2018-11-27 17:47:19 +01:00
}
public void start ( ) {
2019-01-06 00:31:52 +01:00
if ( ! DISABLE_CLEANER ) {
this . cleanerThread . start ( ) ;
}
2018-11-27 17:47:19 +01:00
}
/ * *
* Clean
* @return number of removed items
* /
private long clean ( ) {
long cleanedItems = 0 ;
for ( Cleanable cleanable : objectsToClean ) {
cleanedItems + = cleanable . clean ( ) ;
}
2019-01-06 00:31:52 +01:00
//System.gc();
2018-11-27 17:47:19 +01:00
return cleanedItems ;
}
public void stop ( ) {
if ( cleanerThread ! = null ) {
2018-12-06 12:30:04 +01:00
stopRequest = true ;
2018-12-05 02:39:41 +01:00
while ( cleanerThread . isAlive ( ) ) {
try {
Thread . sleep ( 100 ) ;
} catch ( InterruptedException e ) {
e . printStackTrace ( ) ;
}
}
2018-11-27 17:47:19 +01:00
}
}
private class CleanLoop implements Runnable {
@Override
public void run ( ) {
2018-12-06 12:30:04 +01:00
while ( ! stopRequest ) {
2018-11-27 17:47:19 +01:00
try {
2019-01-06 00:31:52 +01:00
if ( ENABLE_CLEANER_LOGGING ) System . out . println ( " [CLEANER] Waiting " + sleepInterval + " ms. " ) ;
2018-12-11 23:00:51 +01:00
sleepFor ( sleepInterval ) ;
2018-12-19 12:19:03 +01:00
final long time1 = System . currentTimeMillis ( ) ;
2018-12-05 02:39:41 +01:00
final double removedItems = clean ( ) ;
2018-12-19 12:19:03 +01:00
final long time2 = System . currentTimeMillis ( ) ;
2019-01-06 00:31:52 +01:00
if ( ENABLE_CLEANER_LOGGING ) System . out . println ( " [CLEANER] CLEAN_TIME " + ( time2 - time1 ) ) ;
2018-12-11 23:00:51 +01:00
double suggestedExecutionTimeByItemsCalculations = ( sleepInterval + MAXIMUM_SLEEP_INTERVAL ) / 2 ;
2018-12-05 02:39:41 +01:00
2019-01-06 00:31:52 +01:00
if ( ENABLE_CLEANER_LOGGING ) System . out . println ( " [CLEANER] REMOVED_ITEMS: " + removedItems ) ;
2018-12-05 02:39:41 +01:00
if ( removedItems > 0 ) {
final double removedItemsRatio = removedItems / NORMAL_REMOVED_ITEMS ;
2019-01-06 00:31:52 +01:00
if ( ENABLE_CLEANER_LOGGING ) System . out . println ( " [CLEANER] REMOVED_ITEMS_RATIO: " + removedItemsRatio ) ;
2018-12-21 10:03:30 +01:00
if ( removedItemsRatio < 1d / REMOVED_ITEMS_RATIO | | removedItemsRatio > = REMOVED_ITEMS_RATIO ) {
2018-12-05 02:39:41 +01:00
suggestedExecutionTimeByItemsCalculations = sleepInterval / removedItemsRatio ;
}
}
2019-01-06 00:31:52 +01:00
if ( ENABLE_CLEANER_LOGGING ) System . out . println ( " [CLEANER] Items: SUGGESTING SLEEP_INTERVAL FROM " + sleepInterval + " ms TO " + suggestedExecutionTimeByItemsCalculations + " ms " ) ;
2018-12-05 02:39:41 +01:00
double newSleepInterval = suggestedExecutionTimeByItemsCalculations ;
2019-01-06 00:31:52 +01:00
if ( ENABLE_CLEANER_LOGGING ) System . out . println ( " [CLEANER] Total: SUGGESTING SLEEP_INTERVAL FROM " + sleepInterval + " ms TO " + newSleepInterval + " ms " ) ;
2018-12-05 02:39:41 +01:00
if ( newSleepInterval > MAXIMUM_SLEEP_INTERVAL ) {
sleepInterval = ( int ) MAXIMUM_SLEEP_INTERVAL ;
} else if ( newSleepInterval < MINIMUM_SLEEP_INTERVAL ) {
sleepInterval = ( int ) MINIMUM_SLEEP_INTERVAL ;
} else {
2019-01-06 00:31:52 +01:00
if ( ENABLE_CLEANER_LOGGING ) System . out . println ( " [CLEANER] CHANGED SLEEP_INTERVAL FROM " + sleepInterval + " ms TO " + newSleepInterval + " ms " ) ;
2018-12-05 02:39:41 +01:00
sleepInterval = ( int ) newSleepInterval ;
}
2019-01-06 00:31:52 +01:00
if ( ENABLE_CLEANER_LOGGING ) System . out . println ( " [CLEANER] Cleaned " + removedItems + " items. " ) ;
2018-12-06 12:30:04 +01:00
} catch ( InterruptedException e ) {
2018-11-27 17:47:19 +01:00
}
}
}
2018-12-11 23:00:51 +01:00
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 ) ;
}
}
2018-11-27 17:47:19 +01:00
}
}