Package freenet.store

Source Code of freenet.store.RAMFreenetStore$Block

package freenet.store;

import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;

import freenet.keys.KeyVerifyException;
import freenet.node.stats.StoreAccessStats;
import freenet.node.useralerts.UserAlertManager;
import freenet.support.ByteArrayWrapper;
import freenet.support.LRUMap;
import freenet.support.Logger;
import freenet.support.Ticker;

/**
* LRU in memory store.
*
* For debugging / simulation only
*/
public class RAMFreenetStore<T extends StorableBlock> implements FreenetStore<T> {

  private final static class Block {
    byte[] header;
    byte[] data;
    byte[] fullKey;
    boolean oldBlock;
  }
 
  private final LRUMap<ByteArrayWrapper, Block> blocksByRoutingKey;
 
  private final StoreCallback<T> callback;
 
  private int maxKeys;
 
  private long hits;
  private long misses;
  private long writes;
 
  public RAMFreenetStore(StoreCallback<T> callback, int maxKeys) {
    this.callback = callback;
    this.blocksByRoutingKey = LRUMap.createSafeMap(ByteArrayWrapper.FAST_COMPARATOR);
    this.maxKeys = maxKeys;
    callback.setStore(this);
  }
 
  @Override
  public synchronized T fetch(byte[] routingKey, byte[] fullKey,
      boolean dontPromote, boolean canReadClientCache, boolean canReadSlashdotCache, boolean ignoreOldBlocks, BlockMetadata meta) throws IOException {
    ByteArrayWrapper key = new ByteArrayWrapper(routingKey);
    Block block = blocksByRoutingKey.get(key);
    if(block == null) {
      misses++;
      return null;
    }
    if(ignoreOldBlocks && block.oldBlock) {
      Logger.normal(this, "Ignoring old block");
      return null;
    }
    try {
      T ret =
        callback.construct(block.data, block.header, routingKey, block.fullKey, canReadClientCache, canReadSlashdotCache, meta, null);
      hits++;
      if(!dontPromote)
        blocksByRoutingKey.push(key, block);
      if(meta != null && block.oldBlock)
        meta.setOldBlock();
      return ret;
    } catch (KeyVerifyException e) {
      blocksByRoutingKey.removeKey(key);
      misses++;
      return null;
    }
  }

  @Override
  public synchronized long getMaxKeys() {
    return maxKeys;
  }

  @Override
  public synchronized long hits() {
    return hits;
  }

  @Override
  public synchronized long keyCount() {
    return blocksByRoutingKey.size();
  }

  @Override
  public synchronized long misses() {
    return misses;
  }

  @Override
  public synchronized void put(T block, byte[] data, byte[] header, boolean overwrite, boolean isOldBlock) throws KeyCollisionException {
    byte[] routingkey = block.getRoutingKey();
    byte[] fullKey = block.getFullKey();
   
    writes++;
    ByteArrayWrapper key = new ByteArrayWrapper(routingkey);
    Block oldBlock = blocksByRoutingKey.get(key);
    boolean storeFullKeys = callback.storeFullKeys();
    if(oldBlock != null) {
      if(callback.collisionPossible()) {
        boolean equals = Arrays.equals(oldBlock.data, data) &&
          Arrays.equals(oldBlock.header, header) &&
          (storeFullKeys ? Arrays.equals(oldBlock.fullKey, fullKey) : true);
        if(equals) {
          if(!isOldBlock)
            oldBlock.oldBlock = false;
          return;
        }
        if(overwrite) {
          oldBlock.data = data;
          oldBlock.header = header;
          if(storeFullKeys)
            oldBlock.fullKey = fullKey;
          oldBlock.oldBlock = isOldBlock;
        } else {
          throw new KeyCollisionException();
        }
        return;
      } else {
        if(!isOldBlock)
          oldBlock.oldBlock = false;
        return;
      }
    }
    Block storeBlock = new Block();
    storeBlock.data = data;
    storeBlock.header = header;
    if(storeFullKeys)
      storeBlock.fullKey = fullKey;
    storeBlock.oldBlock = isOldBlock;
    blocksByRoutingKey.push(key, storeBlock);
    while(blocksByRoutingKey.size() > maxKeys) {
      blocksByRoutingKey.popKey();
    }
  }

  @Override
  public synchronized void setMaxKeys(long maxStoreKeys, boolean shrinkNow)
      throws IOException {
    this.maxKeys = (int)Math.min(Integer.MAX_VALUE, maxStoreKeys);
    // Always shrink now regardless of parameter as we will shrink on the next put() anyway.
    while(blocksByRoutingKey.size() > maxKeys) {
      blocksByRoutingKey.popKey();
    }
  }

  @Override
  public long writes() {
    return writes;
  }

  @Override
  public long getBloomFalsePositive() {
    return -1;
  }
 
  @Override
  public boolean probablyInStore(byte[] routingKey) {
    ByteArrayWrapper key = new ByteArrayWrapper(routingKey);
    return blocksByRoutingKey.get(key) != null;
  }

  public void clear() {
    blocksByRoutingKey.clear();
  }

  public void migrateTo(StoreCallback<T> target, boolean canReadClientCache) throws IOException {
    Enumeration<ByteArrayWrapper> keys = blocksByRoutingKey.keys();
    while(keys.hasMoreElements()) {
      ByteArrayWrapper routingKeyWrapped = keys.nextElement();
      byte[] routingKey = routingKeyWrapped.get();
      Block block = blocksByRoutingKey.get(routingKeyWrapped);
     
      T ret;
      try {
        ret = callback.construct(block.data, block.header, routingKey, block.fullKey, canReadClientCache, false, null, null);
      } catch (KeyVerifyException e) {
        Logger.error(this, "Caught while migrating: "+e, e);
        continue;
      }
      try {
        target.getStore().put(ret, block.data, block.header, false, block.oldBlock);
      } catch (KeyCollisionException e) {
        // Ignore
      }
    }
  }
 
  @Override
  public StoreAccessStats getSessionAccessStats() {
    return new StoreAccessStats() {

      @Override
      public long hits() {
        return hits;
      }

      @Override
      public long misses() {
        return misses;
      }

      @Override
      public long falsePos() {
        return 0;
      }

      @Override
      public long writes() {
        return writes;
      }
     
    };
  }

  @Override
  public StoreAccessStats getTotalAccessStats() {
    return null;
  }

  @Override
  public boolean start(Ticker ticker, boolean longStart) throws IOException {
    return false;
  }

  @Override
  public void setUserAlertManager(UserAlertManager userAlertManager) {
    // Do nothing
  }
 
  @Override
  public FreenetStore<T> getUnderlyingStore() {
    return this;
  }
 
  @Override
  public void close() {
    // Do nothing
  }
}
TOP

Related Classes of freenet.store.RAMFreenetStore$Block

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.