/* * 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.compute; import java.util.concurrent.Executor; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteCompute; import org.apache.ignite.binary.BinaryObject; import org.apache.ignite.cluster.ClusterGroup; import org.apache.ignite.compute.ComputeTaskFuture; import org.apache.ignite.internal.IgniteComputeImpl; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.binary.BinaryObjectImpl; import org.apache.ignite.internal.binary.BinaryRawReaderEx; import org.apache.ignite.internal.binary.BinaryRawWriterEx; import org.apache.ignite.internal.processors.platform.PlatformAbstractTarget; import org.apache.ignite.internal.processors.platform.PlatformContext; import org.apache.ignite.internal.processors.platform.PlatformTarget; import org.apache.ignite.internal.processors.platform.utils.PlatformFutureUtils; import org.apache.ignite.internal.processors.platform.utils.PlatformListenable; import org.apache.ignite.internal.util.future.IgniteFutureImpl; import org.apache.ignite.lang.IgniteClosure; import org.apache.ignite.lang.IgniteInClosure; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; import static org.apache.ignite.internal.processors.task.GridTaskThreadContextKey.TC_SUBGRID; /** * Interop compute. */ @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored", "UnusedDeclaration"}) public class PlatformCompute extends PlatformAbstractTarget { /** */ private static final int OP_AFFINITY = 1; /** */ private static final int OP_BROADCAST = 2; /** */ private static final int OP_EXEC = 3; /** */ private static final int OP_EXEC_ASYNC = 4; /** */ private static final int OP_UNICAST = 5; /** */ private static final int OP_WITH_NO_FAILOVER = 6; /** */ private static final int OP_WITH_TIMEOUT = 7; /** */ private static final int OP_EXEC_NATIVE = 8; /** Compute instance. */ private final IgniteComputeImpl compute; /** Compute instance for platform-only nodes. */ private final IgniteComputeImpl computeForPlatform; /** * Constructor. * * @param platformCtx Context. * @param grp Cluster group. */ public PlatformCompute(PlatformContext platformCtx, ClusterGroup grp, String platformAttr) { super(platformCtx); assert grp != null; assert platformAttr != null; compute = (IgniteComputeImpl)grp.ignite().compute(grp); ClusterGroup platformGrp = grp.forAttribute(platformAttr, platformCtx.platform()); computeForPlatform = (IgniteComputeImpl)grp.ignite().compute(platformGrp); } /** {@inheritDoc} */ @Override public PlatformTarget processInStreamOutObject(int type, BinaryRawReaderEx reader) throws IgniteCheckedException { switch (type) { case OP_UNICAST: return processClosures(reader.readLong(), reader, false, false); case OP_BROADCAST: return processClosures(reader.readLong(), reader, true, false); case OP_AFFINITY: return processClosures(reader.readLong(), reader, false, true); case OP_EXEC_NATIVE: { long taskPtr = reader.readLong(); long topVer = reader.readLong(); final PlatformFullTask task = new PlatformFullTask(platformCtx, computeForPlatform, taskPtr, topVer); return executeNative0(task); } case OP_EXEC_ASYNC: return wrapListenable((PlatformListenable) executeJavaTask(reader, true)); default: return super.processInStreamOutObject(type, reader); } } /** {@inheritDoc} */ @Override public long processInLongOutLong(int type, long val) throws IgniteCheckedException { switch (type) { case OP_WITH_TIMEOUT: { compute.withTimeout(val); computeForPlatform.withTimeout(val); return TRUE; } case OP_WITH_NO_FAILOVER: { compute.withNoFailover(); computeForPlatform.withNoFailover(); return TRUE; } } return super.processInLongOutLong(type, val); } /** * Process closure execution request. * @param taskPtr Task pointer. * @param reader Reader. * @param broadcast broadcast flag. */ private PlatformTarget processClosures(long taskPtr, BinaryRawReaderEx reader, boolean broadcast, boolean affinity) { PlatformAbstractTask task; int size = reader.readInt(); if (size == 1) { if (broadcast) { PlatformBroadcastingSingleClosureTask task0 = new PlatformBroadcastingSingleClosureTask(platformCtx, taskPtr); task0.job(nextClosureJob(task0, reader)); task = task0; } else if (affinity) { PlatformBalancingSingleClosureAffinityTask task0 = new PlatformBalancingSingleClosureAffinityTask(platformCtx, taskPtr); task0.job(nextClosureJob(task0, reader)); task0.affinity(reader.readString(), reader.readObjectDetached(), platformCtx.kernalContext()); task = task0; } else { PlatformBalancingSingleClosureTask task0 = new PlatformBalancingSingleClosureTask(platformCtx, taskPtr); task0.job(nextClosureJob(task0, reader)); task = task0; } } else { if (broadcast) task = new PlatformBroadcastingMultiClosureTask(platformCtx, taskPtr); else task = new PlatformBalancingMultiClosureTask(platformCtx, taskPtr); Collection<PlatformJob> jobs = new ArrayList<>(size); for (int i = 0; i < size; i++) jobs.add(nextClosureJob(task, reader)); if (broadcast) ((PlatformBroadcastingMultiClosureTask)task).jobs(jobs); else ((PlatformBalancingMultiClosureTask)task).jobs(jobs); } platformCtx.kernalContext().task().setThreadContext(TC_SUBGRID, computeForPlatform.clusterGroup().nodes()); return executeNative0(task); } /** * Read the next closure job from the reader. * * @param task Task. * @param reader Reader. * @return Closure job. */ private PlatformJob nextClosureJob(PlatformAbstractTask task, BinaryRawReaderEx reader) { return platformCtx.createClosureJob(task, reader.readLong(), reader.readObjectDetached()); } /** {@inheritDoc} */ @Override public void processInStreamOutStream(int type, BinaryRawReaderEx reader, BinaryRawWriterEx writer) throws IgniteCheckedException { switch (type) { case OP_EXEC: writer.writeObjectDetached(executeJavaTask(reader, false)); break; default: super.processInStreamOutStream(type, reader, writer); } } /** * Execute task. * * @param task Task. * @return Target. */ private PlatformTarget executeNative0(final PlatformAbstractTask task) { IgniteInternalFuture fut = computeForPlatform.executeAsync0(task, null); fut.listen(new IgniteInClosure<IgniteInternalFuture>() { private static final long serialVersionUID = 0L; @Override public void apply(IgniteInternalFuture fut) { try { fut.get(); task.onDone(null); } catch (IgniteCheckedException e) { task.onDone(e); } } }); return wrapListenable(PlatformFutureUtils.getListenable(fut)); } /** * Execute task taking arguments from the given reader. * * @param reader Reader. * @param async Execute asynchronously flag. * @return Task result. * @throws IgniteCheckedException On error. */ protected Object executeJavaTask(BinaryRawReaderEx reader, boolean async) throws IgniteCheckedException { String taskName = reader.readString(); boolean keepBinary = reader.readBoolean(); Object arg = reader.readObjectDetached(); Collection<UUID> nodeIds = readNodeIds(reader); IgniteCompute compute0 = computeForTask(nodeIds); if (!keepBinary && arg instanceof BinaryObjectImpl) arg = ((BinaryObject)arg).deserialize(); if (async) return readAndListenFuture(reader, new ComputeConvertingFuture(compute0.executeAsync(taskName, arg))); else return toBinary(compute0.execute(taskName, arg)); } /** * Convert object to binary form. * * @param src Source object. * @return Result. */ private Object toBinary(Object src) { return platformCtx.kernalContext().grid().binary().toBinary(src); } /** * Read node IDs. * * @param reader Reader. * @return Node IDs. */ protected Collection<UUID> readNodeIds(BinaryRawReaderEx reader) { if (reader.readBoolean()) { int len = reader.readInt(); List<UUID> res = new ArrayList<>(len); for (int i = 0; i < len; i++) res.add(reader.readUuid()); return res; } else return null; } /** * Get compute object for the given node IDs. * * @param nodeIds Node IDs. * @return Compute object. */ protected IgniteCompute computeForTask(Collection<UUID> nodeIds) { return nodeIds == null ? compute : platformCtx.kernalContext().grid().compute(compute.clusterGroup().forNodeIds(nodeIds)); } /** * Wraps ComputeTaskFuture as IgniteInternalFuture. */ protected class ComputeConvertingFuture implements IgniteInternalFuture { /** */ private final IgniteInternalFuture fut; /** * Ctor. * * @param fut Future to wrap. */ public ComputeConvertingFuture(ComputeTaskFuture fut) { this.fut = ((IgniteFutureImpl)fut).internalFuture(); } /** {@inheritDoc} */ @Override public Object get() throws IgniteCheckedException { return convertResult(fut.get()); } /** {@inheritDoc} */ @Override public Object get(long timeout) throws IgniteCheckedException { return convertResult(fut.get(timeout)); } /** {@inheritDoc} */ @Override public Object get(long timeout, TimeUnit unit) throws IgniteCheckedException { return convertResult(fut.get(timeout, unit)); } /** {@inheritDoc} */ @Override public Object getUninterruptibly() throws IgniteCheckedException { return convertResult(fut.get()); } /** {@inheritDoc} */ @Override public boolean cancel() throws IgniteCheckedException { return fut.cancel(); } /** {@inheritDoc} */ @Override public boolean isDone() { return fut.isDone(); } /** {@inheritDoc} */ @Override public boolean isCancelled() { return fut.isCancelled(); } /** {@inheritDoc} */ @Override public void listen(final IgniteInClosure lsnr) { fut.listen(new IgniteInClosure<IgniteInternalFuture>() { private static final long serialVersionUID = 0L; @Override public void apply(IgniteInternalFuture fut0) { lsnr.apply(ComputeConvertingFuture.this); } }); } /** {@inheritDoc} */ @Override public IgniteInternalFuture chain(IgniteClosure doneCb) { throw new UnsupportedOperationException("Chain operation is not supported."); } /** {@inheritDoc} */ @Override public IgniteInternalFuture chain(IgniteClosure doneCb, Executor exec) { throw new UnsupportedOperationException("Chain operation is not supported."); } /** {@inheritDoc} */ @Override public Throwable error() { return fut.error(); } /** {@inheritDoc} */ @Override public Object result() { return convertResult(fut.result()); } /** * Converts future result. * * @param obj Object to convert. * @return Result. */ protected Object convertResult(Object obj) { return toBinary(obj); } } }