/** * @param ctx Kernal context. * @param cfg Ignite configuration. * @param providers Plugin providers. */ @SuppressWarnings("TypeMayBeWeakened") public IgnitePluginProcessor( GridKernalContext ctx, IgniteConfiguration cfg, List<PluginProvider> providers) { super(ctx); ExtensionRegistryImpl registry = new ExtensionRegistryImpl(); for (PluginProvider provider : providers) { GridPluginContext pluginCtx = new GridPluginContext(ctx, cfg); if (F.isEmpty(provider.name())) throw new IgniteException("Plugin name can not be empty."); if (plugins.containsKey(provider.name())) throw new IgniteException("Duplicated plugin name: " + provider.name()); plugins.put(provider.name(), provider); pluginCtxMap.put(provider, pluginCtx); provider.initExtensions(pluginCtx, registry); if (provider.plugin() == null) throw new IgniteException("Plugin is null."); } extensions = registry.createExtensionMap(); }
/** * {@inheritDoc} * * @param ctx */ @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { super.prepareMarshal(ctx); if (ownedVals != null) { ownedValKeys = ownedVals.keySet(); ownedValVals = ownedVals.values(); for (Map.Entry<IgniteTxKey, CacheVersionedValue> entry : ownedVals.entrySet()) { GridCacheContext cacheCtx = ctx.cacheContext(entry.getKey().cacheId()); entry.getKey().prepareMarshal(cacheCtx); entry.getValue().prepareMarshal(cacheCtx.cacheObjectContext()); } } if (retVal != null && retVal.cacheId() != 0) { GridCacheContext cctx = ctx.cacheContext(retVal.cacheId()); assert cctx != null : retVal.cacheId(); retVal.prepareMarshal(cctx); } if (filterFailedKeys != null) { for (IgniteTxKey key : filterFailedKeys) { GridCacheContext cctx = ctx.cacheContext(key.cacheId()); key.prepareMarshal(cctx); } } }
/** Cleans up resources to avoid excessive memory usage. */ public void cleanUp() { topSnapshot.set(null); singleMsgs.clear(); fullMsgs.clear(); rcvdIds.clear(); oldestNode.set(null); partReleaseFut = null; Collection<ClusterNode> rmtNodes = this.rmtNodes; if (rmtNodes != null) rmtNodes.clear(); }
/** {@inheritDoc} */ @Override public void onDiscoveryDataReceived(UUID nodeId, UUID rmtNodeId, Serializable data) { Map<String, Serializable> discData = (Map<String, Serializable>) data; if (discData != null) { for (Map.Entry<String, Serializable> e : discData.entrySet()) { PluginProvider provider = plugins.get(e.getKey()); if (provider != null) provider.receiveDiscoveryData(nodeId, e.getValue()); else U.warn(log, "Received discovery data for unknown plugin: " + e.getKey()); } } }
/** Print plugins information. */ private void ackPluginsInfo() { U.quietAndInfo(log, "Configured plugins:"); if (plugins.isEmpty()) { U.quietAndInfo(log, " ^-- None"); U.quietAndInfo(log, ""); } else { for (PluginProvider plugin : plugins.values()) { U.quietAndInfo(log, " ^-- " + plugin.name() + " " + plugin.version()); U.quietAndInfo(log, " ^-- " + plugin.copyright()); U.quietAndInfo(log, ""); } } }
/** {@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); }
/** {@inheritDoc} */ @Override public boolean onDone(AffinityTopologyVersion res, Throwable err) { Map<Integer, Boolean> m = null; for (GridCacheContext cacheCtx : cctx.cacheContexts()) { if (cacheCtx.config().getTopologyValidator() != null && !CU.isSystemCache(cacheCtx.name())) { if (m == null) m = new HashMap<>(); m.put( cacheCtx.cacheId(), cacheCtx.config().getTopologyValidator().validate(discoEvt.topologyNodes())); } } cacheValidRes = m != null ? m : Collections.<Integer, Boolean>emptyMap(); cctx.cache().onExchangeDone(exchId.topologyVersion(), reqs, err); cctx.exchange().onExchangeDone(this, err); if (super.onDone(res, err) && !dummy && !forcePreload) { if (log.isDebugEnabled()) log.debug( "Completed partition exchange [localNode=" + cctx.localNodeId() + ", exchange= " + this + ']'); initFut.onDone(err == null); GridTimeoutObject timeoutObj = this.timeoutObj; // Deschedule timeout object. if (timeoutObj != null) cctx.kernalContext().timeout().removeTimeoutObject(timeoutObj); if (exchId.isLeft()) { for (GridCacheContext cacheCtx : cctx.cacheContexts()) cacheCtx.config().getAffinity().removeNode(exchId.nodeId()); } return true; } return dummy; }
/** * Adds owned value. * * @param key Key. * @param ver DHT version. * @param val Value. */ public void addOwnedValue(IgniteTxKey key, GridCacheVersion ver, CacheObject val) { if (val == null) return; if (ownedVals == null) ownedVals = new HashMap<>(); CacheVersionedValue oVal = new CacheVersionedValue(val, ver); ownedVals.put(key, oVal); }
/** * Cache preloader should call this method within partition lock. * * @param key Key. * @param ver Version. * @return {@code True} if preloading is permitted. */ public boolean preloadingPermitted(KeyCacheObject key, GridCacheVersion ver) { assert key != null; assert ver != null; assert lock.isHeldByCurrentThread(); // Only one thread can enter this method at a time. if (state() != MOVING) return false; Map<KeyCacheObject, GridCacheVersion> evictHist0 = evictHist; if (evictHist0 != null) { GridCacheVersion ver0 = evictHist0.get(key); // Permit preloading if version in history // is missing or less than passed in. return ver0 == null || ver0.isLess(ver); } return false; }
/** * @param key Key. * @param ver Version. */ public void onEntryEvicted(KeyCacheObject key, GridCacheVersion ver) { assert key != null; assert ver != null; assert lock.isHeldByCurrentThread(); // Only one thread can enter this method at a time. if (state() != MOVING) return; Map<KeyCacheObject, GridCacheVersion> evictHist0 = evictHist; if (evictHist0 != null) { GridCacheVersion ver0 = evictHist0.get(key); if (ver0 == null || ver0.isLess(ver)) { GridCacheVersion ver1 = evictHist0.put(key, ver); assert ver1 == ver0; } } }
/** * @param cls Component class. * @param <T> Component type. * @return Component class instance or {@code null} if no one plugin override this component. */ public <T> T createComponent(Class<T> cls) { for (PluginProvider plugin : plugins.values()) { PluginContext ctx = pluginContextForProvider(plugin); T comp = (T) plugin.createComponent(ctx, cls); if (comp != null) return comp; } return null; }
/** * {@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); }
/** {@inheritDoc} */ @Nullable @Override public Serializable collectDiscoveryData(UUID nodeId) { HashMap<String, Serializable> discData = null; for (Map.Entry<String, PluginProvider> e : plugins.entrySet()) { Serializable data = e.getValue().provideDiscoveryData(nodeId); if (data != null) { if (discData == null) discData = new HashMap<>(); discData.put(e.getKey(), data); } } return discData; }
/** {@inheritDoc} */ @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { super.finishUnmarshal(ctx, ldr); if (ownedValKeys != null && ownedVals == null) { ownedVals = U.newHashMap(ownedValKeys.size()); assert ownedValKeys.size() == ownedValVals.size(); Iterator<IgniteTxKey> keyIter = ownedValKeys.iterator(); Iterator<CacheVersionedValue> valIter = ownedValVals.iterator(); while (keyIter.hasNext()) { IgniteTxKey key = keyIter.next(); GridCacheContext cctx = ctx.cacheContext(key.cacheId()); CacheVersionedValue val = valIter.next(); key.finishUnmarshal(cctx, ldr); val.finishUnmarshal(cctx, ldr); ownedVals.put(key, val); } } if (retVal != null && retVal.cacheId() != 0) { GridCacheContext cctx = ctx.cacheContext(retVal.cacheId()); assert cctx != null : retVal.cacheId(); retVal.finishUnmarshal(cctx, ldr); } if (filterFailedKeys != null) { for (IgniteTxKey key : filterFailedKeys) { GridCacheContext cctx = ctx.cacheContext(key.cacheId()); key.finishUnmarshal(cctx, ldr); } } }
/** * Sets configuration properties from the map. * * @param endpointCfg Map of properties. * @throws IgniteCheckedException If invalid property name or value. */ public void setupConfiguration(Map<String, String> endpointCfg) throws IgniteCheckedException { for (Map.Entry<String, String> e : endpointCfg.entrySet()) { try { switch (e.getKey()) { case "type": case "host": case "management": // Ignore these properties break; case "port": setPort(Integer.parseInt(e.getValue())); break; case "size": setSize(Integer.parseInt(e.getValue())); break; case "tokenDirectoryPath": setTokenDirectoryPath(e.getValue()); break; default: throw new IgniteCheckedException( "Invalid property '" + e.getKey() + "' of " + getClass().getSimpleName()); } } catch (Throwable t) { if (t instanceof IgniteCheckedException || t instanceof Error) throw t; throw new IgniteCheckedException( "Invalid value '" + e.getValue() + "' of the property '" + e.getKey() + "' in " + getClass().getSimpleName(), t); } } }
/** * Starts activity. * * @throws IgniteInterruptedCheckedException If interrupted. */ public void init() throws IgniteInterruptedCheckedException { if (isDone()) return; if (init.compareAndSet(false, true)) { if (isDone()) return; try { // Wait for event to occur to make sure that discovery // will return corresponding nodes. U.await(evtLatch); assert discoEvt != null : this; assert !dummy && !forcePreload : this; ClusterNode oldest = CU.oldestAliveCacheServerNode(cctx, exchId.topologyVersion()); oldestNode.set(oldest); startCaches(); // True if client node joined or failed. boolean clientNodeEvt; if (F.isEmpty(reqs)) { int type = discoEvt.type(); assert type == EVT_NODE_JOINED || type == EVT_NODE_LEFT || type == EVT_NODE_FAILED : discoEvt; clientNodeEvt = CU.clientNode(discoEvt.eventNode()); } else { assert discoEvt.type() == EVT_DISCOVERY_CUSTOM_EVT : discoEvt; boolean clientOnlyStart = true; for (DynamicCacheChangeRequest req : reqs) { if (!req.clientStartOnly()) { clientOnlyStart = false; break; } } clientNodeEvt = clientOnlyStart; } if (clientNodeEvt) { ClusterNode node = discoEvt.eventNode(); // Client need to initialize affinity for local join event or for stated client caches. if (!node.isLocal()) { for (GridCacheContext cacheCtx : cctx.cacheContexts()) { if (cacheCtx.isLocal()) continue; GridDhtPartitionTopology top = cacheCtx.topology(); top.updateTopologyVersion(exchId, this, -1, stopping(cacheCtx.cacheId())); if (cacheCtx.affinity().affinityTopologyVersion() == AffinityTopologyVersion.NONE) { initTopology(cacheCtx); top.beforeExchange(this); } else cacheCtx.affinity().clientEventTopologyChange(discoEvt, exchId.topologyVersion()); } if (exchId.isLeft()) cctx.mvcc().removeExplicitNodeLocks(exchId.nodeId(), exchId.topologyVersion()); onDone(exchId.topologyVersion()); skipPreload = cctx.kernalContext().clientNode(); return; } } if (cctx.kernalContext().clientNode()) { skipPreload = true; for (GridCacheContext cacheCtx : cctx.cacheContexts()) { if (cacheCtx.isLocal()) continue; GridDhtPartitionTopology top = cacheCtx.topology(); top.updateTopologyVersion(exchId, this, -1, stopping(cacheCtx.cacheId())); } for (GridCacheContext cacheCtx : cctx.cacheContexts()) { if (cacheCtx.isLocal()) continue; initTopology(cacheCtx); } if (oldestNode.get() != null) { rmtNodes = new ConcurrentLinkedQueue<>( CU.aliveRemoteServerNodesWithCaches(cctx, exchId.topologyVersion())); rmtIds = Collections.unmodifiableSet(new HashSet<>(F.nodeIds(rmtNodes))); ready.set(true); initFut.onDone(true); if (log.isDebugEnabled()) log.debug("Initialized future: " + this); sendPartitions(); } else onDone(exchId.topologyVersion()); return; } assert oldestNode.get() != null; for (GridCacheContext cacheCtx : cctx.cacheContexts()) { if (isCacheAdded(cacheCtx.cacheId(), exchId.topologyVersion())) { if (cacheCtx .discovery() .cacheAffinityNodes(cacheCtx.name(), topologyVersion()) .isEmpty()) U.quietAndWarn(log, "No server nodes found for cache client: " + cacheCtx.namex()); } cacheCtx.preloader().onExchangeFutureAdded(); } List<String> cachesWithoutNodes = null; if (exchId.isLeft()) { for (String name : cctx.cache().cacheNames()) { if (cctx.discovery().cacheAffinityNodes(name, topologyVersion()).isEmpty()) { if (cachesWithoutNodes == null) cachesWithoutNodes = new ArrayList<>(); cachesWithoutNodes.add(name); // Fire event even if there is no client cache started. if (cctx.gridEvents().isRecordable(EventType.EVT_CACHE_NODES_LEFT)) { Event evt = new CacheEvent( name, cctx.localNode(), cctx.localNode(), "All server nodes have left the cluster.", EventType.EVT_CACHE_NODES_LEFT, 0, false, null, null, null, null, false, null, false, null, null, null); cctx.gridEvents().record(evt); } } } } if (cachesWithoutNodes != null) { StringBuilder sb = new StringBuilder( "All server nodes for the following caches have left the cluster: "); for (int i = 0; i < cachesWithoutNodes.size(); i++) { String cache = cachesWithoutNodes.get(i); sb.append('\'').append(cache).append('\''); if (i != cachesWithoutNodes.size() - 1) sb.append(", "); } U.quietAndWarn(log, sb.toString()); U.quietAndWarn(log, "Must have server nodes for caches to operate."); } assert discoEvt != null; assert exchId.nodeId().equals(discoEvt.eventNode().id()); for (GridCacheContext cacheCtx : cctx.cacheContexts()) { GridClientPartitionTopology clientTop = cctx.exchange().clearClientTopology(cacheCtx.cacheId()); long updSeq = clientTop == null ? -1 : clientTop.lastUpdateSequence(); // Update before waiting for locks. if (!cacheCtx.isLocal()) cacheCtx .topology() .updateTopologyVersion(exchId, this, updSeq, stopping(cacheCtx.cacheId())); } // Grab all alive remote nodes with order of equal or less than last joined node. rmtNodes = new ConcurrentLinkedQueue<>( CU.aliveRemoteServerNodesWithCaches(cctx, exchId.topologyVersion())); rmtIds = Collections.unmodifiableSet(new HashSet<>(F.nodeIds(rmtNodes))); for (Map.Entry<UUID, GridDhtPartitionsSingleMessage> m : singleMsgs.entrySet()) // If received any messages, process them. onReceive(m.getKey(), m.getValue()); for (Map.Entry<UUID, GridDhtPartitionsFullMessage> m : fullMsgs.entrySet()) // If received any messages, process them. onReceive(m.getKey(), m.getValue()); AffinityTopologyVersion topVer = exchId.topologyVersion(); for (GridCacheContext cacheCtx : cctx.cacheContexts()) { if (cacheCtx.isLocal()) continue; // Must initialize topology after we get discovery event. initTopology(cacheCtx); cacheCtx.preloader().updateLastExchangeFuture(this); } IgniteInternalFuture<?> partReleaseFut = cctx.partitionReleaseFuture(topVer); // Assign to class variable so it will be included into toString() method. this.partReleaseFut = partReleaseFut; if (log.isDebugEnabled()) log.debug("Before waiting for partition release future: " + this); while (true) { try { partReleaseFut.get(2 * cctx.gridConfig().getNetworkTimeout(), TimeUnit.MILLISECONDS); break; } catch (IgniteFutureTimeoutCheckedException ignored) { // Print pending transactions and locks that might have led to hang. dumpPendingObjects(); } } if (log.isDebugEnabled()) log.debug("After waiting for partition release future: " + this); if (!F.isEmpty(reqs)) blockGateways(); if (exchId.isLeft()) cctx.mvcc().removeExplicitNodeLocks(exchId.nodeId(), exchId.topologyVersion()); IgniteInternalFuture<?> locksFut = cctx.mvcc().finishLocks(exchId.topologyVersion()); while (true) { try { locksFut.get(2 * cctx.gridConfig().getNetworkTimeout(), TimeUnit.MILLISECONDS); break; } catch (IgniteFutureTimeoutCheckedException ignored) { U.warn( log, "Failed to wait for locks release future. " + "Dumping pending objects that might be the cause: " + cctx.localNodeId()); U.warn(log, "Locked entries:"); Map<IgniteTxKey, Collection<GridCacheMvccCandidate>> locks = cctx.mvcc().unfinishedLocks(exchId.topologyVersion()); for (Map.Entry<IgniteTxKey, Collection<GridCacheMvccCandidate>> e : locks.entrySet()) U.warn(log, "Locked entry [key=" + e.getKey() + ", mvcc=" + e.getValue() + ']'); } } for (GridCacheContext cacheCtx : cctx.cacheContexts()) { if (cacheCtx.isLocal()) continue; // Notify replication manager. GridCacheContext drCacheCtx = cacheCtx.isNear() ? cacheCtx.near().dht().context() : cacheCtx; if (drCacheCtx.isDrEnabled()) drCacheCtx.dr().beforeExchange(topVer, exchId.isLeft()); // Partition release future is done so we can flush the write-behind store. cacheCtx.store().forceFlush(); // Process queued undeploys prior to sending/spreading map. cacheCtx.preloader().unwindUndeploys(); GridDhtPartitionTopology top = cacheCtx.topology(); assert topVer.equals(top.topologyVersion()) : "Topology version is updated only in this class instances inside single ExchangeWorker thread."; top.beforeExchange(this); } for (GridClientPartitionTopology top : cctx.exchange().clientTopologies()) { top.updateTopologyVersion(exchId, this, -1, stopping(top.cacheId())); top.beforeExchange(this); } } catch (IgniteInterruptedCheckedException e) { onDone(e); throw e; } catch (Throwable e) { U.error( log, "Failed to reinitialize local partitions (preloading will be stopped): " + exchId, e); onDone(e); if (e instanceof Error) throw (Error) e; return; } if (F.isEmpty(rmtIds)) { onDone(exchId.topologyVersion()); return; } ready.set(true); initFut.onDone(true); if (log.isDebugEnabled()) log.debug("Initialized future: " + this); // If this node is not oldest. if (!oldestNode.get().id().equals(cctx.localNodeId())) sendPartitions(); else { boolean allReceived = allReceived(); if (allReceived && replied.compareAndSet(false, true)) { if (spreadPartitions()) onDone(exchId.topologyVersion()); } } scheduleRecheck(); } else assert false : "Skipped init future: " + this; }
/** {@inheritDoc} */ @Override public boolean isCacheTopologyValid(GridCacheContext cctx) { return cctx.config().getTopologyValidator() != null && cacheValidRes.containsKey(cctx.cacheId()) ? cacheValidRes.get(cctx.cacheId()) : true; }
/** * Remove particular entry from the trash directory or subdirectory. * * @param parentId Parent ID. * @param id Entry id. * @throws IgniteCheckedException If delete failed for some reason. */ private void deleteDirectory(IgniteUuid parentId, IgniteUuid id) throws IgniteCheckedException { assert parentId != null; assert id != null; while (true) { IgfsFileInfo info = meta.info(id); if (info != null) { assert info.isDirectory(); Map<String, IgfsListingEntry> listing = info.listing(); if (listing.isEmpty()) return; // Directory is empty. Map<String, IgfsListingEntry> delListing; if (listing.size() <= MAX_DELETE_BATCH) delListing = listing; else { delListing = new HashMap<>(MAX_DELETE_BATCH, 1.0f); int i = 0; for (Map.Entry<String, IgfsListingEntry> entry : listing.entrySet()) { delListing.put(entry.getKey(), entry.getValue()); if (++i == MAX_DELETE_BATCH) break; } } GridCompoundFuture<Object, ?> fut = new GridCompoundFuture<>(); // Delegate to child folders. for (IgfsListingEntry entry : delListing.values()) { if (!cancelled) { if (entry.isDirectory()) deleteDirectory(id, entry.fileId()); else { IgfsFileInfo fileInfo = meta.info(entry.fileId()); if (fileInfo != null) { assert fileInfo.isFile(); fut.add(data.delete(fileInfo)); } } } else return; } fut.markInitialized(); // Wait for data cache to delete values before clearing meta cache. try { fut.get(); } catch (IgniteFutureCancelledCheckedException ignore) { // This future can be cancelled only due to IGFS shutdown. cancelled = true; return; } // Actual delete of folder content. Collection<IgniteUuid> delIds = meta.delete(id, delListing); if (delListing == listing && delListing.size() == delIds.size()) break; // All entries were deleted. } else break; // Entry was deleted concurrently. } }
/** @return All plugin providers. */ public Collection<PluginProvider> allProviders() { return plugins.values(); }
/** * @param name Plugin name. * @return Plugin provider. */ @SuppressWarnings("unchecked") @Nullable public <T extends PluginProvider> T pluginProvider(String name) { return (T) plugins.get(name); }
/** * @param key Key. * @return {@code True} if response has owned value for given key. */ public boolean hasOwnedValue(IgniteTxKey key) { return ownedVals != null && ownedVals.containsKey(key); }
/** * Adds version to be verified on remote node. * * @param key Key for which version is verified. * @param dhtVer DHT version to check. */ public void addDhtVersion(IgniteTxKey key, @Nullable GridCacheVersion dhtVer) { if (dhtVers == null) dhtVers = new HashMap<>(); dhtVers.put(key, dhtVer); }
/** * @param provider Plugin context. * @return Plugin context. */ @SuppressWarnings("unchecked") public <T extends PluginContext> T pluginContextForProvider(PluginProvider provider) { return (T) pluginCtxMap.get(provider); }