private void runAssertion(CacheOperation operation)
      throws NotSupportedException, SystemException, HeuristicMixedException,
          HeuristicRollbackException, InvalidTransactionException, RollbackException {
    txStatus.reset();
    tm.begin();
    cache(1).put("k1", "v1");
    Transaction k1LockOwner = tm.suspend();
    assert lm1.isLocked("k1");

    assertEquals(1, txTable1.getLocalTxCount());
    tm.begin();
    cache(0).put("k2", "v2");
    assert lm0.isLocked("k2");
    assert !lm1.isLocked("k2");

    operation.execute();

    assertEquals(1, txTable1.getLocalTxCount());
    assertEquals(1, txTable0.getLocalTxCount());

    try {
      tm.commit();
      assert false;
    } catch (RollbackException re) {
      // expected
    }
    assert txStatus.teReceived;
    assert txStatus.isTxInTableAfterTeOnPrepare;
    // expect 1 as k1 is locked by the other tx
    assertEquals(
        txStatus.numLocksAfterTeOnPrepare,
        1,
        "This would make sure that locks are being released quickly, not waiting for a remote rollback to happen");

    assertEquals(0, txTable0.getLocalTxCount());
    assertEquals(1, txTable1.getLocalTxCount());

    log.trace("Right before second commit");
    tm.resume(k1LockOwner);
    tm.commit();
    assertEquals("v1", cache(0).get("k1"));
    assertEquals("v1", cache(1).get("k1"));
    assertEquals(0, txTable1.getLocalTxCount());
    assertEquals(0, txTable1.getLocalTxCount());
    assertEquals(0, lm0.getNumberOfLocksHeld());
    assertEquals(0, lm1.getNumberOfLocksHeld());
  }
 @Override
 public final BasicInvocationStage visitInvalidateCommand(
     InvocationContext ctx, InvalidateCommand command) throws Throwable {
   if (hasSkipLocking(command)) {
     return invokeNext(ctx, command);
   }
   try {
     lockAllAndRecord(ctx, Arrays.asList(command.getKeys()), getLockTimeoutMillis(command));
   } catch (Throwable t) {
     lockManager.unlockAll(ctx);
   }
   return invokeNext(ctx, command).handle(unlockAllReturnHandler);
 }
  // We need this method in here because of putForExternalRead
  protected final BasicInvocationStage visitNonTxDataWriteCommand(
      InvocationContext ctx, DataWriteCommand command) throws Throwable {
    if (hasSkipLocking(command) || !shouldLockKey(command.getKey())) {
      return invokeNext(ctx, command);
    }

    try {
      lockAndRecord(ctx, command.getKey(), getLockTimeoutMillis(command));
    } catch (Throwable t) {
      lockManager.unlockAll(ctx);
      throw t;
    }
    return invokeNext(ctx, command).handle(unlockAllReturnHandler);
  }
  public void testSyncReplMap() throws Exception {
    Integer age;
    LockManager lm1 = TestingUtil.extractComponent(cache1, LockManager.class);

    assert lm1.getOwner("age") == null : "lock info is " + lm1.printLockInfo();
    LocalListener lis = new LocalListener();
    cache1.addListener(lis);
    lis.put("age", 38);
    assert lm1.getOwner("age") == null : "lock info is " + lm1.printLockInfo();

    cache1.put("name", "Ben");
    // value on cache2 must be 38
    age = (Integer) cache2.get("age");
    assertNotNull("\"age\" obtained from cache2 must be non-null ", age);
    assertTrue("\"age\" must be 38", age == 38);
    assert lm1.getOwner("age") == null : "lock info is " + lm1.printLockInfo();
  }
  @Override
  public final BasicInvocationStage visitInvalidateL1Command(
      InvocationContext ctx, InvalidateL1Command command) throws Throwable {
    if (command.isCausedByALocalWrite(cdl.getAddress())) {
      if (trace) getLog().trace("Skipping invalidation as the write operation originated here.");
      return returnWith(null);
    }

    if (hasSkipLocking(command)) {
      return invokeNext(ctx, command);
    }

    final Object[] keys = command.getKeys();
    if (keys == null || keys.length < 1) {
      return returnWith(null);
    }

    ArrayList<Object> keysToInvalidate = new ArrayList<>(keys.length);
    for (Object key : keys) {
      try {
        lockAndRecord(ctx, key, 0);
        keysToInvalidate.add(key);
      } catch (TimeoutException te) {
        getLog().unableToLockToInvalidate(key, cdl.getAddress());
      }
    }
    if (keysToInvalidate.isEmpty()) {
      return returnWith(null);
    }

    command.setKeys(keysToInvalidate.toArray());
    return invokeNext(ctx, command)
        .handle(
            (rCtx, rCommand, rv, t) -> {
              ((InvalidateL1Command) rCommand).setKeys(keys);
              if (!rCtx.isInTxScope()) lockManager.unlockAll(rCtx);
            });
  }
    @Override
    public Map<String, Number> call() throws Exception {

      Map<String, Number> map = new HashMap<>();
      Stats stats = remoteCache.getStats();
      map.put(AVERAGE_READ_TIME, stats.getAverageReadTime());
      map.put(AVERAGE_WRITE_TIME, stats.getAverageWriteTime());
      map.put(AVERAGE_REMOVE_TIME, stats.getAverageRemoveTime());
      map.put(EVICTIONS, stats.getEvictions());
      map.put(HITS, stats.getHits());
      map.put(MISSES, stats.getMisses());
      final CacheMode cacheMode = getCacheMode(remoteCache);
      // for replicated caches, we don't need to send the number of entries since it is the same in
      // all the nodes.
      if (cacheMode.isDistributed()) {
        map.put(NUMBER_OF_ENTRIES, stats.getCurrentNumberOfEntries() / numOwners());
      } else if (!cacheMode.isReplicated()) {
        map.put(NUMBER_OF_ENTRIES, stats.getCurrentNumberOfEntries());
      }
      map.put(STORES, stats.getStores());
      map.put(REMOVE_HITS, stats.getRemoveHits());
      map.put(REMOVE_MISSES, stats.getRemoveMisses());
      map.put(TIME_SINCE_START, stats.getTimeSinceStart());

      LockManager lockManager = remoteCache.getLockManager();
      map.put(NUMBER_OF_LOCKS_HELD, lockManager.getNumberOfLocksHeld());

      // number of locks available is not exposed through the LockManager interface
      map.put(NUMBER_OF_LOCKS_AVAILABLE, 0);

      // invalidations
      InvalidationInterceptor invalidationInterceptor =
          getFirstInterceptorWhichExtends(remoteCache, InvalidationInterceptor.class);
      if (invalidationInterceptor != null) {
        map.put(INVALIDATIONS, invalidationInterceptor.getInvalidations());
      } else {
        map.put(INVALIDATIONS, 0);
      }

      // passivations
      PassivationManager pManager =
          remoteCache.getComponentRegistry().getComponent(PassivationManager.class);
      if (pManager != null) {
        map.put(PASSIVATIONS, pManager.getPassivations());
      } else {
        map.put(PASSIVATIONS, 0);
      }

      // activations
      ActivationManager aManager =
          remoteCache.getComponentRegistry().getComponent(ActivationManager.class);
      if (pManager != null) {
        map.put(ACTIVATIONS, aManager.getActivationCount());
      } else {
        map.put(ACTIVATIONS, 0);
      }

      // cache loaders
      ActivationInterceptor aInterceptor =
          getFirstInterceptorWhichExtends(remoteCache, ActivationInterceptor.class);
      if (aInterceptor != null) {
        map.put(CACHE_LOADER_LOADS, aInterceptor.getCacheLoaderLoads());
        map.put(CACHE_LOADER_MISSES, aInterceptor.getCacheLoaderMisses());
      } else {
        map.put(CACHE_LOADER_LOADS, 0);
        map.put(CACHE_LOADER_MISSES, 0);
      }
      // cache store
      CacheWriterInterceptor interceptor =
          getFirstInterceptorWhichExtends(remoteCache, CacheWriterInterceptor.class);
      if (interceptor != null) {
        map.put(CACHE_WRITER_STORES, interceptor.getWritesToTheStores());
      } else {
        map.put(CACHE_WRITER_STORES, 0);
      }
      return map;
    }
 /**
  * Verifies the cache doesn't contain any lock
  *
  * @param cache
  */
 public static void assertNoLocks(Cache<?, ?> cache) {
   LockManager lm = TestingUtil.extractLockManager(cache);
   for (Object key : cache.keySet()) assert !lm.isLocked(key);
 }
  public void testCommitDoesntWriteAfterRollback() throws Exception {
    // Start a tx on A: put(k, v1), owners(k) = [B (primary) and C (backup)]
    // Block the commit on C so that it times out
    // Wait for the rollback command to be executed on B and C, and for the tx to end
    // Check that locks are released on B
    // Start another transaction on A: put(k, v2) with the same key
    // Check that the new transaction writes successfully
    // Allow the commit to proceed on C
    // Check that k=v2 everywhere
    StateSequencer sequencer = new StateSequencer();
    sequencer.logicalThread(
        "tx1",
        "tx1:begin",
        "tx1:block_commit_on_backup",
        "tx1:after_rollback_on_primary",
        "tx1:after_rollback_on_backup",
        "tx1:resume_commit_on_backup",
        "tx1:after_commit_on_backup",
        "tx1:check");
    sequencer.logicalThread("tx2", "tx2:begin", "tx2:end");

    sequencer.order(
        "tx1:after_rollback_on_backup", "tx2:begin", "tx2:end", "tx1:resume_commit_on_backup");

    advanceOnInterceptor(
            sequencer,
            cache(2),
            StateTransferInterceptor.class,
            matchCommand(CommitCommand.class).matchCount(0).build())
        .before("tx1:block_commit_on_backup", "tx1:resume_commit_on_backup")
        .after("tx1:after_commit_on_backup");

    advanceOnInterceptor(
            sequencer,
            cache(1),
            StateTransferInterceptor.class,
            matchCommand(RollbackCommand.class).build())
        .after("tx1:after_rollback_on_primary");

    advanceOnInterceptor(
            sequencer,
            cache(2),
            StateTransferInterceptor.class,
            matchCommand(RollbackCommand.class).build())
        .after("tx1:after_rollback_on_backup");

    assertEquals(
        Arrays.asList(address(1), address(2)),
        advancedCache(0).getDistributionManager().locate(TEST_KEY));
    sequencer.advance("tx1:begin");

    tm(0).begin();
    cache(0).put(TEST_KEY, TX1_VALUE);
    try {
      tm(0).commit();
    } catch (RollbackException e) {
      log.debugf("Commit timed out as expected", e);
    }

    sequencer.advance("tx2:begin");
    LockManager lockManager1 = TestingUtil.extractLockManager(cache(1));
    assertFalse(lockManager1.isLocked(TEST_KEY));

    tm(0).begin();
    cache(0).put(TEST_KEY, TX2_VALUE);
    tm(0).commit();

    checkValue();
    sequencer.advance("tx2:end");

    sequencer.advance("tx1:check");
    checkValue();
  }
 @Override
 public void accept(
     InvocationContext rCtx, VisitableCommand rCommand, Object rv, Throwable throwable)
     throws Throwable {
   lockManager.unlockAll(rCtx);
 }
 protected final void lockAllAndRecord(InvocationContext context, Collection<?> keys, long timeout)
     throws InterruptedException {
   keys.forEach(context::addLockedKey);
   lockManager.lockAll(keys, context.getLockOwner(), timeout, TimeUnit.MILLISECONDS).lock();
 }
 protected final void lockAndRecord(InvocationContext context, Object key, long timeout)
     throws InterruptedException {
   context.addLockedKey(key);
   lockManager.lock(key, context.getLockOwner(), timeout, TimeUnit.MILLISECONDS).lock();
 }
 protected final Throwable cleanLocksAndRethrow(InvocationContext ctx, Throwable te) {
   lockManager.unlockAll(ctx);
   return te;
 }
 private void lockAndWrap(InvocationContext ctx, Object key, InternalCacheEntry ice)
     throws InterruptedException {
   lockManager.acquireLock(ctx, key);
   entryFactory.wrapEntryForPut(ctx, key, ice, false);
 }