/* This file is part of VoltDB. * Copyright (C) 2008-2017 VoltDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with VoltDB. If not, see <http://www.gnu.org/licenses/>. */ package org.voltdb.sysprocs; import java.io.ByteArrayInputStream; import java.io.ObjectInputStream; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.voltdb.DRConsumerDrIdTracker; import org.voltdb.DRLogSegmentId; import org.voltdb.DependencyPair; import org.voltdb.ParameterSet; import org.voltdb.SystemProcedureExecutionContext; import org.voltdb.TupleStreamStateInfo; import org.voltdb.VoltSystemProcedure; import org.voltdb.VoltTable; import org.voltdb.VoltTable.ColumnInfo; import org.voltdb.VoltType; import org.voltdb.dtxn.DtxnConstants; import org.voltdb.jni.ExecutionEngine.TaskType; import org.voltdb.utils.VoltTableUtil; public class ExecuteTask extends VoltSystemProcedure { private static final int DEP_executeTask = (int) SysProcFragmentId.PF_executeTask | DtxnConstants.MULTIPARTITION_DEPENDENCY; private static final int DEP_executeTaskAggregate = (int) SysProcFragmentId.PF_executeTaskAggregate; static VoltTable createDRTupleStreamStateResultTable() { return new VoltTable(new VoltTable.ColumnInfo(CNAME_HOST_ID, CTYPE_ID), new VoltTable.ColumnInfo(CNAME_PARTITION_ID, CTYPE_ID), new VoltTable.ColumnInfo("REPLICATED", VoltType.TINYINT), new VoltTable.ColumnInfo("SEQUENCE_NUMBER", VoltType.BIGINT), new VoltTable.ColumnInfo("SP_UNIQUEID", VoltType.BIGINT), new VoltTable.ColumnInfo("MP_UNIUQEID", VoltType.BIGINT), new VoltTable.ColumnInfo("DR_VERSION", VoltType.INTEGER)); } @Override public long[] getPlanFragmentIds() { return new long[]{SysProcFragmentId.PF_executeTask, SysProcFragmentId.PF_executeTaskAggregate}; } @Override public DependencyPair executePlanFragment( Map<Integer, List<VoltTable>> dependencies, long fragmentId, ParameterSet params, SystemProcedureExecutionContext context) { if (fragmentId == SysProcFragmentId.PF_executeTask) { assert(params.toArray()[0] != null); byte[] payload = (byte [])params.toArray()[0]; ByteBuffer buffer = ByteBuffer.wrap(payload); int taskId = buffer.getInt(); TaskType taskType = TaskType.values()[taskId]; VoltTable result = null; switch (taskType) { // @VALIDATE_PARTITIONING is an existing system stored procedure, don't bother to provide another implementation here. case GET_DR_TUPLESTREAM_STATE: { TupleStreamStateInfo stateInfo = context.getSiteProcedureConnection().getDRTupleStreamStateInfo(); result = createDRTupleStreamStateResultTable(); result.addRow(context.getHostId(), context.getPartitionId(), 0, stateInfo.partitionInfo.drId, stateInfo.partitionInfo.spUniqueId, stateInfo.partitionInfo.mpUniqueId, stateInfo.drVersion); if (stateInfo.containsReplicatedStreamInfo) { result.addRow(context.getHostId(), context.getPartitionId(), 1, stateInfo.replicatedInfo.drId, stateInfo.replicatedInfo.spUniqueId, stateInfo.replicatedInfo.mpUniqueId, stateInfo.drVersion); } break; } case SET_DR_SEQUENCE_NUMBERS: { result = new VoltTable(STATUS_SCHEMA); result.addRow(STATUS_OK); long partitionSequenceNumber = buffer.getLong(); long mpSequenceNumber = buffer.getLong(); context.getSiteProcedureConnection().setDRSequenceNumbers(partitionSequenceNumber, mpSequenceNumber); break; } case SET_DR_PROTOCOL_VERSION: { result = new VoltTable(STATUS_SCHEMA); result.addRow(STATUS_OK); int drVersion = buffer.getInt(); int createStartStream = buffer.getInt(); if (createStartStream > 0) { long uniqueId = m_runner.getUniqueId(); long spHandle = m_runner.getTxnState().getNotice().getSpHandle(); context.getSiteProcedureConnection().setDRProtocolVersion(drVersion, spHandle, uniqueId); } else { context.getSiteProcedureConnection().setDRProtocolVersion(drVersion); } break; } case SET_DRID_TRACKER_START: { result = new VoltTable(STATUS_SCHEMA, new ColumnInfo("LOCAL_UNIQUEID", VoltType.BIGINT)); try { byte[] paramBuf = new byte[buffer.remaining()]; buffer.get(paramBuf); ByteArrayInputStream bais = new ByteArrayInputStream(paramBuf); ObjectInputStream ois = new ObjectInputStream(bais); Map<Integer, DRLogSegmentId> lastAckedIds = (Map<Integer, DRLogSegmentId>)ois.readObject(); for (Entry<Integer, DRLogSegmentId> e : lastAckedIds.entrySet()) { if (!DRLogSegmentId.isEmptyDRId(e.getValue().drId)) { int producerPartitionId = e.getKey(); int producerClusterId = DRLogSegmentId.getClusterIdFromDRId(e.getValue().drId); DRConsumerDrIdTracker tracker = DRConsumerDrIdTracker.createPartitionTracker(e.getValue().drId, e.getValue().spUniqueId, e.getValue().mpUniqueId, producerPartitionId); context.appendApplyBinaryLogTxns(producerClusterId, producerPartitionId, -1L, tracker); } } result.addRow(STATUS_OK, m_runner.getTxnState().uniqueId); } catch (Exception e) { e.printStackTrace(); result.addRow("FAILURE"); } break; } case RESET_DR_APPLIED_TRACKER: { result = new VoltTable(STATUS_SCHEMA); result.addRow(STATUS_OK); context.resetDrAppliedTracker(); break; } case SET_MERGED_DRID_TRACKER: { result = new VoltTable(STATUS_SCHEMA); try { byte[] paramBuf = new byte[buffer.remaining()]; buffer.get(paramBuf); ByteArrayInputStream bais = new ByteArrayInputStream(paramBuf); ObjectInputStream ois = new ObjectInputStream(bais); Map<Integer, Map<Integer, DRConsumerDrIdTracker>> clusterToPartitionMap = (Map<Integer, Map<Integer, DRConsumerDrIdTracker>>)ois.readObject(); context.recoverWithDrAppliedTrackers(clusterToPartitionMap); result.addRow(STATUS_OK); } catch (Exception e) { e.printStackTrace(); result.addRow("FAILURE"); } break; } case INIT_DRID_TRACKER: { result = new VoltTable(STATUS_SCHEMA); try { byte[] paramBuf = new byte[buffer.remaining()]; buffer.get(paramBuf); ByteArrayInputStream bais = new ByteArrayInputStream(paramBuf); ObjectInputStream ois = new ObjectInputStream(bais); Map<Byte, Integer> clusterIdToPartitionCountMap = (Map<Byte, Integer>)ois.readObject(); context.initDRAppliedTracker(clusterIdToPartitionCountMap); result.addRow(STATUS_OK); } catch (Exception e) { e.printStackTrace(); result.addRow("FAILURE"); } break; } default: throw new VoltAbortException("Unable to find the task associated with the given task id"); } return new DependencyPair.TableDependencyPair(DEP_executeTask, result); } else if (fragmentId == SysProcFragmentId.PF_executeTaskAggregate) { VoltTable unionTable = VoltTableUtil.unionTables(dependencies.get(DEP_executeTask)); return new DependencyPair.TableDependencyPair(DEP_executeTaskAggregate, unionTable); } assert false; return null; } public VoltTable[] run(SystemProcedureExecutionContext ctx, byte[] params) { SynthesizedPlanFragment pfs[] = new SynthesizedPlanFragment[2]; pfs[0] = new SynthesizedPlanFragment(); pfs[0].fragmentId = SysProcFragmentId.PF_executeTask; pfs[0].inputDepIds = new int[]{}; pfs[0].outputDepId = DEP_executeTask; pfs[0].multipartition = true; pfs[0].parameters = ParameterSet.fromArrayNoCopy(new Object[] { params }); pfs[1] = new SynthesizedPlanFragment(); pfs[1].fragmentId = SysProcFragmentId.PF_executeTaskAggregate; pfs[1].inputDepIds = new int[]{DEP_executeTask}; pfs[1].outputDepId = DEP_executeTaskAggregate; pfs[1].multipartition = false; pfs[1].parameters = ParameterSet.emptyParameterSet(); VoltTable[] results = executeSysProcPlanFragments(pfs, DEP_executeTaskAggregate); return results; } }