/**
   * In case of a remotely originating transactions we don't have a chance to visit the single
   * commands but receive this "batch". We then need the before-apply snapshot of some types to
   * route the cleanup commands to the correct indexes. Note we don't need to visit the
   * CommitCommand as the indexing context is registered as a transaction sync.
   */
  @Override
  public Object visitPrepareCommand(TxInvocationContext ctx, PrepareCommand command)
      throws Throwable {
    final WriteCommand[] writeCommands = command.getModifications();
    final Object[] stateBeforePrepare = new Object[writeCommands.length];

    for (int i = 0; i < writeCommands.length; i++) {
      final WriteCommand writeCommand = writeCommands[i];
      if (writeCommand instanceof PutKeyValueCommand) {
        InternalCacheEntry internalCacheEntry =
            dataContainer.get(((PutKeyValueCommand) writeCommand).getKey());
        stateBeforePrepare[i] = internalCacheEntry != null ? internalCacheEntry.getValue() : null;
      } else if (writeCommand instanceof PutMapCommand) {
        stateBeforePrepare[i] = getPreviousValues(((PutMapCommand) writeCommand).getMap().keySet());
      } else if (writeCommand instanceof RemoveCommand) {
        InternalCacheEntry internalCacheEntry =
            dataContainer.get(((RemoveCommand) writeCommand).getKey());
        stateBeforePrepare[i] = internalCacheEntry != null ? internalCacheEntry.getValue() : null;
      } else if (writeCommand instanceof ReplaceCommand) {
        InternalCacheEntry internalCacheEntry =
            dataContainer.get(((ReplaceCommand) writeCommand).getKey());
        stateBeforePrepare[i] = internalCacheEntry != null ? internalCacheEntry.getValue() : null;
      }
    }

    final Object toReturn = super.visitPrepareCommand(ctx, command);

    if (ctx.isTransactionValid()) {
      final TransactionContext transactionContext = makeTransactionalEventContext();
      for (int i = 0; i < writeCommands.length; i++) {
        final WriteCommand writeCommand = writeCommands[i];
        if (writeCommand instanceof PutKeyValueCommand) {
          processPutKeyValueCommand(
              (PutKeyValueCommand) writeCommand, ctx, stateBeforePrepare[i], transactionContext);
        } else if (writeCommand instanceof PutMapCommand) {
          processPutMapCommand(
              (PutMapCommand) writeCommand,
              ctx,
              (Map<Object, Object>) stateBeforePrepare[i],
              transactionContext);
        } else if (writeCommand instanceof RemoveCommand) {
          processRemoveCommand(
              (RemoveCommand) writeCommand, ctx, stateBeforePrepare[i], transactionContext);
        } else if (writeCommand instanceof ReplaceCommand) {
          processReplaceCommand(
              (ReplaceCommand) writeCommand, ctx, stateBeforePrepare[i], transactionContext);
        } else if (writeCommand instanceof ClearCommand) {
          processClearCommand((ClearCommand) writeCommand, ctx, transactionContext);
        }
      }
    }
    return toReturn;
  }
  @Override
  public void copyForUpdate(DataContainer container, boolean writeSkewCheck) {
    if (isChanged()) return; // already copied

    // mark entry as changed.
    setChanged();

    if (writeSkewCheck) {
      // check for write skew.
      InternalCacheEntry ice = container.get(key);
      Object actualValue = ice == null ? null : ice.getValue();

      // Note that this identity-check is intentional.  We don't *want* to call actualValue.equals()
      // since that defeats the purpose.
      // the implicit "versioning" we have in R_R creates a new wrapper "value" instance for every
      // update.
      if (actualValue != null && actualValue != value) {
        String errormsg =
            new StringBuilder()
                .append("Detected write skew on key [")
                .append(getKey())
                .append("].  Another process has changed the entry since we last read it!")
                .toString();
        if (log.isWarnEnabled()) log.warn(errormsg + ".  Unable to copy entry for update.");
        throw new CacheException(errormsg);
      }
    }
    // make a backup copy
    oldValue = value;
  }
 private Map<Object, Object> getPreviousValues(Set<Object> keySet) {
   HashMap<Object, Object> previousValues = new HashMap<Object, Object>();
   for (Object key : keySet) {
     InternalCacheEntry internalCacheEntry = dataContainer.get(key);
     Object previousValue = internalCacheEntry != null ? internalCacheEntry.getValue() : null;
     previousValues.put(key, previousValue);
   }
   return previousValues;
 }
Exemple #4
0
  public void testIdleExpiryInPut() throws InterruptedException {
    Cache<String, String> cache = cm.getCache();
    long idleTime = IDLE_TIMEOUT;
    cache.put("k", "v", -1, MILLISECONDS, idleTime, MILLISECONDS);

    DataContainer dc = cache.getAdvancedCache().getDataContainer();
    InternalCacheEntry se = dc.get("k", null);
    assert se.getKey().equals("k");
    assert se.getValue().equals("v");
    assert se.getLifespan() == -1;
    assert se.getMaxIdle() == idleTime;
    assert !se.isExpired();
    assert cache.get("k").equals("v");
    Thread.sleep(idleTime + 100);
    assert se.isExpired();
    assert cache.get("k") == null;
  }
 @SuppressWarnings("UnusedParameters")
 protected EntryVersion getEntryVersion(InvocationContext ctx, Object key) {
   CacheEntry cacheEntry = dataContainer.get(key);
   return (cacheEntry != null) ? cacheEntry.getVersion() : null;
 }