/** {@inheritDoc} */
  @Override
  public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr)
      throws IgniteCheckedException {
    super.finishUnmarshal(ctx, ldr);

    if (writes != null) unmarshalTx(writes, false, ctx, ldr);

    if (reads != null) unmarshalTx(reads, false, ctx, ldr);

    if (grpLockKeyBytes != null && grpLockKey == null)
      grpLockKey = ctx.marshaller().unmarshal(grpLockKeyBytes, ldr);

    if (dhtVerKeys != null && dhtVers == null) {
      assert dhtVerVals != null;
      assert dhtVerKeys.size() == dhtVerVals.size();

      Iterator<IgniteTxKey> keyIt = dhtVerKeys.iterator();
      Iterator<GridCacheVersion> verIt = dhtVerVals.iterator();

      dhtVers = U.newHashMap(dhtVerKeys.size());

      while (keyIt.hasNext()) {
        IgniteTxKey key = keyIt.next();

        key.finishUnmarshal(ctx.cacheContext(key.cacheId()), ldr);

        dhtVers.put(key, verIt.next());
      }
    }

    if (txNodesBytes != null) txNodes = ctx.marshaller().unmarshal(txNodesBytes, ldr);
  }
  /**
   * @param key Key to add to read set.
   * @param val Value.
   * @param drVer Data center replication version.
   * @param skipStore Skip store flag.
   * @throws IgniteCheckedException If failed.
   * @return {@code True} if entry has been enlisted.
   */
  public boolean addEntry(
      GridCacheContext cacheCtx,
      IgniteTxKey key,
      GridCacheOperation op,
      CacheObject val,
      @Nullable GridCacheVersion drVer,
      boolean skipStore)
      throws IgniteCheckedException {
    checkInternal(key);

    GridNearCacheEntry cached = cacheCtx.near().peekExx(key.key());

    try {
      if (cached == null) {
        evicted.add(key);

        return false;
      } else {
        cached.unswap();

        CacheObject peek = cached.peek(true, false, false, null);

        if (peek == null && cached.evictInternal(false, xidVer, null)) {
          cached.context().cache().removeIfObsolete(key.key());

          evicted.add(key);

          return false;
        } else {
          IgniteTxEntry txEntry =
              new IgniteTxEntry(cacheCtx, this, op, val, -1L, -1L, cached, drVer, skipStore);

          writeMap.put(key, txEntry);

          return true;
        }
      }
    } catch (GridCacheEntryRemovedException ignore) {
      evicted.add(key);

      if (log.isDebugEnabled())
        log.debug(
            "Got removed entry when adding reads to remote transaction (will ignore): " + cached);

      return false;
    }
  }
  /**
   * {@inheritDoc}
   *
   * @param ctx
   */
  @Override
  public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException {
    super.prepareMarshal(ctx);

    if (writes != null) marshalTx(writes, ctx);

    if (reads != null) marshalTx(reads, ctx);

    if (grpLockKey != null && grpLockKeyBytes == null)
      grpLockKeyBytes = ctx.marshaller().marshal(grpLockKey);

    if (dhtVers != null) {
      for (IgniteTxKey key : dhtVers.keySet()) {
        GridCacheContext cctx = ctx.cacheContext(key.cacheId());

        key.prepareMarshal(cctx);
      }

      dhtVerKeys = dhtVers.keySet();
      dhtVerVals = dhtVers.values();
    }

    if (txNodes != null) txNodesBytes = ctx.marshaller().marshal(txNodes);
  }