Package org.directmemory.impl

Source Code of org.directmemory.impl.CacheStoreImpl

package org.directmemory.impl;

import java.io.EOFException;
import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

import org.directmemory.ICacheEntry;
import org.directmemory.ICacheStore;
import org.directmemory.ICacheSupervisor;
import org.directmemory.utils.SerializationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CacheStoreImpl implements ICacheStore {

  // suggested java memory settings:
  //-Xms512m -Xmx512m -XX:MaxPermSize=512m -Xss512k
  //   - win32 with 4gb - allocated 1250mb
  //   - win32 with 2gb - allocated 490mb

  // have to try this
  //-XX:MaxDirectMemorySize
  //java -d64 -XX:MaxDirectMemorySize=12g -XX:+UseLargePages com.example.MyApp 
  // see http://www.kdgregory.com/index.php?page=java.byteBuffer
  // and http://www.kdgregory.com/programming/java/ByteBuffer_JUG_Presentation.pdf
 
  private static Logger logger=LoggerFactory.getLogger(CacheStoreImpl.class);
 
  private Map<String, ICacheEntry> entries;
  private long offHeapLimit;
  private long inHeapEntriesLimit;
  private AtomicLong usedMemory = new AtomicLong(0);
  private int defaultDuration=-1;
 
  private ICacheSupervisor supervisor;
 
  private void setup(long inHeapEntriesLimit, long offHeapLimit) {
    this.inHeapEntriesLimit = inHeapEntriesLimit;
    this.offHeapLimit = offHeapLimit;
    // these params make things considerably worse
    // entries = new ConcurrentHashMap <String, ICacheEntry>(60000, 0.75F, 30);
    entries = new ConcurrentHashMap <String, ICacheEntry>();
    logger.info("DirectCache allocated with " + offHeapLimit + " bytes buffer");
    usedMemory = new AtomicLong(0);
    if (supervisor == null) {
      supervisor = new SimpleCacheSupervisor();
    } else {
      supervisor.signalReset();
    }
  }

  public void dispose() {
    entries.clear();
    usedMemory.set(0);
    // something more to free buffers?
  }
   
  public CacheStoreImpl() {
    // defaults to 50mb
    setup(-1, 50*1024*1024);
  }
  public CacheStoreImpl(long inHeapEntriesLimit, long offHeapLimit) {
    setup(inHeapEntriesLimit, offHeapLimit);
  }
 
  public void reset() {
    setup(inHeapEntriesLimit, offHeapLimit);
  }

  public int getDefaultDuration() {
    return defaultDuration;
  }
  public void setDefaultDuration(int defaultDuration) {
    this.defaultDuration = defaultDuration;
  }
  public Map<String, ICacheEntry> entries() {
    return this.entries;
  }

  public ICacheEntry put(String key, Serializable obj) throws IOException {
    return put(key, obj, defaultDuration);
  }
 
  public ICacheEntry put(String key, Serializable obj, int duration) throws IOException {

    // RpG
    // modify to insert in heap and then call entry.moveOffheap
    // the latter could also be performed later by the supervisor
   
    logger.info("serializing object with key '" + key + "'");

    byte source[] = null;

    try {
      source = SerializationUtils.serializeObject(obj);
      logger.info("object with key '" + key + "' serialized (" + source.length + ") bytes");
    } catch (IOException e) {
      logger.error("error serializing object with key '" + key + "': " + e.getMessage());
      throw new IOException();
    }
   
    if (usedMemory.get() + source.length >= offHeapLimit) {
      logger.debug("we are over capacity: removing one expired entry - no room for entry with key '" + key + "'");
      makeRoomForObject(source.length);
    }
   
    CacheEntryImpl newEntry = null;
   
    while  (newEntry == null) {
      logger.debug("trying to create entry for object with key '" + key + "'");
      newEntry = CacheEntryImpl.allocate(key, source, duration);
      if (newEntry == null) {
        makeRoomForObject(source.length);
      }
    }

    entries.put(key, newEntry);
    signalWeInserted(newEntry);
   
    usedMemory.addAndGet(source.length);

    source = null;

    logger.debug("stored entry with key '" + key + "'");

    return newEntry;
  }

  private void makeRoomForObject(long size) {

    long bytesFreed = signalCollectExpiredNeeded(size);

    if ( bytesFreed >= size || bytesFreed == -1 ) {
      return;
    } else {
      logger.debug("collecting LRU item");
      signalLRUCollectionNeeded(this, size- bytesFreed);
    }
  }

  public Serializable get(String key)  {

    logger.info("looking for object with key '" + key + "'");
   
    CacheEntryImpl entry = (CacheEntryImpl)entries.get(key);

    if (entry == null) {
      logger.info("could not find object with key '" + key + "'");
      return null;
    }
   
    try {
      Serializable obj = null;
     
      if (entry.offHeap()) {
        obj = entry.getPayload();
        logger.info("retrieved object with key '" + key + "' from heap");
      } else {
        byte[] dest = entry.getBuffer();
        if (dest == null) {
          logger.error("invalid buffer");
          return null;
        }
        obj = SerializationUtils.deserialize(dest);
        logger.info("retrieved object with key '" + key + "' (" +
            dest.length + " bytes)");
      }
      signalWeRetrevied(entry);
      return obj;
     
    } catch (EOFException ex) {
      logger.error("EOFException deserializing object with key '"
          + key + "' with size " + entry.size());
      return null;
    } catch (IOException e) {
      logger.error("IOException deserializing object with key '"
          + key + "' with size " + entry.size());
    } catch (ClassNotFoundException e) {
      logger.error("ClassNotFoundException deserializing object with key '"
          + key + "' with size " + entry.size());
    }
    return null;
  }
 
  public long  signalCollectExpiredNeeded(long bytesToFree) { 
   
    logger.debug("Looking for expired entries");

    long expiredSize = supervisor.signalCollectExpiredNeeded(this, bytesToFree);

    logger.debug("Collected " + expiredSize +  " bytes of expired entries");   
   
    return expiredSize;
 
 
  public ICacheEntry delete(String key) {

    logger.info("trying to remove entry with key '" + key + "'")

    ICacheEntry entry = null;
   
    entry = entries.remove(key);
    signalWeDeleted(key);
   
    if (entry != null) {
      usedMemory.addAndGet(-entry.size());
      entry.dispose();
      logger.info("object with key '" + key + "' disposed");
    }

    return entry;
  }
 
  public long remaining() {
    return offHeapLimit-usedMemory.get();
  }
  public long usedMemory() {
    return usedMemory.get();
  }
 
  @Override
  public String toString() {
    StringBuffer sb = new StringBuffer();
   
    sb.append("DirectCacheImpl {" );
    sb.append("supervisor: ");
    sb.append(supervisor.getClass());
    sb.append(", entries: ");
    sb.append(entries().size());
    sb.append(", ");
    sb.append("limit (mb): ");
    sb.append(offHeapLimit()/1024/1024);
    sb.append(", ");
    sb.append("size (mb): ");
    sb.append(usedMemory()/1024/1024);
    sb.append(", ");
    sb.append("remaining (mb): ");
    sb.append(remaining()/1024/1024);
    sb.append("}");
   
    return sb.toString();
  }

  public long offHeapLimit() {
    return offHeapLimit;
  }

  public void setSupervisor(ICacheSupervisor supervisor) {
    this.supervisor = supervisor;
  }

  public ICacheSupervisor getSupervisor() {
    return supervisor;
  }
 
  private void signalWeDeleted(String key) {
    supervisor.signalWeDeleted(key);
  }

  private void signalWeInserted(CacheEntryImpl newEntry) {
    supervisor.signalWeInserted(newEntry);
  }

  private void signalWeRetrevied(ICacheEntry entry) {
    supervisor.signalWeRetrieved(entry);
  }

  public void signalLRUCollectionNeeded(ICacheStore cache, long bytesToFree) { 
    logger.debug("Signalint LRU collection needed for " + bytesToFree + " bytes");
    long freedBytes = supervisor.signalLRUCollectionNeeded(this, bytesToFree);
    logger.debug("" + freedBytes + " bytes collected out " + bytesToFree + " needed");
  }

}
TOP

Related Classes of org.directmemory.impl.CacheStoreImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.