AdaptiveCachingCoordinator.java
Home
/
aplcache /
src /
main /
java /
br /
ufrgs /
inf /
prosoft /
adaptivecaching /
AdaptiveCachingCoordinator.java
package br.ufrgs.inf.prosoft.adaptivecaching;
import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.FlowchartWorkFlow;
import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.model.MethodEntry;
import br.ufrgs.inf.prosoft.adaptivecaching.cache.CacheMonitor;
import br.ufrgs.inf.prosoft.adaptivecaching.cache.CacheMonitorFactory;
import br.ufrgs.inf.prosoft.adaptivecaching.cachemanager.cacher.AdaptiveMethodCacher;
import br.ufrgs.inf.prosoft.adaptivecaching.cachemanager.util.threads.NamedThreads;
import br.ufrgs.inf.prosoft.adaptivecaching.configuration.annotation.AdaptiveCaching;
import br.ufrgs.inf.prosoft.tigris.configuration.types.Modelling;
import br.ufrgs.inf.prosoft.tigris.monitoring.aspects.CustomMonitoring;
import br.ufrgs.inf.prosoft.tigris.monitoring.metadata.Key;
import br.ufrgs.inf.prosoft.tigris.monitoring.metadata.LogTrace;
import br.ufrgs.inf.prosoft.tigris.monitoring.storage.Repository;
import br.ufrgs.inf.prosoft.tigris.monitoring.usersession.UserGetter;
import br.ufrgs.inf.prosoft.tigris.monitoring.usersession.UserGetterFactory;
import br.ufrgs.inf.prosoft.utils.ConfigurationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class AdaptiveCachingCoordinator implements CustomMonitoring {
//used in case the method info is required
private Set<MethodEntry> cacheableMethods = new ConcurrentSkipListSet<>();
//used in case the method info is not required
private Set<Object> cacheableMethodKeys = new ConcurrentSkipListSet<>();
private boolean enabled = true;
private final ScheduledExecutorService analyzerExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreads(
"adaptivecaching-analyzer",
"identifying cacheable methods"
));
Logger logger = LoggerFactory.getLogger(AdaptiveCachingCoordinator.class);
private AdaptiveMethodCacher cacher;
private CacheMonitor cacheMonitor;
//adaptive caching configurations
private AdaptiveCaching cachingConfig;
private Properties properties;
private UserGetter userGetter;
private Repository repository;
public boolean isCacheable(Key key){
return cacheableMethodKeys.contains(key);
}
private Properties getPropertiesFile() throws IOException {
Properties properties = new Properties();
properties.load(getClass().getClassLoader().getResourceAsStream("adaptivecaching.properties"));
return properties;
}
public boolean isEnabled() {
return enabled;
}
public void turnoff() {
enabled = false;
}
public Object getFromCache(Key key) throws Throwable {
return this.cacher.getFromCache(key);
}
public void putInCache(Key key, Object value) throws Throwable {
this.cacher.putInCache(key, value);
}
@Override
public void run() {
if(!enabled) {
logger.info("Analyzer disabled, waiting until next run to check again...");
return;
}
List all = repository.findAll();
Set<MethodEntry> process = analyzeAndReturn(all);
//todo maybe clean the cache here?
cacheableMethods = process;
cacheableMethodKeys = process.stream().parallel().map(MethodEntry::getMethodInfoKey).collect(Collectors.toSet());
String methods = "";
for (MethodEntry me : process) methods = methods.concat(me.getMethodInfo().getSignature() + ",");
//TODO maybe after the analysis end, new data would be already registered, which should not be deleted
if (cachingConfig.modelling().equals(Modelling.FULLEXPLORATION)) {
repository.removeAll();
logger.info("Old monitoring data deleted.");
}
if (cachingConfig.analyzeOnce())
enabled = false;
logger.info("Start caching...");
}
/**
* Analyze and return set.
*
* @param logList the log list
* @return the set
*/
private Set<MethodEntry> analyzeAndReturn(List<LogTrace> logList) {
logger.info("Starting the analysis of cacheable methods from logs: " + logList.size() + " loaded.");
FlowchartWorkFlow workflow = new FlowchartWorkFlow(cacheMonitor.getCacheInfo(), logList);
Set<MethodEntry> process = workflow.filterCacheableMethods(cachingConfig.expiryInterval());
logger.info(process.size() + " cacheable methods identified.");
//TODO find by annotations @Ignore and remove the methods marked
//if disable monitoring, should not schedule future analysis
if (cachingConfig.disableMonitoringAfterAnalysis()) {
enabled = false;
logger.info("Adaptive caching monitoring disabled since the model was built.");
}
return process;
}
@Override
public void initialize(Repository repository) {
Class<?> adaptiveCachingConfig = ConfigurationUtils.getAvailableConfigurationClass(AdaptiveCaching.class);
this.repository = repository;
this.cachingConfig = adaptiveCachingConfig.getAnnotation(AdaptiveCaching.class);
//todo load uncacheable annotation and methods and add to the blacklist
//todo load cacheable annotation and methods and add to the must-cache list
//setting up the repository
try {
properties = getPropertiesFile();
} catch (IOException e) {
e.printStackTrace();
}
if (properties == null || properties.isEmpty()) {
logger.error("adaptivecaching.properties is not defined, adaptive caching disabled.");
enabled = false;
} else
logger.info("adaptivecaching.properties found, loading properties...");
//TODO switch and build: pass a parameter and build
userGetter = UserGetterFactory.getInstance();
this.cacher = new AdaptiveMethodCacher(this.cachingConfig.cacheProvider(), this.cachingConfig.expiryInterval());
this.cacheMonitor = CacheMonitorFactory.getCacheMonitor(this.cacher.getCache(), this.cachingConfig.cacheProvider());
//TODO load another options from @AdaptiveCaching
//TODO get time from properties or see the external process
//TODO trigger by time
analyzerExecutor.scheduleWithFixedDelay(
this::run,
this.cachingConfig.firstAnalysis(), this.cachingConfig.analysisInterval(), TimeUnit.MILLISECONDS);
}
@Override
public boolean beforeExecuting(Key key) {
return isCacheable(key);
}
@Override
public void afterExecuting(Key key, Object result) {
try {
putInCache(key, result);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
@Override
public Object returnResult(Key key) {
try {
return getFromCache(key);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
}