예제 #1
0
  /**
   * Adds key mapping to dht mapping.
   *
   * @param key Key to add.
   * @param node Node this key mapped to.
   */
  public void addKeyMapping(IgniteTxKey key, ClusterNode node) {
    GridDistributedTxMapping m = mappings.get(node.id());

    if (m == null) mappings.put(m = new GridDistributedTxMapping(node));

    IgniteTxEntry txEntry = entry(key);

    assert txEntry != null;

    txEntry.nodeId(node.id());

    m.add(txEntry);

    if (log.isDebugEnabled())
      log.debug(
          "Added mappings to transaction [locId="
              + cctx.localNodeId()
              + ", key="
              + key
              + ", node="
              + node
              + ", tx="
              + this
              + ']');
  }
예제 #2
0
  /**
   * Adds entries to started near remote tx.
   *
   * @param ldr Class loader.
   * @param entries Entries to add.
   * @throws IgniteCheckedException If failed.
   */
  public void addEntries(ClassLoader ldr, Iterable<IgniteTxEntry> entries)
      throws IgniteCheckedException {
    for (IgniteTxEntry entry : entries) {
      entry.unmarshal(cctx, true, ldr);

      addEntry(entry);
    }
  }
예제 #3
0
  /**
   * This constructor is meant for optimistic transactions.
   *
   * @param ldr Class loader.
   * @param nodeId Node ID.
   * @param nearNodeId Near node ID.
   * @param rmtThreadId Remote thread ID.
   * @param xidVer XID version.
   * @param commitVer Commit version.
   * @param sys System flag.
   * @param concurrency Concurrency level (should be pessimistic).
   * @param isolation Transaction isolation.
   * @param invalidate Invalidate flag.
   * @param timeout Timeout.
   * @param writeEntries Write entries.
   * @param ctx Cache registry.
   * @param txSize Expected transaction size.
   * @throws IgniteCheckedException If unmarshalling failed.
   */
  public GridNearTxRemote(
      GridCacheSharedContext ctx,
      ClassLoader ldr,
      UUID nodeId,
      UUID nearNodeId,
      long rmtThreadId,
      GridCacheVersion xidVer,
      GridCacheVersion commitVer,
      boolean sys,
      byte plc,
      TransactionConcurrency concurrency,
      TransactionIsolation isolation,
      boolean invalidate,
      long timeout,
      Collection<IgniteTxEntry> writeEntries,
      int txSize,
      @Nullable UUID subjId,
      int taskNameHash)
      throws IgniteCheckedException {
    super(
        ctx,
        nodeId,
        rmtThreadId,
        xidVer,
        commitVer,
        sys,
        plc,
        concurrency,
        isolation,
        invalidate,
        timeout,
        txSize,
        subjId,
        taskNameHash);

    assert nearNodeId != null;

    this.nearNodeId = nearNodeId;

    readMap = Collections.emptyMap();

    writeMap =
        new LinkedHashMap<>(
            writeEntries != null ? Math.max(txSize, writeEntries.size()) : txSize, 1.0f);

    if (writeEntries != null) {
      for (IgniteTxEntry entry : writeEntries) {
        entry.unmarshal(ctx, true, ldr);

        addEntry(entry);
      }
    }
  }
예제 #4
0
  /** {@inheritDoc} */
  @Override
  protected GridCacheEntryEx entryEx(GridCacheContext cacheCtx, IgniteTxKey key) {
    if (cacheCtx.isColocated()) {
      IgniteTxEntry txEntry = entry(key);

      if (txEntry == null) return cacheCtx.colocated().entryExx(key.key(), topologyVersion(), true);

      GridCacheEntryEx cached = txEntry.cached();

      assert cached != null;

      if (cached.detached()) return cached;

      if (cached.obsoleteVersion() != null) {
        cached = cacheCtx.colocated().entryExx(key.key(), topologyVersion(), true);

        txEntry.cached(cached);
      }

      return cached;
    } else return cacheCtx.cache().entryEx(key.key());
  }
예제 #5
0
  /** {@inheritDoc} */
  @Override
  protected void updateExplicitVersion(IgniteTxEntry txEntry, GridCacheEntryEx entry)
      throws GridCacheEntryRemovedException {
    if (entry.detached()) {
      GridCacheMvccCandidate cand = cctx.mvcc().explicitLock(threadId(), entry.txKey());

      if (cand != null && !xidVersion().equals(cand.version())) {
        GridCacheVersion candVer = cand.version();

        txEntry.explicitVersion(candVer);

        if (candVer.isLess(minVer)) minVer = candVer;
      }
    } else super.updateExplicitVersion(txEntry, entry);
  }
예제 #6
0
  /**
   * @param entry Entry to enlist.
   * @throws IgniteCheckedException If failed.
   * @return {@code True} if entry was enlisted.
   */
  private boolean addEntry(IgniteTxEntry entry) throws IgniteCheckedException {
    checkInternal(entry.txKey());

    GridCacheContext cacheCtx = entry.context();

    if (!cacheCtx.isNear()) cacheCtx = cacheCtx.dht().near().context();

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

    if (cached == null) {
      evicted.add(entry.txKey());

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

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

        if (val == null && cached.evictInternal(false, xidVer, null)) {
          evicted.add(entry.txKey());

          return false;
        } else {
          // Initialize cache entry.
          entry.cached(cached);

          txState.addWriteEntry(entry.txKey(), entry);

          addExplicit(entry);

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

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

        return false;
      }
    }
  }
예제 #7
0
  /**
   * @param entries Entries.
   * @param dhtVer DHT version.
   * @param pendingVers Pending versions.
   * @param committedVers Committed versions.
   * @param rolledbackVers Rolled back versions.
   */
  void readyNearLocks(
      Collection<IgniteTxEntry> entries,
      GridCacheVersion dhtVer,
      Collection<GridCacheVersion> pendingVers,
      Collection<GridCacheVersion> committedVers,
      Collection<GridCacheVersion> rolledbackVers) {
    for (IgniteTxEntry txEntry : entries) {
      while (true) {
        GridCacheContext cacheCtx = txEntry.cached().context();

        assert cacheCtx.isNear();

        GridDistributedCacheEntry entry = (GridDistributedCacheEntry) txEntry.cached();

        try {
          // Handle explicit locks.
          GridCacheVersion explicit = txEntry.explicitVersion();

          if (explicit == null) {
            entry.readyNearLock(xidVer, dhtVer, committedVers, rolledbackVers, pendingVers);
          }

          break;
        } catch (GridCacheEntryRemovedException ignored) {
          assert entry.obsoleteVersion() != null;

          if (log.isDebugEnabled())
            log.debug(
                "Replacing obsolete entry in remote transaction [entry="
                    + entry
                    + ", tx="
                    + this
                    + ']');

          // Replace the entry.
          txEntry.cached(txEntry.context().cache().entryEx(txEntry.key()));
        }
      }
    }
  }
  /** {@inheritDoc} */
  @Override
  public boolean onDone(IgniteInternalTx tx0, Throwable err) {
    if (isDone()) return false;

    synchronized (this) {
      if (isDone()) return false;

      if (err != null) {
        tx.commitError(err);

        boolean marked = tx.setRollbackOnly();

        if (err instanceof IgniteTxRollbackCheckedException) {
          if (marked) {
            try {
              tx.rollback();
            } catch (IgniteCheckedException ex) {
              U.error(log, "Failed to automatically rollback transaction: " + tx, ex);
            }
          }
        } else if (tx.implicit()
            && tx.isSystemInvalidate()) { // Finish implicit transaction on heuristic error.
          try {
            tx.close();
          } catch (IgniteCheckedException ex) {
            U.error(log, "Failed to invalidate transaction: " + tx, ex);
          }
        }
      }

      if (initialized() || err != null) {
        if (tx.needCheckBackup()) {
          assert tx.onePhaseCommit();

          if (err != null)
            err = new TransactionRollbackException("Failed to commit transaction.", err);

          try {
            tx.finish(err == null);
          } catch (IgniteCheckedException e) {
            if (err != null) err.addSuppressed(e);
            else err = e;
          }
        }

        if (tx.onePhaseCommit()) {
          boolean commit = this.commit && err == null;

          finishOnePhase(commit);

          tx.tmFinish(commit);
        }

        if (super.onDone(tx0, err)) {
          if (error() instanceof IgniteTxHeuristicCheckedException) {
            AffinityTopologyVersion topVer = tx.topologyVersion();

            for (IgniteTxEntry e : tx.writeMap().values()) {
              GridCacheContext cacheCtx = e.context();

              try {
                if (e.op() != NOOP && !cacheCtx.affinity().localNode(e.key(), topVer)) {
                  GridCacheEntryEx entry = cacheCtx.cache().peekEx(e.key());

                  if (entry != null) entry.invalidate(null, tx.xidVersion());
                }
              } catch (Throwable t) {
                U.error(log, "Failed to invalidate entry.", t);

                if (t instanceof Error) throw (Error) t;
              }
            }
          }

          // Don't forget to clean up.
          cctx.mvcc().removeFuture(futId);

          return true;
        }
      }
    }

    return false;
  }
예제 #9
0
  /**
   * @param dhtMap DHT map.
   * @param nearMap Near map.
   * @return {@code True} in case there is at least one synchronous {@code MiniFuture} to wait for.
   */
  private boolean finish(
      Map<UUID, GridDistributedTxMapping> dhtMap, Map<UUID, GridDistributedTxMapping> nearMap) {
    if (tx.onePhaseCommit()) return false;

    boolean sync = tx.syncMode() == FULL_SYNC;

    if (tx.explicitLock()) sync = true;

    boolean res = false;

    // Create mini futures.
    for (GridDistributedTxMapping dhtMapping : dhtMap.values()) {
      ClusterNode n = dhtMapping.node();

      assert !n.isLocal();

      GridDistributedTxMapping nearMapping = nearMap.get(n.id());

      if (dhtMapping.empty() && nearMapping != null && nearMapping.empty())
        // Nothing to send.
        continue;

      MiniFuture fut = new MiniFuture(dhtMapping, nearMapping);

      add(fut); // Append new future.

      Collection<Long> updCntrs = new ArrayList<>(dhtMapping.entries().size());

      for (IgniteTxEntry e : dhtMapping.entries()) updCntrs.add(e.updateCounter());

      GridDhtTxFinishRequest req =
          new GridDhtTxFinishRequest(
              tx.nearNodeId(),
              futId,
              fut.futureId(),
              tx.topologyVersion(),
              tx.xidVersion(),
              tx.commitVersion(),
              tx.threadId(),
              tx.isolation(),
              commit,
              tx.isInvalidate(),
              tx.system(),
              tx.ioPolicy(),
              tx.isSystemInvalidate(),
              sync,
              sync,
              tx.completedBase(),
              tx.committedVersions(),
              tx.rolledbackVersions(),
              tx.pendingVersions(),
              tx.size(),
              tx.subjectId(),
              tx.taskNameHash(),
              tx.activeCachesDeploymentEnabled(),
              updCntrs,
              false,
              false);

      req.writeVersion(tx.writeVersion() != null ? tx.writeVersion() : tx.xidVersion());

      try {
        cctx.io().send(n, req, tx.ioPolicy());

        if (msgLog.isDebugEnabled()) {
          msgLog.debug(
              "DHT finish fut, sent request dht [txId="
                  + tx.nearXidVersion()
                  + ", dhtTxId="
                  + tx.xidVersion()
                  + ", node="
                  + n.id()
                  + ']');
        }

        if (sync) res = true;
        else fut.onDone();
      } catch (IgniteCheckedException e) {
        // Fail the whole thing.
        if (e instanceof ClusterTopologyCheckedException)
          fut.onNodeLeft((ClusterTopologyCheckedException) e);
        else {
          if (msgLog.isDebugEnabled()) {
            msgLog.debug(
                "DHT finish fut, failed to send request dht [txId="
                    + tx.nearXidVersion()
                    + ", dhtTxId="
                    + tx.xidVersion()
                    + ", node="
                    + n.id()
                    + ", err="
                    + e
                    + ']');
          }

          fut.onResult(e);
        }
      }
    }

    for (GridDistributedTxMapping nearMapping : nearMap.values()) {
      if (!dhtMap.containsKey(nearMapping.node().id())) {
        if (nearMapping.empty())
          // Nothing to send.
          continue;

        MiniFuture fut = new MiniFuture(null, nearMapping);

        add(fut); // Append new future.

        GridDhtTxFinishRequest req =
            new GridDhtTxFinishRequest(
                tx.nearNodeId(),
                futId,
                fut.futureId(),
                tx.topologyVersion(),
                tx.xidVersion(),
                tx.commitVersion(),
                tx.threadId(),
                tx.isolation(),
                commit,
                tx.isInvalidate(),
                tx.system(),
                tx.ioPolicy(),
                tx.isSystemInvalidate(),
                sync,
                sync,
                tx.completedBase(),
                tx.committedVersions(),
                tx.rolledbackVersions(),
                tx.pendingVersions(),
                tx.size(),
                tx.subjectId(),
                tx.taskNameHash(),
                tx.activeCachesDeploymentEnabled(),
                false,
                false);

        req.writeVersion(tx.writeVersion());

        try {
          cctx.io().send(nearMapping.node(), req, tx.ioPolicy());

          if (msgLog.isDebugEnabled()) {
            msgLog.debug(
                "DHT finish fut, sent request near [txId="
                    + tx.nearXidVersion()
                    + ", dhtTxId="
                    + tx.xidVersion()
                    + ", node="
                    + nearMapping.node().id()
                    + ']');
          }

          if (sync) res = true;
          else fut.onDone();
        } catch (IgniteCheckedException e) {
          // Fail the whole thing.
          if (e instanceof ClusterTopologyCheckedException)
            fut.onNodeLeft((ClusterTopologyCheckedException) e);
          else {
            if (msgLog.isDebugEnabled()) {
              msgLog.debug(
                  "DHT finish fut, failed to send request near [txId="
                      + tx.nearXidVersion()
                      + ", dhtTxId="
                      + tx.xidVersion()
                      + ", node="
                      + nearMapping.node().id()
                      + ", err="
                      + e
                      + ']');
            }

            fut.onResult(e);
          }
        }
      }
    }

    return res;
  }