@Test
 public void testProcessMatchingLock() throws Exception {
   ExpiryMarker original =
       new ExpiryMarker(null, 100L, "the-marker-id").markForExpiration(100L, "some-marker-id");
   Map.Entry<Object, Expirable> entry = mockEntry(original);
   UnlockEntryProcessor processor =
       new UnlockEntryProcessor(
           new ExpiryMarker(null, 100L, "the-marker-id"), "next-marker-id", 150L);
   ArgumentCaptor<Expirable> captor = ArgumentCaptor.forClass(Expirable.class);
   processor.process(entry);
   verify(entry).setValue(captor.capture());
   Expirable result = captor.getValue();
   assertNotSame(original, result);
   assertThat(result, instanceOf(ExpiryMarker.class));
   ExpiryMarker marker = (ExpiryMarker) result;
   assertTrue(marker.matches(original));
 }
 @Test
 public void testProcessWithValue() throws Exception {
   Map.Entry<Object, Expirable> entry = mockEntry(new Value(null, 100L, "some-value"));
   UnlockEntryProcessor processor =
       new UnlockEntryProcessor(
           new ExpiryMarker(null, 100L, "other-marker-id"), "next-marker-id", 150L);
   ArgumentCaptor<Expirable> captor = ArgumentCaptor.forClass(Expirable.class);
   processor.process(entry);
   verify(entry).setValue(captor.capture());
   Expirable result = captor.getValue();
   assertThat(result, instanceOf(ExpiryMarker.class));
   ExpiryMarker marker = (ExpiryMarker) result;
   assertFalse(
       "market must be expirable after timestamp", marker.isReplaceableBy(150L, null, null));
   assertTrue(
       "market must be expirable after timestamp", marker.isReplaceableBy(151L, null, null));
 }
  @Override
  public Boolean process(Map.Entry<Object, Expirable> entry) {
    Expirable expirable = entry.getValue();
    boolean updated;

    if (expirable == null) {
      // Nothing there. The entry was evicted? It should be safe to replace it
      expirable = new Value(newVersion, timestamp, newValue);
      updated = true;
    } else {
      if (expirable.matches(lock)) {
        final ExpiryMarker marker = (ExpiryMarker) expirable;
        if (marker.isConcurrent()) {
          // Multiple transactions are attempting to update the same entry. Its highly
          // likely that the value we are attempting to set is invalid. Instead just
          // expire the entry and allow the next put to the cache to succeed if no more
          // transactions are in-flight.
          expirable = marker.expire(timestamp);
          updated = false;
        } else {
          // Only one transaction attempted to update the entry so it is safe to replace
          // it with the value supplied
          expirable = new Value(newVersion, timestamp, newValue);
          updated = true;
        }
      } else if (expirable.getValue() == null) {
        // It's a different marker, Leave it as is
        return false;
      } else {
        // It's a value. We have no way to see which is correct so we expire the entry.
        // It is expired instead of removed to prevent in progress transactions from
        // putting stale values into the cache
        expirable = new ExpiryMarker(newVersion, timestamp, nextMarkerId).expire(timestamp);
        updated = false;
      }
    }

    entry.setValue(expirable);
    return updated;
  }