Esempio n. 1
0
  /**
   * Completeness callback.
   *
   * @param success {@code True} if lock was acquired.
   * @param distribute {@code True} if need to distribute lock removal in case of failure.
   * @return {@code True} if complete by this operation.
   */
  private boolean onComplete(boolean success, boolean distribute) {
    if (log.isDebugEnabled())
      log.debug(
          "Received onComplete(..) callback [success="
              + success
              + ", distribute="
              + distribute
              + ", fut="
              + this
              + ']');

    if (!success) undoLocks(distribute);

    if (tx != null) cctx.tm().txContext(tx);

    if (super.onDone(success, err.get())) {
      if (log.isDebugEnabled()) log.debug("Completing future: " + this);

      // Clean up.
      cctx.mvcc().removeFuture(this);

      if (timeoutObj != null) cctx.time().removeTimeoutObject(timeoutObj);

      return true;
    }

    return false;
  }
  /** {@inheritDoc} */
  @Override
  public boolean onDone(GridCacheTx tx, Throwable err) {
    if ((initialized() || err != null) && super.onDone(tx, err)) {
      if (error() instanceof GridCacheTxHeuristicException) {
        long topVer = this.tx.topologyVersion();

        for (GridCacheTxEntry<K, V> e : this.tx.writeMap().values()) {
          try {
            if (e.op() != NOOP && !cctx.affinity().localNode(e.key(), topVer)) {
              GridCacheEntryEx<K, V> cacheEntry = cctx.cache().peekEx(e.key());

              if (cacheEntry != null) cacheEntry.invalidate(null, this.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(this);

      return true;
    }

    return false;
  }
  /** @return Nodes to execute on. */
  private Collection<GridNode> nodes() {
    GridCacheMode cacheMode = cctx.config().getCacheMode();

    switch (cacheMode) {
      case LOCAL:
        if (prj != null)
          U.warn(
              log,
              "Ignoring query projection because it's executed over LOCAL cache "
                  + "(only local node will be queried): "
                  + this);

        return Collections.singletonList(cctx.localNode());

      case REPLICATED:
        if (prj != null) return nodes(cctx, prj);

        GridCacheDistributionMode mode = cctx.config().getDistributionMode();

        return mode == PARTITIONED_ONLY || mode == NEAR_PARTITIONED
            ? Collections.singletonList(cctx.localNode())
            : Collections.singletonList(F.rand(nodes(cctx, null)));

      case PARTITIONED:
        return nodes(cctx, prj);

      default:
        throw new IllegalStateException("Unknown cache distribution mode: " + cacheMode);
    }
  }
Esempio n. 4
0
  /**
   * @param mapping Mappings.
   * @param key Key to map.
   * @param topVer Topology version.
   * @return Near lock mapping.
   * @throws GridException If mapping for key failed.
   */
  private GridNearLockMapping<K, V> map(
      K key, @Nullable GridNearLockMapping<K, V> mapping, long topVer) throws GridException {
    assert mapping == null || mapping.node() != null;

    GridNode primary = cctx.affinity().primary(key, topVer);

    if (cctx.discovery().node(primary.id()) == null)
      // If primary node left the grid before lock acquisition, fail the whole future.
      throw newTopologyException(null, primary.id());

    if (inTx() && tx.groupLock() && !primary.isLocal())
      throw new GridException(
          "Failed to start group lock transaction (local node is not primary for "
              + " key) [key="
              + key
              + ", primaryNodeId="
              + primary.id()
              + ']');

    if (mapping == null || !primary.id().equals(mapping.node().id()))
      mapping = new GridNearLockMapping<>(primary, key);
    else mapping.addKey(key);

    return mapping;
  }
  /**
   * @param rmtReducer Optional reducer.
   * @param rmtTransform Optional transformer.
   * @param args Arguments.
   * @return Future.
   */
  @SuppressWarnings("IfMayBeConditional")
  private <R> GridCacheQueryFuture<R> execute(
      @Nullable GridReducer<T, R> rmtReducer,
      @Nullable GridClosure<T, R> rmtTransform,
      @Nullable Object... args) {
    Collection<GridNode> nodes = nodes();

    cctx.checkSecurity(GridSecurityPermission.CACHE_READ);

    if (F.isEmpty(nodes))
      return new GridCacheQueryErrorFuture<>(
          cctx.kernalContext(),
          new GridEmptyProjectionException("There are no data nodes for cache: " + cctx.namexx()));

    if (log.isDebugEnabled())
      log.debug("Executing query [query=" + this + ", nodes=" + nodes + ']');

    if (cctx.deploymentEnabled()) {
      try {
        cctx.deploy().registerClasses(filter, rmtReducer, rmtTransform);
        cctx.deploy().registerClasses(args);
      } catch (GridException e) {
        return new GridCacheQueryErrorFuture<>(cctx.kernalContext(), e);
      }
    }

    if (subjId == null) subjId = cctx.localNodeId();

    taskHash = cctx.kernalContext().job().currentTaskNameHash();

    GridCacheQueryBean bean =
        new GridCacheQueryBean(
            this,
            (GridReducer<Object, Object>) rmtReducer,
            (GridClosure<Object, Object>) rmtTransform,
            args);

    GridCacheQueryManager qryMgr = cctx.queries();

    boolean loc = nodes.size() == 1 && F.first(nodes).id().equals(cctx.localNodeId());

    if (type == SQL_FIELDS)
      return (GridCacheQueryFuture<R>)
          (loc ? qryMgr.queryFieldsLocal(bean) : qryMgr.queryFieldsDistributed(bean, nodes));
    else
      return (GridCacheQueryFuture<R>)
          (loc ? qryMgr.queryLocal(bean) : qryMgr.queryDistributed(bean, nodes));
  }
  /**
   * @param cctx Context.
   * @param type Query type.
   * @param clsName Class name.
   * @param clause Clause.
   * @param filter Scan filter.
   * @param incMeta Include metadata flag.
   * @param keepPortable Keep portable flag.
   * @param prjPred Cache projection filter.
   */
  public GridCacheQueryAdapter(
      GridCacheContext<?, ?> cctx,
      GridCacheQueryType type,
      @Nullable GridPredicate<GridCacheEntry<Object, Object>> prjPred,
      @Nullable String clsName,
      @Nullable String clause,
      @Nullable GridBiPredicate<Object, Object> filter,
      boolean incMeta,
      boolean keepPortable) {
    assert cctx != null;
    assert type != null;

    this.cctx = cctx;
    this.type = type;
    this.clsName = clsName;
    this.clause = clause;
    this.prjPred = prjPred;
    this.filter = filter;
    this.incMeta = incMeta;
    this.keepPortable = keepPortable;

    log = cctx.logger(getClass());

    pageSize = DFLT_PAGE_SIZE;
    timeout = 0;
    keepAll = true;
    incBackups = false;
    dedup = false;
    prj = null;

    metrics = new GridCacheQueryMetricsAdapter();
  }
  /**
   * Constructor.
   *
   * @param name Latch name.
   * @param cnt Current count.
   * @param initCnt Initial count.
   * @param autoDel Auto delete flag.
   * @param key Latch key.
   * @param latchView Latch projection.
   * @param ctx Cache context.
   */
  public GridCacheCountDownLatchImpl(
      String name,
      int cnt,
      int initCnt,
      boolean autoDel,
      GridCacheInternalKey key,
      GridCacheProjection<GridCacheInternalKey, GridCacheCountDownLatchValue> latchView,
      GridCacheContext ctx) {
    assert name != null;
    assert cnt >= 0;
    assert initCnt >= 0;
    assert key != null;
    assert latchView != null;
    assert ctx != null;

    this.name = name;
    this.cnt = cnt;
    this.initCnt = initCnt;
    this.autoDel = autoDel;
    this.key = key;
    this.latchView = latchView;
    this.ctx = ctx;

    log = ctx.gridConfig().getGridLogger().getLogger(getClass());
  }
  /** @param m Mapping. */
  @SuppressWarnings({"unchecked"})
  private void finish(GridDistributedTxMapping<K, V> m) {
    GridRichNode n = m.node();

    assert !m.empty();

    GridNearTxFinishRequest req =
        new GridNearTxFinishRequest<K, V>(
            futId,
            tx.xidVersion(),
            tx.commitVersion(),
            tx.threadId(),
            commit,
            tx.isInvalidate(),
            m.explicitLock(),
            tx.topologyVersion(),
            null,
            null,
            null,
            commit && tx.pessimistic() ? m.writes() : null,
            tx.syncCommit() && commit || tx.syncRollback() && !commit);

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

      if (CU.DHT_ENABLED) {
        GridFuture<GridCacheTx> fut =
            commit ? dht().commitTx(n.id(), req) : dht().rollbackTx(n.id(), req);

        // Add new future.
        add(fut);
      } else
        // Add done future for testing.
        add(new GridFinishedFuture<GridCacheTx>(ctx));
    } else {
      MiniFuture fut = new MiniFuture(m);

      req.miniId(fut.futureId());

      add(fut); // Append new future.

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

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

        fut.onResult(e);
      } catch (GridException e) {
        // Fail the whole thing.
        fut.onResult(e);
      }
    }
  }
  /**
   * @param entry Transaction entry.
   * @param nodes Nodes.
   */
  private void map(GridCacheTxEntry<K, V> entry, Collection<GridRichNode> nodes) {
    GridRichNode primary = CU.primary0(cctx.affinity(entry.key(), nodes));

    GridDistributedTxMapping<K, V> t = mappings.get(primary.id());

    if (t == null) mappings.put(primary.id(), t = new GridDistributedTxMapping<K, V>(primary));

    t.add(entry);
  }
  /** {@inheritDoc} */
  @Override
  public boolean onDone(GridCacheTx tx, Throwable err) {
    if (initialized() && super.onDone(tx, err)) {
      // Don't forget to clean up.
      cctx.mvcc().removeFuture(this);

      return true;
    }

    return false;
  }
Esempio n. 11
0
  /**
   * Undoes all locks.
   *
   * @param dist If {@code true}, then remove locks from remote nodes as well.
   */
  private void undoLocks(boolean dist) {
    // Transactions will undo during rollback.
    if (dist && tx == null) cctx.nearTx().removeLocks(lockVer, keys);
    else {
      if (tx != null) {
        if (tx.setRollbackOnly()) {
          if (log.isDebugEnabled())
            log.debug(
                "Marked transaction as rollback only because locks could not be acquired: " + tx);
        } else if (log.isDebugEnabled())
          log.debug(
              "Transaction was not marked rollback-only while locks were not acquired: " + tx);
      }

      for (GridCacheEntryEx<K, V> e : entriesCopy()) {
        try {
          e.removeLock(lockVer);
        } catch (GridCacheEntryRemovedException ignored) {
          while (true) {
            try {
              e = cctx.cache().peekEx(e.key());

              if (e != null) e.removeLock(lockVer);

              break;
            } catch (GridCacheEntryRemovedException ignore) {
              if (log.isDebugEnabled())
                log.debug(
                    "Attempted to remove lock on removed entry (will retry) [ver="
                        + lockVer
                        + ", entry="
                        + e
                        + ']');
            }
          }
        }
      }
    }

    cctx.mvcc().recheckPendingLocks();
  }
 /** {@inheritDoc} */
 @Override
 public GridFuture<Boolean> awaitAsync(final long timeout, final TimeUnit unit) {
   return ctx.closures()
       .callLocalSafe(
           new Callable<Boolean>() {
             @Override
             public Boolean call() throws Exception {
               return await(timeout, unit);
             }
           },
           true);
 }
  /**
   * @param ctx Cache context.
   * @param topic Topic for ordered messages.
   * @param prjPred Projection predicate.
   */
  GridCacheContinuousQueryAdapter(
      GridCacheContext<K, V> ctx,
      Object topic,
      @Nullable GridPredicate<GridCacheEntry<K, V>> prjPred) {
    assert ctx != null;
    assert topic != null;

    this.ctx = ctx;
    this.topic = topic;
    this.prjPred = prjPred;

    log = ctx.logger(getClass());
  }
  /** {@inheritDoc} */
  @Override
  public void close() throws GridException {
    closeLock.lock();

    try {
      if (routineId == null)
        throw new IllegalStateException("Can't cancel query that was not executed.");

      ctx.kernalContext().continuous().stopRoutine(routineId).get();
    } finally {
      closeLock.unlock();
    }
  }
  /**
   * Default constructor.
   *
   * @param name Sequence name.
   * @param key Sequence key.
   * @param seqView Sequence projection.
   * @param ctx CacheContext.
   * @param locVal Local counter.
   * @param upBound Upper bound.
   */
  public GridCacheAtomicSequenceImpl(
      String name,
      GridCacheInternalStorableKey key,
      GridCacheProjection<GridCacheInternalStorableKey, GridCacheAtomicSequenceValue> seqView,
      GridCacheContext ctx,
      long locVal,
      long upBound) {
    assert key != null;
    assert seqView != null;
    assert ctx != null;
    assert locVal <= upBound;

    batchSize = ctx.config().getAtomicSequenceReserveSize();
    this.ctx = ctx;
    this.key = key;
    this.seqView = seqView;
    this.upBound = upBound;
    this.locVal = locVal;
    this.name = name;

    log = ctx.gridConfig().getGridLogger().getLogger(getClass());
  }
Esempio n. 16
0
  /**
   * @param cctx Registry.
   * @param keys Keys to lock.
   * @param tx Transaction.
   * @param read Read flag.
   * @param retval Flag to return value or not.
   * @param timeout Lock acquisition timeout.
   * @param filter Filter.
   */
  public GridNearLockFuture(
      GridCacheContext<K, V> cctx,
      Collection<? extends K> keys,
      @Nullable GridNearTxLocal<K, V> tx,
      boolean read,
      boolean retval,
      long timeout,
      GridPredicate<GridCacheEntry<K, V>>[] filter) {
    super(cctx.kernalContext(), CU.boolReducer());
    assert cctx != null;
    assert keys != null;

    this.cctx = cctx;
    this.keys = keys;
    this.tx = tx;
    this.read = read;
    this.retval = retval;
    this.timeout = timeout;
    this.filter = filter;

    threadId = tx == null ? Thread.currentThread().getId() : tx.threadId();

    lockVer = tx != null ? tx.xidVersion() : cctx.versions().next();

    futId = GridUuid.randomUuid();

    entries = new ArrayList<>(keys.size());

    log = U.logger(ctx, logRef, GridNearLockFuture.class);

    if (timeout > 0) {
      timeoutObj = new LockTimeoutObject();

      cctx.time().addTimeoutObject(timeoutObj);
    }

    valMap = new ConcurrentHashMap8<>(keys.size(), 1f);
  }
Esempio n. 17
0
  /**
   * Acquires topology future and checks it completeness under the read lock. If it is not complete,
   * will asynchronously wait for it's completeness and then try again.
   */
  void mapOnTopology() {
    // We must acquire topology snapshot from the topology version future.
    try {
      cctx.topology().readLock();

      try {
        GridDhtTopologyFuture fut = cctx.topologyVersionFuture();

        if (fut.isDone()) {
          GridDiscoveryTopologySnapshot snapshot = fut.topologySnapshot();

          if (tx != null) {
            tx.topologyVersion(snapshot.topologyVersion());
            tx.topologySnapshot(snapshot);
          }

          topSnapshot.compareAndSet(null, snapshot);

          map(keys);

          markInitialized();
        } else {
          fut.listenAsync(
              new CI1<GridFuture<Long>>() {
                @Override
                public void apply(GridFuture<Long> t) {
                  mapOnTopology();
                }
              });
        }
      } finally {
        cctx.topology().readUnlock();
      }
    } catch (GridException e) {
      onDone(e);
    }
  }
  /** {@inheritDoc} */
  @Override
  public boolean onDone(@Nullable GridCacheCommittedTxInfo<K, V> res, @Nullable Throwable err) {
    if (super.onDone(res, err)) {
      cctx.mvcc().removeFuture(this);

      if (log.isDebugEnabled())
        log.debug(
            "Completing check committed tx future for transaction [tx="
                + tx
                + ", res="
                + res
                + ", err="
                + err
                + ']');

      if (err == null) cctx.tm().finishPessimisticTxOnRecovery(tx, res);
      else {
        if (log.isDebugEnabled())
          log.debug(
              "Failed to check prepared transactions, "
                  + "invalidating transaction [err="
                  + err
                  + ", tx="
                  + tx
                  + ']');

        if (nearCheck) return true;

        cctx.tm().salvageTx(tx);
      }

      return true;
    }

    return false;
  }
  /** {@inheritDoc} */
  @Override
  public GridFuture<?> awaitAsync() {
    return ctx.closures()
        .callLocalSafe(
            new Callable<Object>() {
              @Nullable
              @Override
              public Object call() throws Exception {
                await();

                return null;
              }
            },
            true);
  }
  /**
   * @param cctx Context.
   * @param tx Transaction.
   * @param failedNodeId ID of failed node started transaction.
   */
  @SuppressWarnings("ConstantConditions")
  public GridCachePessimisticCheckCommittedTxFuture(
      GridCacheContext<K, V> cctx, GridCacheTxEx<K, V> tx, UUID failedNodeId) {
    super(cctx.kernalContext(), new SingleReducer<K, V>());

    this.cctx = cctx;
    this.tx = tx;
    this.failedNodeId = failedNodeId;

    log = U.logger(ctx, logRef, GridCacheOptimisticCheckPreparedTxFuture.class);

    nodes = new GridLeanMap<>();

    for (GridNode node : CU.allNodes(cctx, tx.topologyVersion())) nodes.put(node.id(), node);
  }
  /**
   * @param cctx Context.
   * @param tx Transaction.
   * @param commit Commit flag.
   */
  public GridNearTxFinishFuture(
      GridCacheContext<K, V> cctx, GridNearTxLocal<K, V> tx, boolean commit) {
    super(cctx.kernalContext(), F.<GridCacheTx>identityReducer(tx));

    assert cctx != null;

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

    mappings = tx.mappings();

    futId = GridUuid.randomUuid();

    log = U.logger(ctx, logRef, GridNearTxFinishFuture.class);
  }
  /**
   * Default constructor.
   *
   * @param name Atomic reference name.
   * @param key Atomic reference key.
   * @param atomicView Atomic projection.
   * @param ctx Cache context.
   */
  public GridCacheAtomicReferenceImpl(
      String name,
      GridCacheInternalKey key,
      GridCacheProjection<GridCacheInternalKey, GridCacheAtomicReferenceValue<T>> atomicView,
      GridCacheContext ctx) {
    assert key != null;
    assert atomicView != null;
    assert ctx != null;
    assert name != null;

    this.ctx = ctx;
    this.key = key;
    this.atomicView = atomicView;
    this.name = name;

    log = ctx.gridConfig().getGridLogger().getLogger(getClass());
  }
Esempio n. 23
0
  /**
   * @param cached Entry to check.
   * @return {@code True} if filter passed.
   */
  private boolean filter(GridCacheEntryEx<K, V> cached) {
    try {
      if (!cctx.isAll(cached, filter)) {
        if (log.isDebugEnabled())
          log.debug("Filter didn't pass for entry (will fail lock): " + cached);

        onFailed(true);

        return false;
      }

      return true;
    } catch (GridException e) {
      onError(e);

      return false;
    }
  }
Esempio n. 24
0
  /** @return {@code True} if locks have been acquired. */
  private boolean checkLocks() {
    if (!isDone() && initialized() && !hasPending()) {
      for (int i = 0; i < entries.size(); i++) {
        while (true) {
          GridCacheEntryEx<K, V> cached = entries.get(i);

          try {
            if (!locked(cached)) {
              if (log.isDebugEnabled())
                log.debug(
                    "Lock is still not acquired for entry (will keep waiting) [entry="
                        + cached
                        + ", fut="
                        + this
                        + ']');

              return false;
            }

            break;
          }
          // Possible in concurrent cases, when owner is changed after locks
          // have been released or cancelled.
          catch (GridCacheEntryRemovedException ignore) {
            if (log.isDebugEnabled())
              log.debug("Got removed entry in onOwnerChanged method (will retry): " + cached);

            // Replace old entry with new one.
            entries.set(i, (GridDistributedCacheEntry<K, V>) cctx.cache().entryEx(cached.key()));
          }
        }
      }

      if (log.isDebugEnabled())
        log.debug("Local lock acquired for entries [fut=" + this + ", entries=" + entries + "]");

      onComplete(true, true);

      return true;
    }

    return false;
  }
Esempio n. 25
0
  /**
   * Basically, future mapping consists from two parts. First, we must determine the topology
   * version this future will map on. Locking is performed within a user transaction, we must
   * continue to map keys on the same topology version as it started. If topology version is
   * undefined, we get current topology future and wait until it completes so the topology is ready
   * to use.
   *
   * <p>During the second part we map keys to primary nodes using topology snapshot we obtained
   * during the first part. Note that if primary node leaves grid, the future will fail and
   * transaction will be rolled back.
   */
  void map() {
    // Obtain the topology version to use.
    GridDiscoveryTopologySnapshot snapshot =
        tx != null
            ? tx.topologySnapshot()
            : cctx.mvcc().lastExplicitLockTopologySnapshot(Thread.currentThread().getId());

    if (snapshot != null) {
      // Continue mapping on the same topology version as it was before.
      topSnapshot.compareAndSet(null, snapshot);

      map(keys);

      markInitialized();

      return;
    }

    // Must get topology snapshot and map on that version.
    mapOnTopology();
  }
  /**
   * @param res Query result.
   * @param err Error or {@code null} if query executed successfully.
   * @param startTime Start time.
   * @param duration Duration.
   */
  public void onExecuted(Object res, Throwable err, long startTime, long duration) {
    boolean fail = err != null;

    // Update own metrics.
    metrics.onQueryExecute(duration, fail);

    // Update metrics in query manager.
    cctx.queries().onMetricsUpdate(duration, fail);

    if (log.isDebugEnabled())
      log.debug(
          "Query execution finished [qry="
              + this
              + ", startTime="
              + startTime
              + ", duration="
              + duration
              + ", fail="
              + fail
              + ", res="
              + res
              + ']');
  }
  /** {@inheritDoc} */
  @Override
  public void execute(@Nullable GridProjection prj) throws GridException {
    if (cb == null)
      throw new IllegalStateException("Mandatory local callback is not set for the query: " + this);

    if (prj == null) prj = ctx.grid();

    prj = prj.forCache(ctx.name());

    if (prj.nodes().isEmpty())
      throw new GridTopologyException("Failed to execute query (projection is empty): " + this);

    GridCacheMode mode = ctx.config().getCacheMode();

    if (mode == LOCAL || mode == REPLICATED) {
      Collection<GridNode> nodes = prj.nodes();

      GridNode node = nodes.contains(ctx.localNode()) ? ctx.localNode() : F.rand(nodes);

      assert node != null;

      if (nodes.size() > 1 && !ctx.cache().isDrSystemCache()) {
        if (node.id().equals(ctx.localNodeId()))
          U.warn(
              log,
              "Continuous query for "
                  + mode
                  + " cache can be run only on local node. "
                  + "Will execute query locally: "
                  + this);
        else
          U.warn(
              log,
              "Continuous query for "
                  + mode
                  + " cache can be run only on single node. "
                  + "Will execute query on remote node [qry="
                  + this
                  + ", node="
                  + node
                  + ']');
      }

      prj = prj.forNode(node);
    }

    closeLock.lock();

    try {
      if (routineId != null)
        throw new IllegalStateException("Continuous query can't be executed twice.");

      guard.block();

      GridContinuousHandler hnd =
          new GridCacheContinuousQueryHandler<>(ctx.name(), topic, cb, filter, prjPred);

      routineId =
          ctx.kernalContext()
              .continuous()
              .startRoutine(hnd, bufSize, timeInterval, autoUnsubscribe, prj.predicate())
              .get();
    } finally {
      closeLock.unlock();
    }
  }
  /**
   * Asynchronous sequence update operation. Will add given amount to the sequence value.
   *
   * @param l Increment amount.
   * @param updateCall Cache call that will update sequence reservation count in accordance with l.
   * @param updated If {@code true}, will return sequence value after update, otherwise will return
   *     sequence value prior to update.
   * @return Future indicating sequence value.
   * @throws GridException If update failed.
   */
  private GridFuture<Long> internalUpdateAsync(
      long l, @Nullable Callable<Long> updateCall, boolean updated) throws GridException {
    checkRemoved();

    A.ensure(l > 0, " Parameter mustn't be less then 1: " + l);

    lock.lock();

    try {
      // If reserved range isn't exhausted.
      if (locVal + l <= upBound) {
        long curVal = locVal;

        locVal += l;

        return new GridFinishedFuture<Long>(ctx.kernalContext(), updated ? locVal : curVal);
      }
    } finally {
      lock.unlock();
    }

    if (updateCall == null) updateCall = internalUpdate(l, updated);

    while (true) {
      if (updateGuard.compareAndSet(false, true)) {
        try {
          // This call must be outside lock.
          return ctx.closures().callLocalSafe(updateCall, true);
        } finally {
          lock.lock();

          try {
            updateGuard.set(false);

            cond.signalAll();
          } finally {
            lock.unlock();
          }
        }
      } else {
        lock.lock();

        try {
          while (locVal >= upBound && updateGuard.get()) {
            try {
              cond.await(500, MILLISECONDS);
            } catch (InterruptedException e) {
              throw new GridInterruptedException(e);
            }
          }

          checkRemoved();

          // If reserved range isn't exhausted.
          if (locVal + l <= upBound) {
            long curVal = locVal;

            locVal += l;

            return new GridFinishedFuture<Long>(ctx.kernalContext(), updated ? locVal : curVal);
          }
        } finally {
          lock.unlock();
        }
      }
    }
  }
 /** @return DHT cache. */
 private GridDhtCache<K, V> dht() {
   return cctx.near().dht();
 }
Esempio n. 30
0
  /**
   * Gets next near lock mapping and either acquires dht locks locally or sends near lock request to
   * remote primary node.
   *
   * @param mappings Queue of mappings.
   * @throws GridException If mapping can not be completed.
   */
  private void proceedMapping(final ConcurrentLinkedDeque8<GridNearLockMapping<K, V>> mappings)
      throws GridException {
    GridNearLockMapping<K, V> map = mappings.poll();

    // If there are no more mappings to process, complete the future.
    if (map == null) return;

    final GridNearLockRequest<K, V> req = map.request();
    final Collection<K> mappedKeys = map.distributedKeys();
    final GridNode node = map.node();

    if (filter != null && filter.length != 0) req.filter(filter, cctx);

    if (node.isLocal()) {
      req.miniId(GridUuid.randomUuid());

      if (log.isDebugEnabled()) log.debug("Before locally locking near request: " + req);

      GridFuture<GridNearLockResponse<K, V>> fut;

      if (CU.DHT_ENABLED) fut = dht().lockAllAsync(cctx.localNode(), req, filter);
      else {
        // Create dummy values for testing.
        GridNearLockResponse<K, V> res =
            new GridNearLockResponse<>(lockVer, futId, null, false, 1, null);

        res.addValueBytes(null, null, true, lockVer, lockVer, cctx);

        fut = new GridFinishedFuture<>(ctx, res);
      }

      // Add new future.
      add(
          new GridEmbeddedFuture<>(
              cctx.kernalContext(),
              fut,
              new C2<GridNearLockResponse<K, V>, Exception, Boolean>() {
                @Override
                public Boolean apply(GridNearLockResponse<K, V> res, Exception e) {
                  if (CU.isLockTimeoutOrCancelled(e)
                      || (res != null && CU.isLockTimeoutOrCancelled(res.error()))) return false;

                  if (e != null) {
                    onError(e);

                    return false;
                  }

                  if (res == null) {
                    onError(new GridException("Lock response is null for future: " + this));

                    return false;
                  }

                  if (res.error() != null) {
                    onError(res.error());

                    return false;
                  }

                  if (log.isDebugEnabled())
                    log.debug(
                        "Acquired lock for local DHT mapping [locId="
                            + cctx.nodeId()
                            + ", mappedKeys="
                            + mappedKeys
                            + ", fut="
                            + GridNearLockFuture.this
                            + ']');

                  try {
                    int i = 0;

                    for (K k : mappedKeys) {
                      while (true) {
                        GridNearCacheEntry<K, V> entry =
                            cctx.near().entryExx(k, req.topologyVersion());

                        try {
                          GridTuple3<GridCacheVersion, V, byte[]> oldValTup =
                              valMap.get(entry.key());

                          boolean hasBytes = entry.hasValue();
                          V oldVal = entry.rawGet();
                          V newVal = res.value(i);
                          byte[] newBytes = res.valueBytes(i);

                          GridCacheVersion dhtVer = res.dhtVersion(i);
                          GridCacheVersion mappedVer = res.mappedVersion(i);

                          // On local node don't record twice if DHT cache already recorded.
                          boolean record =
                              retval && oldValTup != null && oldValTup.get1().equals(dhtVer);

                          if (newVal == null) {
                            if (oldValTup != null) {
                              if (oldValTup.get1().equals(dhtVer)) {
                                newVal = oldValTup.get2();

                                newBytes = oldValTup.get3();
                              }

                              oldVal = oldValTup.get2();
                            }
                          }

                          // Lock is held at this point, so we can set the
                          // returned value if any.
                          entry.resetFromPrimary(newVal, newBytes, lockVer, dhtVer, node.id());

                          entry.readyNearLock(
                              lockVer,
                              mappedVer,
                              res.committedVersions(),
                              res.rolledbackVersions(),
                              res.pending());

                          if (inTx() && implicitTx() && tx.onePhaseCommit()) {
                            boolean pass = res.filterResult(i);

                            tx.entry(k).filters(pass ? CU.<K, V>empty() : CU.<K, V>alwaysFalse());
                          }

                          if (record) {
                            if (cctx.events().isRecordable(EVT_CACHE_OBJECT_READ))
                              cctx.events()
                                  .addEvent(
                                      entry.partition(),
                                      entry.key(),
                                      tx,
                                      null,
                                      EVT_CACHE_OBJECT_READ,
                                      newVal,
                                      newVal != null,
                                      oldVal,
                                      hasBytes,
                                      CU.subjectId(tx, cctx));

                            cctx.cache().metrics0().onRead(oldVal != null);
                          }

                          if (log.isDebugEnabled())
                            log.debug(
                                "Processed response for entry [res="
                                    + res
                                    + ", entry="
                                    + entry
                                    + ']');

                          break; // Inner while loop.
                        } catch (GridCacheEntryRemovedException ignored) {
                          if (log.isDebugEnabled())
                            log.debug(
                                "Failed to add candidates because entry was "
                                    + "removed (will renew).");

                          // Replace old entry with new one.
                          entries.set(
                              i,
                              (GridDistributedCacheEntry<K, V>) cctx.cache().entryEx(entry.key()));
                        }
                      }

                      i++; // Increment outside of while loop.
                    }

                    // Proceed and add new future (if any) before completing embedded future.
                    proceedMapping(mappings);
                  } catch (GridException ex) {
                    onError(ex);

                    return false;
                  }

                  return true;
                }
              }));
    } else {
      final MiniFuture fut = new MiniFuture(node, mappedKeys, mappings);

      req.miniId(fut.futureId());

      add(fut); // Append new future.

      GridFuture<?> txSync = null;

      if (inTx()) txSync = cctx.tm().awaitFinishAckAsync(node.id(), tx.threadId());

      if (txSync == null || txSync.isDone()) {
        try {
          if (log.isDebugEnabled())
            log.debug("Sending near lock request [node=" + node.id() + ", req=" + req + ']');

          cctx.io().send(node, req);
        } catch (GridTopologyException ex) {
          assert fut != null;

          fut.onResult(ex);
        }
      } else {
        txSync.listenAsync(
            new CI1<GridFuture<?>>() {
              @Override
              public void apply(GridFuture<?> t) {
                try {
                  if (log.isDebugEnabled())
                    log.debug(
                        "Sending near lock request [node=" + node.id() + ", req=" + req + ']');

                  cctx.io().send(node, req);
                } catch (GridTopologyException ex) {
                  assert fut != null;

                  fut.onResult(ex);
                } catch (GridException e) {
                  onError(e);
                }
              }
            });
      }
    }
  }