/* * 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.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.binary.BinaryRawReaderEx; import org.apache.ignite.internal.processors.platform.PlatformContext; import org.apache.ignite.internal.processors.platform.PlatformProcessor; import org.apache.ignite.internal.processors.platform.memory.PlatformInputStream; 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.utils.PlatformUtils; import org.jetbrains.annotations.Nullable; /** * Wrapper around job created in native platform. * <p> * If the job is expected to be executed locally, it contains only pointer to the corresponding entity in the native * platform. In case of topology change or failover, job is serialized on demand. * <p> * If we know in advance that the job is to be executed on remote node, then it is serialized into byte array right * away. * <p> * This class is not thread safe. */ @SuppressWarnings({"FieldCanBeLocal"}) public class PlatformFullJob extends PlatformAbstractJob { /** */ private static final long serialVersionUID = 0L; /** Job is initialized. */ private static final byte STATE_INIT = 0; /** Job is running. */ private static final byte STATE_RUNNING = 1; /** Job execution completed. */ private static final byte STATE_COMPLETED = 2; /** Job cancelled. */ private static final byte STATE_CANCELLED = 3; /** Platform context. */ private transient PlatformContext ctx; /** Serialized job. */ private transient byte state; /** * {@link Externalizable} support. */ @SuppressWarnings("UnusedDeclaration") public PlatformFullJob() { // No-op. } /** * Constructor. * * @param ctx Platform context. * @param task Parent task. * @param ptr Job pointer. * @param job Job. */ public PlatformFullJob(PlatformContext ctx, PlatformAbstractTask task, long ptr, Object job) { super(task, ptr, job); this.ctx = ctx; } /** {@inheritDoc} */ @Nullable @Override public Object execute0(PlatformContext ctx) throws IgniteCheckedException { boolean cancel = false; synchronized (this) { // 1. Create job if necessary. if (task == null) { assert ptr == 0; createJob(ctx); } else assert ptr != 0; // 2. Set correct state. if (state == STATE_INIT) state = STATE_RUNNING; else { assert state == STATE_CANCELLED; cancel = true; } } try { if (task != null) return runLocal(ctx, cancel); else { try (PlatformMemory mem = ctx.memory().allocate()) { PlatformOutputStream out = mem.output(); out.writeLong(ptr); out.writeBoolean(cancel); // cancel out.synchronize(); ctx.gateway().computeJobExecute(mem.pointer()); PlatformInputStream in = mem.input(); in.synchronize(); BinaryRawReaderEx reader = ctx.reader(in); return PlatformUtils.readInvocationResult(ctx, reader); } } } finally { synchronized (this) { if (task == null) { assert ptr != 0; ctx.gateway().computeJobDestroy(ptr); } if (state == STATE_RUNNING) state = STATE_COMPLETED; } } } /** {@inheritDoc} */ @Override public void cancel() { PlatformProcessor proc = PlatformUtils.platformProcessor(ignite); synchronized (this) { if (state == STATE_INIT) state = STATE_CANCELLED; else if (state == STATE_RUNNING) { assert ptr != 0; try { proc.context().gateway().computeJobCancel(ptr); } finally { state = STATE_CANCELLED; } } } } /** {@inheritDoc} */ @Override public void writeExternal(ObjectOutput out) throws IOException { if (job == null) { assert ptr != 0; try { if (task != null) { if (task.onJobLock()) { try { serialize(); } finally { task.onJobUnlock(); } } else throw new IgniteCheckedException("Task already completed: " + task); } else serialize(); } catch (IgniteCheckedException e) { throw new IOException("Failed to serialize interop job.", e); } } assert job != null; out.writeObject(job); } /** {@inheritDoc} */ @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { job = in.readObject(); } /** * Internal job serialization routine. * * @throws org.apache.ignite.IgniteCheckedException If failed. */ private void serialize() throws IgniteCheckedException { try (PlatformMemory mem = ctx.memory().allocate()) { PlatformInputStream in = mem.input(); boolean res = ctx.gateway().computeJobSerialize(ptr, mem.pointer()) == 1; in.synchronize(); BinaryRawReaderEx reader = ctx.reader(in); if (res) job = reader.readObjectDetached(); else throw new IgniteCheckedException(reader.readString()); } } }