/** @throws Exception If failed. */
  public void testRanges() throws Exception {
    IgfsFileMap map = new IgfsFileMap();

    IgniteUuid[] affKeys = new IgniteUuid[20];

    for (int i = 0; i < affKeys.length; i++) affKeys[i] = IgniteUuid.randomUuid();

    int numOfRanges = 0;

    do {
      for (int i = 0; i < 2 * numOfRanges + 1; i++) {
        long off1 = i * 10;
        long off2 = i * 10 + 5;
        long off3 = i * 10 + 8;

        IgniteUuid affKey = i % 2 == 0 ? null : affKeys[i / 2];

        assertEquals("For i: " + i, affKey, map.affinityKey(off1, false));
        assertEquals("For i: " + i, affKey, map.affinityKey(off2, false));
        assertEquals("For i: " + i, affKey, map.affinityKey(off3, false));
      }

      map.addRange(
          new IgfsFileAffinityRange(
              10 + 20 * numOfRanges, 19 + 20 * numOfRanges, affKeys[numOfRanges]));

      numOfRanges++;
    } while (numOfRanges < 20);
  }
  /** @param m Mapping. */
  private void finish(GridDistributedTxMapping m) {
    ClusterNode n = m.node();

    assert !m.empty();

    GridNearTxFinishRequest req =
        new GridNearTxFinishRequest(
            futId,
            tx.xidVersion(),
            tx.threadId(),
            commit,
            tx.isInvalidate(),
            tx.system(),
            tx.ioPolicy(),
            tx.syncCommit(),
            tx.syncRollback(),
            m.explicitLock(),
            tx.storeEnabled(),
            tx.topologyVersion(),
            null,
            null,
            null,
            tx.size(),
            tx.subjectId(),
            tx.taskNameHash(),
            tx.activeCachesDeploymentEnabled());

    // If this is the primary node for the keys.
    if (n.isLocal()) {
      req.miniId(IgniteUuid.randomUuid());

      IgniteInternalFuture<IgniteInternalTx> fut = cctx.tm().txHandler().finish(n.id(), tx, req);

      // Add new future.
      if (fut != null) add(fut);
    } else {
      FinishMiniFuture fut = new FinishMiniFuture(m);

      req.miniId(fut.futureId());

      add(fut); // Append new future.

      if (tx.pessimistic()) cctx.tm().beforeFinishRemote(n.id(), tx.threadId());

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

        // If we don't wait for result, then mark future as done.
        if (!isSync() && !m.explicitLock()) fut.onDone();
      } catch (ClusterTopologyCheckedException e) {
        // Remove previous mapping.
        mappings.remove(m.node().id());

        fut.onNodeLeft(n.id());
      } catch (IgniteCheckedException e) {
        // Fail the whole thing.
        fut.onDone(e);
      }
    }
  }
Пример #3
0
  /**
   * Starts multi-update lock. Will wait for topology future is ready.
   *
   * @return Topology version.
   * @throws IgniteCheckedException If failed.
   */
  public AffinityTopologyVersion beginMultiUpdate() throws IgniteCheckedException {
    IgniteBiTuple<IgniteUuid, GridDhtTopologyFuture> tup = multiTxHolder.get();

    if (tup != null)
      throw new IgniteCheckedException("Nested multi-update locks are not supported");

    top.readLock();

    GridDhtTopologyFuture topFut;

    AffinityTopologyVersion topVer;

    try {
      // While we are holding read lock, register lock future for partition release future.
      IgniteUuid lockId = IgniteUuid.fromUuid(ctx.localNodeId());

      topVer = top.topologyVersion();

      MultiUpdateFuture fut = new MultiUpdateFuture(topVer);

      MultiUpdateFuture old = multiTxFuts.putIfAbsent(lockId, fut);

      assert old == null;

      topFut = top.topologyVersionFuture();

      multiTxHolder.set(F.t(lockId, topFut));
    } finally {
      top.readUnlock();
    }

    topFut.get();

    return topVer;
  }
  private abstract class MinFuture extends GridFutureAdapter<IgniteInternalTx> {
    /** */
    private final IgniteUuid futId = IgniteUuid.randomUuid();

    /**
     * @param nodeId Node ID.
     * @return {@code True} if future processed node failure.
     */
    abstract boolean onNodeLeft(UUID nodeId);

    /** @return Future ID. */
    final IgniteUuid futureId() {
      return futId;
    }
  }
  /**
   * @param cctx Context.
   * @param tx Transaction.
   * @param commit Commit flag.
   */
  public GridNearTxFinishFuture(
      GridCacheSharedContext<K, V> cctx, GridNearTxLocal tx, boolean commit) {
    super(F.<IgniteInternalTx>identityReducer(tx));

    this.cctx = cctx;
    this.tx = tx;
    this.commit = commit;

    ignoreInterrupts(true);

    mappings = tx.mappings();

    futId = IgniteUuid.randomUuid();

    if (log == null) log = U.logger(cctx.kernalContext(), logRef, GridNearTxFinishFuture.class);
  }
  /** @throws Exception If failed. */
  public void testRangeSplit() throws Exception {
    IgniteUuid affKey = IgniteUuid.randomUuid();

    IgfsFileAffinityRange range = new IgfsFileAffinityRange(0, 9999, affKey);

    Collection<IgfsFileAffinityRange> split = range.split(10000);

    assertEquals(1, split.size());
    assertTrue(range.regionEqual(F.first(split)));

    split = range.split(5000);

    assertEquals(2, split.size());

    Iterator<IgfsFileAffinityRange> it = split.iterator();

    IgfsFileAffinityRange part = it.next();

    assertTrue(part.regionEqual(new IgfsFileAffinityRange(0, 4999, affKey)));

    part = it.next();

    assertTrue(part.regionEqual(new IgfsFileAffinityRange(5000, 9999, affKey)));

    split = range.split(3000);

    assertEquals(4, split.size());

    it = split.iterator();

    part = it.next();

    assertTrue(part.regionEqual(new IgfsFileAffinityRange(0, 2999, affKey)));

    part = it.next();

    assertTrue(part.regionEqual(new IgfsFileAffinityRange(3000, 5999, affKey)));

    part = it.next();

    assertTrue(part.regionEqual(new IgfsFileAffinityRange(6000, 8999, affKey)));

    part = it.next();

    assertTrue(part.regionEqual(new IgfsFileAffinityRange(9000, 9999, affKey)));
  }
Пример #7
0
  /**
   * @param cctx Context.
   * @param tx Transaction.
   * @param commit Commit flag.
   */
  public GridDhtTxFinishFuture(
      GridCacheSharedContext<K, V> cctx, GridDhtTxLocalAdapter tx, boolean commit) {
    super(F.<IgniteInternalTx>identityReducer(tx));

    this.cctx = cctx;
    this.tx = tx;
    this.commit = commit;

    dhtMap = tx.dhtMap();
    nearMap = tx.nearMap();

    futId = IgniteUuid.randomUuid();

    if (log == null) {
      msgLog = cctx.txFinishMessageLogger();
      log = U.logger(cctx.kernalContext(), logRef, GridDhtTxFinishFuture.class);
    }
  }
  /** @throws Exception If failed. */
  public void testRangeUpdate1() throws Exception {
    IgfsFileMap map = new IgfsFileMap();

    IgniteUuid affKey = IgniteUuid.randomUuid();

    for (int i = 0; i < 4; i++)
      map.addRange(new IgfsFileAffinityRange(i * 20 + 10, i * 20 + 19, affKey));

    // Middle, first, last.
    map.updateRangeStatus(new IgfsFileAffinityRange(30, 39, affKey), RANGE_STATUS_MOVING);
    map.updateRangeStatus(new IgfsFileAffinityRange(10, 19, affKey), RANGE_STATUS_MOVING);
    map.updateRangeStatus(new IgfsFileAffinityRange(70, 79, affKey), RANGE_STATUS_MOVING);

    List<IgfsFileAffinityRange> ranges = map.ranges();

    assertEquals(RANGE_STATUS_MOVING, ranges.get(0).status());
    assertEquals(RANGE_STATUS_MOVING, ranges.get(1).status());
    assertEquals(RANGE_STATUS_INITIAL, ranges.get(2).status());
    assertEquals(RANGE_STATUS_MOVING, ranges.get(3).status());

    // Middle, first, last.
    map.updateRangeStatus(new IgfsFileAffinityRange(30, 39, affKey), RANGE_STATUS_MOVED);
    map.updateRangeStatus(new IgfsFileAffinityRange(10, 19, affKey), RANGE_STATUS_MOVED);
    map.updateRangeStatus(new IgfsFileAffinityRange(70, 79, affKey), RANGE_STATUS_MOVED);

    ranges = map.ranges();

    assertEquals(RANGE_STATUS_MOVED, ranges.get(0).status());
    assertEquals(RANGE_STATUS_MOVED, ranges.get(1).status());
    assertEquals(RANGE_STATUS_INITIAL, ranges.get(2).status());
    assertEquals(RANGE_STATUS_MOVED, ranges.get(3).status());

    // Middle, first, last.
    map.deleteRange(new IgfsFileAffinityRange(30, 39, affKey));
    map.deleteRange(new IgfsFileAffinityRange(10, 19, affKey));
    map.deleteRange(new IgfsFileAffinityRange(70, 79, affKey));

    ranges = map.ranges();

    assertEquals(1, ranges.size());
    assertEquals(RANGE_STATUS_INITIAL, ranges.get(0).status());
    assertTrue(ranges.get(0).regionEqual(new IgfsFileAffinityRange(50, 59, affKey)));
  }
  /** @throws Exception If failed. */
  public void testAddUpdateAdd() throws Exception {
    IgfsFileMap map = new IgfsFileMap();

    IgniteUuid affKey = IgniteUuid.randomUuid();

    map.addRange(new IgfsFileAffinityRange(0, 9, affKey));

    map.updateRangeStatus(new IgfsFileAffinityRange(0, 9, affKey), RANGE_STATUS_MOVING);

    map.addRange(new IgfsFileAffinityRange(10, 19, affKey));

    List<IgfsFileAffinityRange> ranges = map.ranges();

    assertEquals(2, ranges.size());

    assertEquals(RANGE_STATUS_MOVING, ranges.get(0).status());
    assertTrue(ranges.get(0).regionEqual(new IgfsFileAffinityRange(0, 9, affKey)));

    assertEquals(RANGE_STATUS_INITIAL, ranges.get(1).status());
    assertTrue(ranges.get(1).regionEqual(new IgfsFileAffinityRange(10, 19, affKey)));
  }
  /**
   * Mini-future for get operations. Mini-futures are only waiting on a single node as opposed to
   * multiple nodes.
   */
  private class MiniFuture extends GridFutureAdapter<Map<K, V>> {
    /** */
    private static final long serialVersionUID = 0L;

    /** */
    private final IgniteUuid futId = IgniteUuid.randomUuid();

    /** Node ID. */
    private final ClusterNode node;

    /** Keys. */
    @GridToStringInclude private final LinkedHashMap<KeyCacheObject, Boolean> keys;

    /** Topology version on which this future was mapped. */
    private final AffinityTopologyVersion topVer;

    /** {@code True} if remapped after node left. */
    private boolean remapped;

    /**
     * @param node Node.
     * @param keys Keys.
     * @param topVer Topology version.
     */
    MiniFuture(
        ClusterNode node,
        LinkedHashMap<KeyCacheObject, Boolean> keys,
        AffinityTopologyVersion topVer) {
      this.node = node;
      this.keys = keys;
      this.topVer = topVer;
    }

    /** @return Future ID. */
    IgniteUuid futureId() {
      return futId;
    }

    /** @return Node ID. */
    public ClusterNode node() {
      return node;
    }

    /** @return Keys. */
    public Collection<KeyCacheObject> keys() {
      return keys.keySet();
    }

    /** @param e Error. */
    void onResult(Throwable e) {
      if (log.isDebugEnabled())
        log.debug("Failed to get future result [fut=" + this + ", err=" + e + ']');

      // Fail.
      onDone(e);
    }

    /** @param e Failure exception. */
    @SuppressWarnings("UnusedParameters")
    synchronized void onNodeLeft(ClusterTopologyCheckedException e) {
      if (remapped) return;

      remapped = true;

      if (log.isDebugEnabled())
        log.debug("Remote node left grid while sending or waiting for reply (will retry): " + this);

      // Try getting from existing nodes.
      if (!canRemap) {
        map(keys.keySet(), F.t(node, keys), topVer);

        onDone(Collections.<K, V>emptyMap());
      } else {
        final AffinityTopologyVersion updTopVer =
            new AffinityTopologyVersion(
                Math.max(topVer.topologyVersion() + 1, cctx.discovery().topologyVersion()));

        cctx.affinity()
            .affinityReadyFuture(updTopVer)
            .listen(
                new CI1<IgniteInternalFuture<AffinityTopologyVersion>>() {
                  @Override
                  public void apply(IgniteInternalFuture<AffinityTopologyVersion> fut) {
                    try {
                      fut.get();

                      // Remap.
                      map(keys.keySet(), F.t(node, keys), updTopVer);

                      onDone(Collections.<K, V>emptyMap());
                    } catch (IgniteCheckedException e) {
                      GridPartitionedGetFuture.this.onDone(e);
                    }
                  }
                });
      }
    }

    /** @param res Result callback. */
    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
    void onResult(final GridNearGetResponse res) {
      final Collection<Integer> invalidParts = res.invalidPartitions();

      // If error happened on remote node, fail the whole future.
      if (res.error() != null) {
        onDone(res.error());

        return;
      }

      // Remap invalid partitions.
      if (!F.isEmpty(invalidParts)) {
        AffinityTopologyVersion rmtTopVer = res.topologyVersion();

        assert !rmtTopVer.equals(AffinityTopologyVersion.ZERO);

        if (rmtTopVer.compareTo(topVer) <= 0) {
          // Fail the whole get future.
          onDone(
              new IgniteCheckedException(
                  "Failed to process invalid partitions response (remote node reported "
                      + "invalid partitions but remote topology version does not differ from local) "
                      + "[topVer="
                      + topVer
                      + ", rmtTopVer="
                      + rmtTopVer
                      + ", invalidParts="
                      + invalidParts
                      + ", nodeId="
                      + node.id()
                      + ']'));

          return;
        }

        if (log.isDebugEnabled())
          log.debug(
              "Remapping mini get future [invalidParts=" + invalidParts + ", fut=" + this + ']');

        if (!canRemap) {
          map(
              F.view(
                  keys.keySet(),
                  new P1<KeyCacheObject>() {
                    @Override
                    public boolean apply(KeyCacheObject key) {
                      return invalidParts.contains(cctx.affinity().partition(key));
                    }
                  }),
              F.t(node, keys),
              topVer);

          onDone(createResultMap(res.entries()));

          return;
        }

        // Need to wait for next topology version to remap.
        IgniteInternalFuture<AffinityTopologyVersion> topFut =
            cctx.affinity().affinityReadyFuture(rmtTopVer);

        topFut.listen(
            new CIX1<IgniteInternalFuture<AffinityTopologyVersion>>() {
              @SuppressWarnings("unchecked")
              @Override
              public void applyx(IgniteInternalFuture<AffinityTopologyVersion> fut)
                  throws IgniteCheckedException {
                AffinityTopologyVersion topVer = fut.get();

                // This will append new futures to compound list.
                map(
                    F.view(
                        keys.keySet(),
                        new P1<KeyCacheObject>() {
                          @Override
                          public boolean apply(KeyCacheObject key) {
                            return invalidParts.contains(cctx.affinity().partition(key));
                          }
                        }),
                    F.t(node, keys),
                    topVer);

                onDone(createResultMap(res.entries()));
              }
            });
      } else {
        try {
          onDone(createResultMap(res.entries()));
        } catch (Exception e) {
          onDone(e);
        }
      }
    }

    /** {@inheritDoc} */
    @Override
    public String toString() {
      return S.toString(MiniFuture.class, this);
    }
  }
  /** @throws Exception If failed. */
  public void testInvalidRangeUpdates() throws Exception {
    final IgfsFileMap map = new IgfsFileMap();

    final IgniteUuid affKey1 = IgniteUuid.randomUuid();
    final IgniteUuid affKey2 = IgniteUuid.randomUuid();

    map.addRange(new IgfsFileAffinityRange(10, 19, affKey1));
    map.addRange(new IgfsFileAffinityRange(30, 39, affKey1));

    GridTestUtils.assertThrows(
        log,
        new Callable<Object>() {
          @Override
          public Object call() throws Exception {
            map.updateRangeStatus(new IgfsFileAffinityRange(0, 5, affKey1), RANGE_STATUS_MOVING);

            return null;
          }
        },
        IgfsInvalidRangeException.class,
        null);

    GridTestUtils.assertThrows(
        log,
        new Callable<Object>() {
          @Override
          public Object call() throws Exception {
            map.updateRangeStatus(new IgfsFileAffinityRange(15, 19, affKey1), RANGE_STATUS_MOVING);

            return null;
          }
        },
        IgfsInvalidRangeException.class,
        null);

    GridTestUtils.assertThrows(
        log,
        new Callable<Object>() {
          @Override
          public Object call() throws Exception {
            map.updateRangeStatus(new IgfsFileAffinityRange(10, 19, affKey2), RANGE_STATUS_MOVING);

            return null;
          }
        },
        AssertionError.class,
        null);

    GridTestUtils.assertThrows(
        log,
        new Callable<Object>() {
          @Override
          public Object call() throws Exception {
            map.updateRangeStatus(new IgfsFileAffinityRange(10, 22, affKey1), RANGE_STATUS_MOVING);

            return null;
          }
        },
        AssertionError.class,
        null);

    assertEquals(2, map.ranges().size());
  }
Пример #12
0
  /**
   * Prepares next batch of entries in dht transaction.
   *
   * @param reads Read entries.
   * @param writes Write entries.
   * @param txNodes Transaction nodes mapping.
   * @param last {@code True} if this is last prepare request.
   * @return Future that will be completed when locks are acquired.
   */
  @SuppressWarnings("TypeMayBeWeakened")
  public IgniteInternalFuture<GridNearTxPrepareResponse> prepareAsyncLocal(
      @Nullable Collection<IgniteTxEntry> reads,
      @Nullable Collection<IgniteTxEntry> writes,
      Map<UUID, Collection<UUID>> txNodes,
      boolean last) {
    if (state() != PREPARING) {
      if (timedOut())
        return new GridFinishedFuture<>(
            new IgniteTxTimeoutCheckedException("Transaction timed out: " + this));

      setRollbackOnly();

      return new GridFinishedFuture<>(
          new IgniteCheckedException(
              "Invalid transaction state for prepare [state=" + state() + ", tx=" + this + ']'));
    }

    init();

    GridDhtTxPrepareFuture fut =
        new GridDhtTxPrepareFuture(
            cctx,
            this,
            IgniteUuid.randomUuid(),
            Collections.<IgniteTxKey, GridCacheVersion>emptyMap(),
            last,
            needReturnValue() && implicit());

    try {
      // At this point all the entries passed in must be enlisted in transaction because this is an
      // optimistic transaction.
      optimisticLockEntries =
          (serializable() && optimistic()) ? F.concat(false, writes, reads) : writes;

      userPrepare();

      // Make sure to add future before calling prepare on it.
      cctx.mvcc().addFuture(fut);

      if (isSystemInvalidate()) fut.complete();
      else fut.prepare(reads, writes, txNodes);
    } catch (IgniteTxTimeoutCheckedException | IgniteTxOptimisticCheckedException e) {
      fut.onError(e);
    } catch (IgniteCheckedException e) {
      setRollbackOnly();

      fut.onError(
          new IgniteTxRollbackCheckedException("Failed to prepare transaction: " + this, e));

      try {
        rollback();
      } catch (IgniteTxOptimisticCheckedException e1) {
        if (log.isDebugEnabled())
          log.debug("Failed optimistically to prepare transaction [tx=" + this + ", e=" + e1 + ']');

        fut.onError(e);
      } catch (IgniteCheckedException e1) {
        U.error(log, "Failed to rollback transaction: " + this, e1);
      }
    }

    return chainOnePhasePrepare(fut);
  }
 /** {@inheritDoc} */
 @Override
 public boolean equals(Object o) {
   return o == this
       || o instanceof GridDeploymentInfoBean
           && clsLdrId.equals(((GridDeploymentInfoBean) o).clsLdrId);
 }
 /** {@inheritDoc} */
 @Override
 public int hashCode() {
   return clsLdrId.hashCode();
 }
 /** {@inheritDoc} */
 @Override
 public long sequenceNumber() {
   return clsLdrId.localId();
 }
Пример #16
0
  /**
   * Mini-future for get operations. Mini-futures are only waiting on a single node as opposed to
   * multiple nodes.
   */
  private class MiniFuture extends GridFutureAdapter<IgniteInternalTx> {
    /** */
    private static final long serialVersionUID = 0L;

    /** */
    private final IgniteUuid futId = IgniteUuid.randomUuid();

    /** DHT mapping. */
    @GridToStringInclude private GridDistributedTxMapping dhtMapping;

    /** Near mapping. */
    @GridToStringInclude private GridDistributedTxMapping nearMapping;

    /** */
    @GridToStringInclude private ClusterNode node;

    /** @param node Node. */
    private MiniFuture(ClusterNode node) {
      this.node = node;
    }

    /**
     * @param dhtMapping Mapping.
     * @param nearMapping nearMapping.
     */
    MiniFuture(GridDistributedTxMapping dhtMapping, GridDistributedTxMapping nearMapping) {
      assert dhtMapping == null
          || nearMapping == null
          || dhtMapping.node().equals(nearMapping.node());

      this.dhtMapping = dhtMapping;
      this.nearMapping = nearMapping;
    }

    /** @return Future ID. */
    IgniteUuid futureId() {
      return futId;
    }

    /** @return Node ID. */
    public ClusterNode node() {
      return node != null ? node : dhtMapping != null ? dhtMapping.node() : nearMapping.node();
    }

    /** @param e Error. */
    void onResult(Throwable e) {
      if (log.isDebugEnabled())
        log.debug("Failed to get future result [fut=" + this + ", err=" + e + ']');

      // Fail.
      onDone(e);
    }

    /** @param e Node failure. */
    void onNodeLeft(ClusterTopologyCheckedException e) {
      onNodeLeft(e, false);
    }

    /**
     * @param e Node failure.
     * @param discoThread {@code True} if executed from discovery thread.
     */
    void onNodeLeft(ClusterTopologyCheckedException e, boolean discoThread) {
      if (msgLog.isDebugEnabled()) {
        msgLog.debug(
            "DHT finish fut, mini future node left [txId="
                + tx.nearXidVersion()
                + ", dhtTxId="
                + tx.xidVersion()
                + ", node="
                + node().id()
                + ']');
      }

      // If node left, then there is nothing to commit on it.
      onDone(tx);
    }

    /** @param res Result callback. */
    void onResult(GridDhtTxFinishResponse res) {
      if (log.isDebugEnabled())
        log.debug(
            "Transaction synchronously completed on node [node=" + node() + ", res=" + res + ']');

      onDone();
    }

    /** {@inheritDoc} */
    @Override
    public String toString() {
      return S.toString(
          MiniFuture.class, this, "done", isDone(), "cancelled", isCancelled(), "err", error());
    }
  }