Example #1
0
  /**
   * Unmarshalls transfer object from remote node within a given context.
   *
   * @param ctx Grid kernal context that provides deployment and marshalling services.
   * @param sndNodeId {@link UUID} of the sender node.
   * @param msg Transfer object that contains original serialized object and deployment information.
   * @return Unmarshalled object.
   * @throws IgniteCheckedException If node cannot obtain deployment.
   */
  static Object unmarshall(GridKernalContext ctx, UUID sndNodeId, GridAffinityMessage msg)
      throws IgniteCheckedException {
    GridDeployment dep =
        ctx.deploy()
            .getGlobalDeployment(
                msg.deploymentMode(),
                msg.sourceClassName(),
                msg.sourceClassName(),
                msg.userVersion(),
                sndNodeId,
                msg.classLoaderId(),
                msg.loaderParticipants(),
                null);

    if (dep == null)
      throw new IgniteDeploymentCheckedException(
          "Failed to obtain affinity object (is peer class loading turned on?): " + msg);

    Object src =
        U.unmarshal(ctx, msg.source(), U.resolveClassLoader(dep.classLoader(), ctx.config()));

    // Resource injection.
    ctx.resource().inject(dep, dep.deployedClass(msg.sourceClassName()), src);

    return src;
  }
  /** {@inheritDoc} */
  @Override
  public RegisterStatus register(
      final UUID nodeId, final UUID routineId, final GridKernalContext ctx)
      throws IgniteCheckedException {
    assert nodeId != null;
    assert routineId != null;
    assert ctx != null;

    if (locLsnr != null) ctx.resource().injectGeneric(locLsnr);

    if (rmtFilter != null) ctx.resource().injectGeneric(rmtFilter);

    entryBufs = new ConcurrentHashMap<>();

    backupQueue = new ConcurrentLinkedDeque8<>();

    ackBuf = new AcknowledgeBuffer();

    rcvs = new ConcurrentHashMap<>();

    final boolean loc = nodeId.equals(ctx.localNodeId());

    assert !skipPrimaryCheck || loc;

    final GridCacheContext<K, V> cctx = cacheContext(ctx);

    if (!internal && cctx != null && initUpdCntrs != null) {
      Map<Integer, Long> map = cctx.topology().updateCounters();

      for (Map.Entry<Integer, Long> e : map.entrySet()) {
        Long cntr0 = initUpdCntrs.get(e.getKey());
        Long cntr1 = e.getValue();

        if (cntr0 == null || cntr1 > cntr0) initUpdCntrs.put(e.getKey(), cntr1);
      }
    }

    CacheContinuousQueryListener<K, V> lsnr =
        new CacheContinuousQueryListener<K, V>() {
          @Override
          public void onExecution() {
            if (ctx.event().isRecordable(EVT_CACHE_QUERY_EXECUTED)) {
              ctx.event()
                  .record(
                      new CacheQueryExecutedEvent<>(
                          ctx.discovery().localNode(),
                          "Continuous query executed.",
                          EVT_CACHE_QUERY_EXECUTED,
                          CacheQueryType.CONTINUOUS.name(),
                          cacheName,
                          null,
                          null,
                          null,
                          rmtFilter,
                          null,
                          nodeId,
                          taskName()));
            }
          }

          /** {@inheritDoc} */
          @Override
          public boolean keepBinary() {
            return keepBinary;
          }

          @Override
          public void onEntryUpdated(
              CacheContinuousQueryEvent<K, V> evt, boolean primary, boolean recordIgniteEvt) {
            if (ignoreExpired && evt.getEventType() == EventType.EXPIRED) return;

            final GridCacheContext<K, V> cctx = cacheContext(ctx);

            // Check that cache stopped.
            if (cctx == null) return;

            // skipPrimaryCheck is set only when listen locally for replicated cache events.
            assert !skipPrimaryCheck || (cctx.isReplicated() && ctx.localNodeId().equals(nodeId));

            boolean notify = true;

            if (rmtFilter != null) {
              try {
                notify = rmtFilter.evaluate(evt);
              } catch (Exception e) {
                U.error(
                    cctx.logger(CacheContinuousQueryHandler.class),
                    "CacheEntryEventFilter failed: " + e);
              }
            }

            try {
              final CacheContinuousQueryEntry entry = evt.entry();

              if (!notify) entry.markFiltered();

              if (primary || skipPrimaryCheck) {
                if (loc) {
                  if (!locCache) {
                    Collection<CacheContinuousQueryEntry> entries = handleEvent(ctx, entry);

                    if (!entries.isEmpty()) {
                      final IgniteCache cache = cctx.kernalContext().cache().jcache(cctx.name());

                      Iterable<CacheEntryEvent<? extends K, ? extends V>> evts =
                          F.viewReadOnly(
                              entries,
                              new C1<
                                  CacheContinuousQueryEntry,
                                  CacheEntryEvent<? extends K, ? extends V>>() {
                                @Override
                                public CacheEntryEvent<? extends K, ? extends V> apply(
                                    CacheContinuousQueryEntry e) {
                                  return new CacheContinuousQueryEvent<>(cache, cctx, e);
                                }
                              },
                              new IgnitePredicate<CacheContinuousQueryEntry>() {
                                @Override
                                public boolean apply(CacheContinuousQueryEntry entry) {
                                  return !entry.isFiltered();
                                }
                              });

                      locLsnr.onUpdated(evts);

                      if (!internal && !skipPrimaryCheck)
                        sendBackupAcknowledge(ackBuf.onAcknowledged(entry), routineId, ctx);
                    }
                  } else {
                    if (!entry.isFiltered())
                      locLsnr.onUpdated(F.<CacheEntryEvent<? extends K, ? extends V>>asList(evt));
                  }
                } else {
                  if (!entry.isFiltered()) prepareEntry(cctx, nodeId, entry);

                  CacheContinuousQueryEntry e = handleEntry(entry);

                  if (e != null)
                    ctx.continuous().addNotification(nodeId, routineId, entry, topic, sync, true);
                }
              } else {
                if (!internal) {
                  // Skip init query and expire entries.
                  if (entry.updateCounter() != -1L) {
                    entry.markBackup();

                    backupQueue.add(entry);
                  }
                }
              }
            } catch (ClusterTopologyCheckedException ex) {
              IgniteLogger log = ctx.log(getClass());

              if (log.isDebugEnabled())
                log.debug(
                    "Failed to send event notification to node, node left cluster "
                        + "[node="
                        + nodeId
                        + ", err="
                        + ex
                        + ']');
            } catch (IgniteCheckedException ex) {
              U.error(
                  ctx.log(getClass()), "Failed to send event notification to node: " + nodeId, ex);
            }

            if (recordIgniteEvt && notify) {
              ctx.event()
                  .record(
                      new CacheQueryReadEvent<>(
                          ctx.discovery().localNode(),
                          "Continuous query executed.",
                          EVT_CACHE_QUERY_OBJECT_READ,
                          CacheQueryType.CONTINUOUS.name(),
                          cacheName,
                          null,
                          null,
                          null,
                          rmtFilter,
                          null,
                          nodeId,
                          taskName(),
                          evt.getKey(),
                          evt.getValue(),
                          evt.getOldValue(),
                          null));
            }
          }

          @Override
          public void onUnregister() {
            if (rmtFilter instanceof PlatformContinuousQueryFilter)
              ((PlatformContinuousQueryFilter) rmtFilter).onQueryUnregister();
          }

          @Override
          public void cleanupBackupQueue(Map<Integer, Long> updateCntrs) {
            Iterator<CacheContinuousQueryEntry> it = backupQueue.iterator();

            while (it.hasNext()) {
              CacheContinuousQueryEntry backupEntry = it.next();

              Long updateCntr = updateCntrs.get(backupEntry.partition());

              if (updateCntr != null && backupEntry.updateCounter() <= updateCntr) it.remove();
            }
          }

          @Override
          public void flushBackupQueue(GridKernalContext ctx, AffinityTopologyVersion topVer) {
            if (backupQueue.isEmpty()) return;

            try {
              GridCacheContext<K, V> cctx = cacheContext(ctx);

              for (CacheContinuousQueryEntry e : backupQueue) {
                if (!e.isFiltered()) prepareEntry(cctx, nodeId, e);
              }

              ctx.continuous().addBackupNotification(nodeId, routineId, backupQueue, topic);

              backupQueue.clear();
            } catch (IgniteCheckedException e) {
              U.error(
                  ctx.log(getClass()),
                  "Failed to send backup event notification to node: " + nodeId,
                  e);
            }
          }

          @Override
          public void acknowledgeBackupOnTimeout(GridKernalContext ctx) {
            sendBackupAcknowledge(ackBuf.acknowledgeOnTimeout(), routineId, ctx);
          }

          @Override
          public void skipUpdateEvent(
              CacheContinuousQueryEvent<K, V> evt, AffinityTopologyVersion topVer) {
            try {
              assert evt != null;

              CacheContinuousQueryEntry e = evt.entry();

              EntryBuffer buf = entryBufs.get(e.partition());

              if (buf == null) {
                buf = new EntryBuffer();

                EntryBuffer oldRec = entryBufs.putIfAbsent(e.partition(), buf);

                if (oldRec != null) buf = oldRec;
              }

              e = buf.skipEntry(e);

              if (e != null && !ctx.localNodeId().equals(nodeId))
                ctx.continuous().addNotification(nodeId, routineId, e, topic, sync, true);
            } catch (ClusterTopologyCheckedException ex) {
              IgniteLogger log = ctx.log(getClass());

              if (log.isDebugEnabled())
                log.debug(
                    "Failed to send event notification to node, node left cluster "
                        + "[node="
                        + nodeId
                        + ", err="
                        + ex
                        + ']');
            } catch (IgniteCheckedException ex) {
              U.error(
                  ctx.log(getClass()), "Failed to send event notification to node: " + nodeId, ex);
            }
          }

          @Override
          public void onPartitionEvicted(int part) {
            for (Iterator<CacheContinuousQueryEntry> it = backupQueue.iterator(); it.hasNext(); ) {
              if (it.next().partition() == part) it.remove();
            }
          }

          @Override
          public boolean oldValueRequired() {
            return oldValRequired;
          }

          @Override
          public boolean notifyExisting() {
            return notifyExisting;
          }

          private String taskName() {
            return ctx.security().enabled() ? ctx.task().resolveTaskName(taskHash) : null;
          }
        };

    CacheContinuousQueryManager mgr = manager(ctx);

    if (mgr == null) return RegisterStatus.DELAYED;

    return mgr.registerListener(routineId, lsnr, internal);
  }