/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ignite.internal.processors.platform; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteAtomicSequence; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteDataStreamer; import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.NearCacheConfiguration; import org.apache.ignite.configuration.PlatformConfiguration; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.binary.BinaryRawReaderEx; import org.apache.ignite.internal.binary.BinaryRawWriterEx; import org.apache.ignite.internal.logger.platform.PlatformLogger; import org.apache.ignite.internal.processors.GridProcessorAdapter; import org.apache.ignite.internal.processors.cache.IgniteCacheProxy; import org.apache.ignite.internal.processors.datastreamer.DataStreamerImpl; import org.apache.ignite.internal.processors.datastructures.GridCacheAtomicLongImpl; import org.apache.ignite.internal.processors.platform.binary.PlatformBinaryProcessor; import org.apache.ignite.internal.processors.platform.cache.PlatformCache; import org.apache.ignite.internal.processors.platform.cache.PlatformCacheExtension; import org.apache.ignite.internal.processors.platform.cache.affinity.PlatformAffinity; import org.apache.ignite.internal.processors.platform.cache.store.PlatformCacheStore; import org.apache.ignite.internal.processors.platform.cluster.PlatformClusterGroup; import org.apache.ignite.internal.processors.platform.compute.PlatformCompute; import org.apache.ignite.internal.processors.platform.datastreamer.PlatformDataStreamer; import org.apache.ignite.internal.processors.platform.datastructures.PlatformAtomicLong; import org.apache.ignite.internal.processors.platform.datastructures.PlatformAtomicReference; import org.apache.ignite.internal.processors.platform.datastructures.PlatformAtomicSequence; import org.apache.ignite.internal.processors.platform.dotnet.PlatformDotNetCacheStore; import org.apache.ignite.internal.processors.platform.events.PlatformEvents; import org.apache.ignite.internal.processors.platform.memory.PlatformMemory; import org.apache.ignite.internal.processors.platform.memory.PlatformOutputStream; import org.apache.ignite.internal.processors.platform.messaging.PlatformMessaging; import org.apache.ignite.internal.processors.platform.services.PlatformServices; import org.apache.ignite.internal.processors.platform.transactions.PlatformTransactions; import org.apache.ignite.internal.processors.platform.utils.PlatformConfigurationUtils; import org.apache.ignite.internal.processors.platform.utils.PlatformUtils; import org.apache.ignite.internal.util.typedef.CI1; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteFuture; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * GridGain platform processor. */ @SuppressWarnings({"ConditionalExpressionWithIdenticalBranches", "unchecked"}) public class PlatformProcessorImpl extends GridProcessorAdapter implements PlatformProcessor { /** Start latch. */ private final CountDownLatch startLatch = new CountDownLatch(1); /** Stores pending initialization. */ private final Collection<StoreInfo> pendingStores = Collections.newSetFromMap(new ConcurrentHashMap<StoreInfo, Boolean>()); /** Lock for store lifecycle operations. */ private final ReadWriteLock storeLock = new ReentrantReadWriteLock(); /** Logger. */ @SuppressWarnings("FieldCanBeLocal") private final IgniteLogger log; /** Context. */ private final PlatformContext platformCtx; /** Interop configuration. */ private final PlatformConfigurationEx interopCfg; /** Extensions. */ private final PlatformPluginExtension[] extensions; /** Whether processor is started. */ private boolean started; /** Whether processor if stopped (or stopping). */ private volatile boolean stopped; /** Cache extensions. */ private final PlatformCacheExtension[] cacheExts; /** Cluster restart flag for the reconnect callback. */ private volatile boolean clusterRestarted; /** * Constructor. * * @param ctx Kernal context. */ public PlatformProcessorImpl(GridKernalContext ctx) { super(ctx); log = ctx.log(PlatformProcessorImpl.class); PlatformConfiguration interopCfg0 = ctx.config().getPlatformConfiguration(); assert interopCfg0 != null : "Must be checked earlier during component creation."; if (!(interopCfg0 instanceof PlatformConfigurationEx)) throw new IgniteException("Unsupported platform configuration: " + interopCfg0.getClass().getName()); interopCfg = (PlatformConfigurationEx)interopCfg0; if (!F.isEmpty(interopCfg.warnings())) { for (String w : interopCfg.warnings()) U.warn(log, w); } platformCtx = new PlatformContextImpl(ctx, interopCfg.gate(), interopCfg.memory(), interopCfg.platform()); // Initialize cache extensions (if any). cacheExts = prepareCacheExtensions(interopCfg.cacheExtensions()); if (interopCfg.logger() != null) interopCfg.logger().setContext(platformCtx); // Initialize extensions (if any). extensions = prepareExtensions(ctx.plugins().extensions(PlatformPluginExtension.class)); } /** {@inheritDoc} */ @Override public void start(boolean activeOnStart) throws IgniteCheckedException { try (PlatformMemory mem = platformCtx.memory().allocate()) { PlatformOutputStream out = mem.output(); BinaryRawWriterEx writer = platformCtx.writer(out); writer.writeString(ctx.igniteInstanceName()); out.synchronize(); platformCtx.gateway().onStart(this, mem.pointer()); } // At this moment all necessary native libraries must be loaded, so we can process with store creation. storeLock.writeLock().lock(); try { for (StoreInfo store : pendingStores) registerStore0(store.store, store.convertBinary); pendingStores.clear(); started = true; } finally { storeLock.writeLock().unlock(); } // Add Interop node attributes. ctx.addNodeAttribute(PlatformUtils.ATTR_PLATFORM, interopCfg.platform()); } /** {@inheritDoc} */ @Override public void onKernalStop(boolean cancel) { startLatch.countDown(); } /** {@inheritDoc} */ @Override public void stop(boolean cancel) throws IgniteCheckedException { if (platformCtx != null) { stopped = true; platformCtx.gateway().onStop(); } } /** {@inheritDoc} */ @Override public Ignite ignite() { return ctx.grid(); } /** {@inheritDoc} */ @Override public long environmentPointer() { return platformCtx.gateway().environmentPointer(); } /** {@inheritDoc} */ @Override public void releaseStart() { startLatch.countDown(); } /** {@inheritDoc} */ @Override public void awaitStart() throws IgniteCheckedException { U.await(startLatch); } /** {@inheritDoc} */ @Override public PlatformContext context() { return platformCtx; } /** {@inheritDoc} */ @Override public PlatformTargetProxy cache(@Nullable String name) throws IgniteCheckedException { IgniteCacheProxy cache = (IgniteCacheProxy)ctx.grid().cache(name); if (cache == null) throw new IllegalArgumentException("Cache doesn't exist: " + name); return createPlatformCache(cache); } /** {@inheritDoc} */ @Override public PlatformTargetProxy createCache(@Nullable String name) throws IgniteCheckedException { IgniteCacheProxy cache = (IgniteCacheProxy)ctx.grid().createCache(name); assert cache != null; return createPlatformCache(cache); } /** {@inheritDoc} */ @Override public PlatformTargetProxy getOrCreateCache(@Nullable String name) throws IgniteCheckedException { IgniteCacheProxy cache = (IgniteCacheProxy)ctx.grid().getOrCreateCache(name); assert cache != null; return createPlatformCache(cache); } /** {@inheritDoc} */ @Override public PlatformTargetProxy createCacheFromConfig(long memPtr) throws IgniteCheckedException { BinaryRawReaderEx reader = platformCtx.reader(platformCtx.memory().get(memPtr)); CacheConfiguration cfg = PlatformConfigurationUtils.readCacheConfiguration(reader); IgniteCacheProxy cache = reader.readBoolean() ? (IgniteCacheProxy)ctx.grid().createCache(cfg, PlatformConfigurationUtils.readNearConfiguration(reader)) : (IgniteCacheProxy)ctx.grid().createCache(cfg); return createPlatformCache(cache); } /** {@inheritDoc} */ @Override public PlatformTargetProxy getOrCreateCacheFromConfig(long memPtr) throws IgniteCheckedException { BinaryRawReaderEx reader = platformCtx.reader(platformCtx.memory().get(memPtr)); CacheConfiguration cfg = PlatformConfigurationUtils.readCacheConfiguration(reader); IgniteCacheProxy cache = reader.readBoolean() ? (IgniteCacheProxy)ctx.grid().getOrCreateCache(cfg, PlatformConfigurationUtils.readNearConfiguration(reader)) : (IgniteCacheProxy)ctx.grid().getOrCreateCache(cfg); return createPlatformCache(cache); } /** {@inheritDoc} */ @Override public void destroyCache(@Nullable String name) throws IgniteCheckedException { ctx.grid().destroyCache(name); } /** {@inheritDoc} */ @Override public PlatformTargetProxy affinity(@Nullable String name) throws IgniteCheckedException { return proxy(new PlatformAffinity(platformCtx, ctx, name)); } /** {@inheritDoc} */ @Override public PlatformTargetProxy dataStreamer(@Nullable String cacheName, boolean keepBinary) throws IgniteCheckedException { IgniteDataStreamer ldr = ctx.dataStream().dataStreamer(cacheName); ldr.keepBinary(true); return proxy(new PlatformDataStreamer(platformCtx, cacheName, (DataStreamerImpl)ldr, keepBinary)); } /** {@inheritDoc} */ @Override public PlatformTargetProxy transactions() { return proxy(new PlatformTransactions(platformCtx)); } /** {@inheritDoc} */ @Override public PlatformTargetProxy projection() throws IgniteCheckedException { return proxy(new PlatformClusterGroup(platformCtx, ctx.grid().cluster())); } /** {@inheritDoc} */ @Override public PlatformTargetProxy compute(PlatformTargetProxy grp) { PlatformClusterGroup grp0 = (PlatformClusterGroup)grp.unwrap(); return proxy(new PlatformCompute(platformCtx, grp0.projection(), PlatformUtils.ATTR_PLATFORM)); } /** {@inheritDoc} */ @Override public PlatformTargetProxy message(PlatformTargetProxy grp) { PlatformClusterGroup grp0 = (PlatformClusterGroup)grp.unwrap(); return proxy(new PlatformMessaging(platformCtx, grp0.projection().ignite().message(grp0.projection()))); } /** {@inheritDoc} */ @Override public PlatformTargetProxy events(PlatformTargetProxy grp) { PlatformClusterGroup grp0 = (PlatformClusterGroup)grp.unwrap(); return proxy(new PlatformEvents(platformCtx, grp0.projection().ignite().events(grp0.projection()))); } /** {@inheritDoc} */ @Override public PlatformTargetProxy services(PlatformTargetProxy grp) { PlatformClusterGroup grp0 = (PlatformClusterGroup)grp.unwrap(); return proxy(new PlatformServices(platformCtx, grp0.projection().ignite().services(grp0.projection()), false)); } /** {@inheritDoc} */ @Override public PlatformTargetProxy extensions() { return null; } /** {@inheritDoc} */ @Override public PlatformTargetProxy extension(int id) { if (extensions != null && id < extensions.length) { PlatformPluginExtension ext = extensions[id]; if (ext != null) return proxy(ext.createTarget()); } throw new IgniteException("Platform extension is not registered [id=" + id + ']'); } /** {@inheritDoc} */ @Override public void registerStore(PlatformCacheStore store, boolean convertBinary) throws IgniteCheckedException { storeLock.readLock().lock(); try { if (stopped) throw new IgniteCheckedException("Failed to initialize interop store because node is stopping: " + store); if (started) registerStore0(store, convertBinary); else pendingStores.add(new StoreInfo(store, convertBinary)); } finally { storeLock.readLock().unlock(); } } /** {@inheritDoc} */ @Override public PlatformTargetProxy atomicLong(String name, long initVal, boolean create) throws IgniteException { GridCacheAtomicLongImpl atomicLong = (GridCacheAtomicLongImpl)ignite().atomicLong(name, initVal, create); if (atomicLong == null) return null; return proxy(new PlatformAtomicLong(platformCtx, atomicLong)); } /** {@inheritDoc} */ @Override public PlatformTargetProxy atomicSequence(String name, long initVal, boolean create) throws IgniteException { IgniteAtomicSequence atomicSeq = ignite().atomicSequence(name, initVal, create); if (atomicSeq == null) return null; return proxy(new PlatformAtomicSequence(platformCtx, atomicSeq)); } /** {@inheritDoc} */ @Override public PlatformTargetProxy atomicReference(String name, long memPtr, boolean create) throws IgniteException { PlatformAtomicReference ref = PlatformAtomicReference.createInstance(platformCtx, name, memPtr, create); return ref != null ? proxy(ref) : null; } /** {@inheritDoc} */ @Override public void onDisconnected(IgniteFuture<?> reconnectFut) throws IgniteCheckedException { platformCtx.gateway().onClientDisconnected(); // 1) onReconnected is called on all grid components. // 2) After all of grid components have completed their reconnection, reconnectFut is completed. reconnectFut.listen(new CI1<IgniteFuture<?>>() { @Override public void apply(IgniteFuture<?> future) { platformCtx.gateway().onClientReconnected(clusterRestarted); } }); } /** {@inheritDoc} */ @Override public IgniteInternalFuture<?> onReconnected(boolean clusterRestarted) throws IgniteCheckedException { // Save the flag value for callback of reconnectFut. this.clusterRestarted = clusterRestarted; return null; } /** {@inheritDoc} */ @Override public void getIgniteConfiguration(long memPtr) { PlatformOutputStream stream = platformCtx.memory().get(memPtr).output(); BinaryRawWriterEx writer = platformCtx.writer(stream); PlatformConfigurationUtils.writeIgniteConfiguration(writer, ignite().configuration()); stream.synchronize(); } /** {@inheritDoc} */ @Override public void getCacheNames(long memPtr) { PlatformOutputStream stream = platformCtx.memory().get(memPtr).output(); BinaryRawWriterEx writer = platformCtx.writer(stream); Collection<String> names = ignite().cacheNames(); writer.writeInt(names.size()); for (String name : names) writer.writeString(name); stream.synchronize(); } /** {@inheritDoc} */ @Override public PlatformTargetProxy createNearCache(@Nullable String cacheName, long memPtr) { NearCacheConfiguration cfg = getNearCacheConfiguration(memPtr); IgniteCacheProxy cache = (IgniteCacheProxy)ctx.grid().createNearCache(cacheName, cfg); return createPlatformCache(cache); } /** {@inheritDoc} */ @Override public PlatformTargetProxy getOrCreateNearCache(@Nullable String cacheName, long memPtr) { NearCacheConfiguration cfg = getNearCacheConfiguration(memPtr); IgniteCacheProxy cache = (IgniteCacheProxy)ctx.grid().getOrCreateNearCache(cacheName, cfg); return createPlatformCache(cache); } /** * Creates new platform cache. */ private PlatformTargetProxy createPlatformCache(IgniteCacheProxy cache) { return proxy(new PlatformCache(platformCtx, cache, false, cacheExts)); } /** {@inheritDoc} */ @Override public boolean loggerIsLevelEnabled(int level) { IgniteLogger log = ctx.grid().log(); switch (level) { case PlatformLogger.LVL_TRACE: return log.isTraceEnabled(); case PlatformLogger.LVL_DEBUG: return log.isDebugEnabled(); case PlatformLogger.LVL_INFO: return log.isInfoEnabled(); case PlatformLogger.LVL_WARN: return true; case PlatformLogger.LVL_ERROR: return true; default: assert false; } return false; } /** {@inheritDoc} */ @Override public void loggerLog(int level, String message, String category, String errorInfo) { IgniteLogger log = ctx.grid().log(); if (category != null) log = log.getLogger(category); Throwable err = errorInfo == null ? null : new IgniteException("Platform error:" + errorInfo); switch (level) { case PlatformLogger.LVL_TRACE: log.trace(message); break; case PlatformLogger.LVL_DEBUG: log.debug(message); break; case PlatformLogger.LVL_INFO: log.info(message); break; case PlatformLogger.LVL_WARN: log.warning(message, err); break; case PlatformLogger.LVL_ERROR: log.error(message, err); break; default: assert false; } } /** {@inheritDoc} */ @Override public PlatformTargetProxy binaryProcessor() { return proxy(new PlatformBinaryProcessor(platformCtx)); } /** * Gets the near cache config. * * @param memPtr Memory pointer. * @return Near config. */ private NearCacheConfiguration getNearCacheConfiguration(long memPtr) { assert memPtr != 0; BinaryRawReaderEx reader = platformCtx.reader(platformCtx.memory().get(memPtr)); return PlatformConfigurationUtils.readNearConfiguration(reader); } /** * Internal store initialization routine. * * @param store Store. * @param convertBinary Convert binary flag. * @throws IgniteCheckedException If failed. */ private void registerStore0(PlatformCacheStore store, boolean convertBinary) throws IgniteCheckedException { if (store instanceof PlatformDotNetCacheStore) { PlatformDotNetCacheStore store0 = (PlatformDotNetCacheStore)store; store0.initialize(ctx, convertBinary); } else throw new IgniteCheckedException("Unsupported interop store: " + store); } /** * Prepare cache extensions. * * @param cacheExts Original extensions. * @return Prepared extensions. */ private static PlatformCacheExtension[] prepareCacheExtensions(Collection<PlatformCacheExtension> cacheExts) { if (!F.isEmpty(cacheExts)) { int maxExtId = 0; Map<Integer, PlatformCacheExtension> idToExt = new HashMap<>(); for (PlatformCacheExtension cacheExt : cacheExts) { if (cacheExt == null) throw new IgniteException("Platform cache extension cannot be null."); if (cacheExt.id() < 0) throw new IgniteException("Platform cache extension ID cannot be negative: " + cacheExt); PlatformCacheExtension oldCacheExt = idToExt.put(cacheExt.id(), cacheExt); if (oldCacheExt != null) throw new IgniteException("Platform cache extensions cannot have the same ID [" + "id=" + cacheExt.id() + ", first=" + oldCacheExt + ", second=" + cacheExt + ']'); if (cacheExt.id() > maxExtId) maxExtId = cacheExt.id(); } PlatformCacheExtension[] res = new PlatformCacheExtension[maxExtId + 1]; for (PlatformCacheExtension cacheExt : cacheExts) res[cacheExt.id()]= cacheExt; return res; } else //noinspection ZeroLengthArrayAllocation return new PlatformCacheExtension[0]; } /** * Prepare extensions. * * @param exts Original extensions. * @return Prepared extensions. */ private static PlatformPluginExtension[] prepareExtensions(PlatformPluginExtension[] exts) { if (!F.isEmpty(exts)) { int maxExtId = 0; Map<Integer, PlatformPluginExtension> idToExt = new HashMap<>(); for (PlatformPluginExtension ext : exts) { if (ext == null) throw new IgniteException("Platform extension cannot be null."); if (ext.id() < 0) throw new IgniteException("Platform extension ID cannot be negative: " + ext); PlatformPluginExtension oldCacheExt = idToExt.put(ext.id(), ext); if (oldCacheExt != null) throw new IgniteException("Platform extensions cannot have the same ID [" + "id=" + ext.id() + ", first=" + oldCacheExt + ", second=" + ext + ']'); if (ext.id() > maxExtId) maxExtId = ext.id(); } PlatformPluginExtension[] res = new PlatformPluginExtension[maxExtId + 1]; for (PlatformPluginExtension ext : exts) res[ext.id()]= ext; return res; } else //noinspection ZeroLengthArrayAllocation return new PlatformPluginExtension[0]; } /** * Wraps target in a proxy. */ private PlatformTargetProxy proxy(PlatformTarget target) { return new PlatformTargetProxyImpl(target, platformCtx); } /** * Store and manager pair. */ private static class StoreInfo { /** Store. */ private final PlatformCacheStore store; /** Convert binary flag. */ private final boolean convertBinary; /** * Constructor. * * @param store Store. * @param convertBinary Convert binary flag. */ private StoreInfo(PlatformCacheStore store, boolean convertBinary) { this.store = store; this.convertBinary = convertBinary; } } }