/* 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.messaging; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import org.voltcore.messaging.TransactionInfoBaseMessage; /** * Used to reply a partition's portion of the work done as part of a * multi-partition procedure. It bundles together all of the state-modifying * FragmentTaskMessages into one message. Execution sites know how to run * this thing. * * This currently assumes that SQL-based plan fragments that modify * state have no dependencies. * * Initially, this is used to reply work during a pause-less rejoin. It * could also be useful for DR replication. * * One interesting guarantee this makes, when the list of FragmentTasks are * consumed, this class ensures there is one and only one final task, and * that it will be the last one in the list. Note, it'll make the last task * final if it isn't already. * */ public class FragmentTaskLogMessage extends TransactionInfoBaseMessage { /** Empty constructor for de-serialization */ FragmentTaskLogMessage() { super(); // all logged frag-tasks are always readwrite. m_isReadOnly = false; } public FragmentTaskLogMessage(long initiatorHSId, long coordinatorHSId, long txnId) { super(initiatorHSId, coordinatorHSId, txnId, 0, false, false); } private ArrayList<FragmentTaskMessage> m_fragmentTasks = new ArrayList<FragmentTaskMessage>(); @Override public int getSerializedSize() { int size = super.getSerializedSize(); size += 4; // fragment count as int for (FragmentTaskMessage ft : m_fragmentTasks) { size += ft.getSerializedSize(); } return size; } @Override public void flattenToBuffer(ByteBuffer buf) throws IOException { buf.put(VoltDbMessageFactory.FRAGMENT_TASK_LOG_ID); super.flattenToBuffer(buf); if (buf.position() != super.getSerializedSize()) { int size = super.getSerializedSize(); assert(buf.position() == size); } buf.putInt(m_fragmentTasks.size()); assert(buf.position() == super.getSerializedSize() + 4); for (FragmentTaskMessage ft : m_fragmentTasks) { int pre = buf.position(); int expected = pre + ft.getSerializedSize(); ft.flattenToSubMessageBuffer(buf); assert(buf.position() == expected); } assert(buf.capacity() == buf.position()); buf.limit(buf.position()); } @Override public void initFromBuffer(ByteBuffer buf) throws IOException { super.initFromBuffer(buf); int size = buf.getInt(); for (int i = 0; i < size; i++) { byte type = buf.get(); assert(type == VoltDbMessageFactory.FRAGMENT_TASK_ID); FragmentTaskMessage ft = new FragmentTaskMessage(); ft.initFromSubMessageBuffer(buf); m_fragmentTasks.add(ft); } } public void appendFragmentTask(FragmentTaskMessage ft) { assert(ft.getFragmentCount() > 0); m_fragmentTasks.add(ft); } public List<FragmentTaskMessage> getFragmentTasks() { return m_fragmentTasks; } }