@Override
 public ReplaceStatus replace(final K key, final V oldValue, final V newValue)
     throws StoreAccessException {
   conditionalReplaceObserver.begin();
   try {
     ConditionalReplaceOperation<K, V> operation =
         new ConditionalReplaceOperation<K, V>(
             key, oldValue, newValue, timeSource.getTimeMillis());
     ByteBuffer payload = codec.encode(operation);
     Chain chain = storeProxy.getAndAppend(key.hashCode(), payload);
     ResolvedChain<K, V> resolvedChain = resolver.resolve(chain, key, timeSource.getTimeMillis());
     Result<V> result = resolvedChain.getResolvedResult(key);
     if (result != null) {
       if (oldValue.equals(result.getValue())) {
         conditionalReplaceObserver.end(StoreOperationOutcomes.ConditionalReplaceOutcome.REPLACED);
         return ReplaceStatus.HIT;
       } else {
         conditionalReplaceObserver.end(StoreOperationOutcomes.ConditionalReplaceOutcome.MISS);
         return ReplaceStatus.MISS_PRESENT;
       }
     } else {
       conditionalReplaceObserver.end(StoreOperationOutcomes.ConditionalReplaceOutcome.MISS);
       return ReplaceStatus.MISS_NOT_PRESENT;
     }
   } catch (RuntimeException re) {
     handleRuntimeException(re);
     return null;
   }
 }
 @Override
 public void remove(K key) {
   checkKey(key);
   removeOperationObserver.begin();
   try {
     map.remove(key);
   } finally {
     removeOperationObserver.end(StoreOperationOutcomes.RemoveOutcome.SUCCESS);
   }
 }
 @Override
 public boolean remove(final K key) throws StoreAccessException {
   removeObserver.begin();
   if (silentRemove(key)) {
     removeObserver.end(StoreOperationOutcomes.RemoveOutcome.REMOVED);
     return true;
   } else {
     removeObserver.end(StoreOperationOutcomes.RemoveOutcome.MISS);
     return false;
   }
 }
 @Override
 public ValueHolder<V> get(final K key) throws StoreAccessException {
   getObserver.begin();
   V value = getInternal(key);
   if (value == null) {
     getObserver.end(StoreOperationOutcomes.GetOutcome.MISS);
     return null;
   } else {
     getObserver.end(StoreOperationOutcomes.GetOutcome.HIT);
     return new ClusteredValueHolder<V>(value);
   }
 }
 @Override
 public ValueHolder<V> getAndFault(K key) throws CacheAccessException {
   getOperationObserver.begin();
   checkKey(key);
   OffHeapValueHolder<V> mappedValue = map.getAndPin(key);
   if (mappedValue == null) {
     getOperationObserver.end(StoreOperationOutcomes.GetOutcome.MISS);
   } else {
     getOperationObserver.end(StoreOperationOutcomes.GetOutcome.HIT);
   }
   return mappedValue;
 }
  @Override
  public ValueHolder<V> get(K key) {
    checkKey(key);
    getOperationObserver.begin();

    ValueHolder<V> result = internalGet(key, true);
    if (result == null) {
      getOperationObserver.end(StoreOperationOutcomes.GetOutcome.MISS);
    } else {
      getOperationObserver.end(StoreOperationOutcomes.GetOutcome.HIT);
    }
    return result;
  }
  @Override
  public void put(final K key, final V value) throws CacheAccessException {
    checkKey(key);
    checkValue(value);

    putOperationObserver.begin();
    while (true) {
      final long now = timeSource.getTimeMillis();
      try {
        map.compute(
            key,
            new BiFunction<K, OffHeapValueHolder<V>, OffHeapValueHolder<V>>() {
              @Override
              public OffHeapValueHolder<V> apply(K mappedKey, OffHeapValueHolder<V> mappedValue) {
                if (mappedValue != null && mappedValue.isExpired(now, TimeUnit.MILLISECONDS)) {
                  mappedValue = null;
                }

                if (mappedValue == null) {
                  return newCreateValueHolder(key, value, now);
                } else {
                  return newUpdatedValueHolder(key, value, mappedValue, now);
                }
              }
            },
            false);
        return;
      } catch (OversizeMappingException ex) {
        handleOversizeMappingException(key, ex);
      }
    }
  }
 @Override
 public PutStatus put(final K key, final V value) throws StoreAccessException {
   putObserver.begin();
   PutStatus status = silentPut(key, value);
   switch (status) {
     case PUT:
       putObserver.end(StoreOperationOutcomes.PutOutcome.PUT);
       break;
     case UPDATE:
       putObserver.end(StoreOperationOutcomes.PutOutcome.REPLACED);
       break;
     case NOOP:
       putObserver.end(StoreOperationOutcomes.PutOutcome.NOOP);
       break;
     default:
       throw new AssertionError("Invalid put status: " + status);
   }
   return status;
 }
 @Override
 public ValueHolder<V> replace(final K key, final V value) throws StoreAccessException {
   replaceObserver.begin();
   try {
     ReplaceOperation<K, V> operation =
         new ReplaceOperation<K, V>(key, value, timeSource.getTimeMillis());
     ByteBuffer payload = codec.encode(operation);
     Chain chain = storeProxy.getAndAppend(key.hashCode(), payload);
     ResolvedChain<K, V> resolvedChain = resolver.resolve(chain, key, timeSource.getTimeMillis());
     Result<V> result = resolvedChain.getResolvedResult(key);
     if (result == null) {
       replaceObserver.end(StoreOperationOutcomes.ReplaceOutcome.MISS);
       return null;
     } else {
       replaceObserver.end(StoreOperationOutcomes.ReplaceOutcome.REPLACED);
       return new ClusteredValueHolder<V>(result.getValue());
     }
   } catch (RuntimeException re) {
     handleRuntimeException(re);
     return null;
   }
 }