package com.quickserverlab.quickcached.cache.impl.directbytebuffer; import java.io.*; import java.nio.ByteBuffer; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; import com.quickserverlab.quickcached.QuickCached; import com.quickserverlab.quickcached.cache.impl.BaseCacheImpl; /** * * @author Akshathkumar Shetty */ public class DirectByteBufferImpl extends BaseCacheImpl { private static final Logger logger = Logger.getLogger(DirectByteBufferImpl.class.getName()); private static int tunerSleeptime = 130;//in sec private Map map = new ConcurrentHashMap(); private Map mapTtl = new ConcurrentHashMap(); protected volatile long expired; private Thread purgeThread = null; public DirectByteBufferImpl() { startPurgeThread(); } private void startPurgeThread() { purgeThread = new Thread("DirectByteBuffer-PurgeThread") { public void run() { long timespent = 0; long timeToSleep = 0; long stime = 0; long etime = 0; while(true) { timeToSleep = tunerSleeptime*1000 - timespent; if(timeToSleep>0) { try { Thread.sleep(timeToSleep); } catch (InterruptedException ex) { logger.log(Level.FINE, "Interrupted "+ex); break; } } stime = System.currentTimeMillis(); try { purgeOperation(); } catch (Exception ex) { logger.log(Level.WARNING, "Error: "+ex, ex); } etime = System.currentTimeMillis(); timespent = etime - stime; } } }; purgeThread.setDaemon(true); purgeThread.start(); } public void purgeOperation() { try { Iterator iterator = mapTtl.keySet().iterator(); String key = null; Date expTime; Date currentTime = new Date(); while(iterator.hasNext()) { key = (String) iterator.next(); expTime = (Date) mapTtl.get(key); if(expTime==null) { continue; } if(expTime.before(currentTime)) { mapTtl.remove(key); map.remove(key); expired++; } } } catch (Exception e) { logger.log(Level.WARNING, "Error: " + e, e); } } public void saveStats(Map stats) { if(stats==null) stats = new LinkedHashMap(); super.saveStats(stats); //expired - Number of items that expired stats.put("expired", ""+expired); } public String getName() { return "DirectByteBufferImpl"; } public long getSize() { return map.size(); } public void setToCache(String key, Object value, int objectSize, int expInSec) throws Exception { ByteBuffer buffer = getByteBuffer(value); map.put(key, buffer); if (expInSec != 0) { mapTtl.put(key, new Date(System.currentTimeMillis()+expInSec*1000)); } else { mapTtl.remove(key);//just in case } } public void updateToCache(String key, Object value, int objectSize) throws Exception { ByteBuffer buffer = getByteBuffer(value); map.put(key, buffer); } public void updateToCache(String key, Object value, int objectSize, int expInSec) throws Exception { updateToCache(key, value, objectSize); if (expInSec != 0) { mapTtl.put(key, new Date(System.currentTimeMillis()+expInSec*1000)); } else { mapTtl.remove(key);//just in case } } public Object getFromCache(String key) throws IOException, ClassNotFoundException { ByteBuffer buffer = (ByteBuffer) map.get(key); if (buffer != null) { return getByteBuffer(buffer); } else { if(QuickCached.DEBUG) logger.log(Level.FINE, "no value for key: {0}", key); return null; } } public boolean deleteFromCache(String key) throws Exception { mapTtl.remove(key); Object obj = map.remove(key); return obj!=null; } public void flushCache() throws Exception { mapTtl.clear(); map.clear(); } private ByteBuffer getByteBuffer(Object value) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream stream = new ObjectOutputStream(baos); stream.writeObject(value); stream.close(); byte b[] = baos.toByteArray(); ByteBuffer buffer = ByteBuffer.allocateDirect(b.length); buffer.put(b); return buffer; } private Object getByteBuffer(ByteBuffer buffer) throws IOException, ClassNotFoundException { byte buf[] = new byte[buffer.capacity()]; buffer.rewind(); buffer.get(buf); ByteArrayInputStream bais = new ByteArrayInputStream(buf); ObjectInputStream oois = new ObjectInputStream(bais); Object object = oois.readObject(); oois.close(); return object; } private String fileName = "./"+getName()+"_"+QuickCached.getPort()+".dat"; public boolean saveToDisk() { System.out.print("Saving state to disk.. "); ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new FileOutputStream(fileName)); writeObject(oos); oos.flush(); return true; } catch (Exception e) { logger.log(Level.WARNING, "Error: {0}", e); } finally { if(oos!=null) { try { oos.close(); } catch (IOException ex) { logger.log(Level.WARNING, "Error: "+ex, ex); } } System.out.println("Done"); } return false; } public boolean readFromDisk() { File file = new File(fileName); if(file.canRead()==false) return false; System.out.print("Reading state from disk.. "); ObjectInputStream ois = null; try { ois = new ObjectInputStream(new FileInputStream(fileName)); readObject(ois); return true; } catch (Exception e) { logger.log(Level.WARNING, "Error: {0}", e); } finally { if(ois!=null) { try { ois.close(); } catch (IOException ex) { logger.log(Level.WARNING, "Error: "+ex, ex); } } file.delete(); System.out.println("Done"); } return false; } private void writeObject(ObjectOutputStream out) throws IOException { purgeThread.interrupt(); HashMap<Object, Object> wcache = new HashMap<Object, Object>(); Iterator<String> it = map.keySet().iterator(); String key = null; Object value = null; while(it.hasNext()) { key = (String) it.next(); try { value = getFromCache(key); } catch (ClassNotFoundException ex) { logger.log(Level.FINE, "Error: "+ex, ex); continue; } if(value!=null) { wcache.put(key, value); } else { mapTtl.remove(key); } } out.writeObject(wcache); out.writeObject(mapTtl); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { HashMap<Object, Object> wcache = (HashMap<Object, Object>) in.readObject(); Iterator it = wcache.keySet().iterator(); Object key = null; Object value = null; while(it.hasNext()) { key = it.next(); value = wcache.get(key); ByteBuffer buffer = getByteBuffer(value); map.put(key, buffer); } mapTtl = (Map) in.readObject(); } }