/**
   * Gets Hibernate session.
   *
   * @param tx Cache transaction.
   * @return Session.
   */
  Session session(@Nullable GridCacheTx tx) {
    Session ses;

    if (tx != null) {
      ses = tx.meta(ATTR_SES);

      if (ses == null) {
        ses = sesFactory.openSession();

        ses.beginTransaction();

        // Store session in transaction metadata, so it can be accessed
        // for other operations on the same transaction.
        tx.addMeta(ATTR_SES, ses);

        if (log.isDebugEnabled())
          log.debug("Hibernate session open [ses=" + ses + ", tx=" + tx.xid() + "]");
      }
    } else {
      ses = sesFactory.openSession();

      ses.beginTransaction();
    }

    return ses;
  }
    /** {@inheritDoc} */
    @Override
    public Integer call() throws Exception {
      GridCacheTx tx = CU.txStartInternal(ctx, latchView, PESSIMISTIC, REPEATABLE_READ);

      try {
        GridCacheCountDownLatchValue latchVal = latchView.get(key);

        if (latchVal == null) {
          if (log.isDebugEnabled())
            log.debug("Failed to find count down latch with given name: " + name);

          assert cnt == 0;

          return cnt;
        }

        int retVal;

        if (val > 0) {
          retVal = latchVal.get() - val;

          if (retVal < 0) retVal = 0;
        } else retVal = 0;

        latchVal.set(retVal);

        latchView.put(key, latchVal);

        tx.commit();

        return retVal;
      } finally {
        tx.end();
      }
    }
  /**
   * @param concurrency Concurrency.
   * @param isolation Isolation.
   * @throws GridException If test failed.
   */
  private void checkTransactionTimeout(
      GridCacheTxConcurrency concurrency, GridCacheTxIsolation isolation) throws Exception {

    boolean wasEx = false;

    GridCacheTx tx = null;

    try {
      GridCache<Integer, String> cache = grid.cache(null);

      tx = cache.txStart(concurrency, isolation, 50, 0);

      cache.put(1, "1");

      Thread.sleep(100);

      cache.put(1, "2");

      tx.commit();
    } catch (GridCacheTxOptimisticException e) {
      info("Received expected optimistic exception: " + e.getMessage());

      wasEx = true;

      tx.rollback();
    } catch (GridCacheTxTimeoutException e) {
      info("Received expected timeout exception: " + e.getMessage());

      wasEx = true;

      tx.rollback();
    }

    assert wasEx;
  }
  /** {@inheritDoc} */
  @Override
  public void txEnd(GridCacheTx tx, boolean commit) throws GridException {
    init();

    Session ses = tx.removeMeta(ATTR_SES);

    if (ses != null) {
      Transaction hTx = ses.getTransaction();

      if (hTx != null) {
        try {
          if (commit) {
            ses.flush();

            hTx.commit();
          } else hTx.rollback();

          if (log.isDebugEnabled())
            log.debug("Transaction ended [xid=" + tx.xid() + ", commit=" + commit + ']');
        } catch (HibernateException e) {
          throw new GridException(
              "Failed to end transaction [xid=" + tx.xid() + ", commit=" + commit + ']', e);
        } finally {
          ses.close();
        }
      }
    }
  }
  /** Roll backs current transaction. */
  private void rollbackCurrentTx() {
    try {
      TxContext ctx = txCtx.get();

      if (ctx != null) {
        txCtx.remove();

        GridCacheTx tx = cache.tx();

        if (tx != null) tx.rollback();
      }
    } catch (GridException e) {
      log.error("Failed to rollback cache transaction.", e);
    }
  }
  /**
   * @param ctx Transaction context.
   * @param key Key.
   * @throws GridException If failed.
   */
  private void unlock(TxContext ctx, Object key) throws GridException {
    if (ctx.unlocked(key)) { // Finish transaction if last key is unlocked.
      txCtx.remove();

      GridCacheTx tx = cache.tx();

      assert tx != null;

      try {
        tx.commit();
      } finally {
        tx.close();
      }

      assert cache.tx() == null;
    }
  }
  /** {@inheritDoc} */
  @Override
  public void rollback() throws GridException {
    enter();

    try {
      tx.rollback();
    } finally {
      leave();
    }
  }
  /** {@inheritDoc} */
  @Override
  public boolean isRollbackOnly() {
    enter();

    try {
      return tx.isRollbackOnly();
    } finally {
      leave();
    }
  }
  /** {@inheritDoc} */
  @Override
  public void end() throws GridException {
    enter();

    try {
      tx.end();
    } finally {
      leave();
    }
  }
  /** {@inheritDoc} */
  @Override
  public GridFuture<GridCacheTx> commitAsync() {
    enter();

    try {
      return tx.commitAsync();
    } finally {
      leave();
    }
  }
 /** {@inheritDoc} */
 @Override
 public GridCacheTxConcurrency concurrency() {
   return tx.concurrency();
 }
 /** {@inheritDoc} */
 @Override
 public GridCacheTxIsolation isolation() {
   return tx.isolation();
 }
 /** {@inheritDoc} */
 @Override
 public long startTime() {
   return tx.startTime();
 }
 /** {@inheritDoc} */
 @Override
 public long threadId() {
   return tx.threadId();
 }
 /** {@inheritDoc} */
 @Override
 public UUID nodeId() {
   return tx.nodeId();
 }
 /** {@inheritDoc} */
 @Override
 public <V> V putMetaIfAbsent(String name, Callable<V> c) {
   return tx.putMetaIfAbsent(name, c);
 }
 /** {@inheritDoc} */
 @Override
 public void copyMeta(GridMetadataAware from) {
   tx.copyMeta(from);
 }
 /** {@inheritDoc} */
 @Override
 public <V> V addMeta(String name, V val) {
   return tx.addMeta(name, val);
 }
 /** {@inheritDoc} */
 @Override
 public <V> Map<String, V> allMeta() {
   return tx.allMeta();
 }
 /** {@inheritDoc} */
 @Override
 public <V> boolean removeMeta(String name, V val) {
   return tx.removeMeta(name, val);
 }
 /** {@inheritDoc} */
 @SuppressWarnings({"RedundantTypeArguments"})
 @Override
 public <V> V removeMeta(String name) {
   return tx.<V>removeMeta(name);
 }
 /** {@inheritDoc} */
 @Override
 public <V> V addMetaIfAbsent(String name, @Nullable Callable<V> c) {
   return tx.addMetaIfAbsent(name, c);
 }
 /** {@inheritDoc} */
 @Nullable
 @Override
 public <V> V addMetaIfAbsent(String name, V val) {
   return tx.addMeta(name, val);
 }
 /** {@inheritDoc} */
 @Override
 public boolean isInvalidate() {
   return tx.isInvalidate();
 }
 /** {@inheritDoc} */
 @Override
 public void copyMeta(Map<String, ?> data) {
   tx.copyMeta(data);
 }
 /** {@inheritDoc} */
 @Override
 public <V> boolean replaceMeta(String name, V curVal, V newVal) {
   return tx.replaceMeta(name, curVal, newVal);
 }
 /** {@inheritDoc} */
 @Override
 public UUID xid() {
   return tx.xid();
 }
 /** {@inheritDoc} */
 @Override
 public <V> V putMetaIfAbsent(String name, V val) {
   return tx.putMetaIfAbsent(name, val);
 }
 /** {@inheritDoc} */
 @Override
 public boolean hasMeta(String name) {
   return tx.hasMeta(name);
 }
 /** {@inheritDoc} */
 @Override
 public <V> boolean hasMeta(String name, V val) {
   return tx.hasMeta(name, val);
 }