/* 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 org.voltcore.messaging.VoltMessage;
import org.voltcore.utils.CoreUtils;
import org.voltcore.utils.Pair;
import org.voltdb.iv2.TxnEgo;
/**
* Message from replicas returning to new leader with repair log entries,
* while doing node rejoin promotion.
*
*/
public class Iv2RepairLogResponseMessage extends VoltMessage
{
private long m_requestId = 0;
private int m_sequence = 0;
private int m_ofTotal = 0;
private long m_handle = Long.MIN_VALUE;
private long m_txnId;
// Only set when sequence is 0
private long m_hashinatorVersion = Long.MIN_VALUE;
// The original task that is must be replicated for
// repair. Note: if the destination repair log is
// empty, a repair log response message is returned
// that has sequence = 0; ofTotal = 0 and a null
// payload (because the requester must know that the
// log request was processed and that no logs exist.)
private VoltMessage m_payload = null;
// Only set when sequence is 0
private byte [] m_hashinatorConfig = new byte[0];
/** Empty constructor for de-serialization */
Iv2RepairLogResponseMessage() {
super();
}
public Iv2RepairLogResponseMessage(long requestId, int sequence, int ofTotal,
long spHandle, long txnId, VoltMessage payload)
{
super();
m_requestId = requestId;
m_sequence = sequence;
m_ofTotal = ofTotal;
m_handle = spHandle;
m_txnId = txnId;
m_payload = payload;
}
public Iv2RepairLogResponseMessage(long requestId, int ofTotal,
long spHandle, long txnId,
Pair<Long, byte[]> versionedHashinatorConfig)
{
super();
m_requestId = requestId;
m_sequence = 0;
m_ofTotal = ofTotal;
m_handle = spHandle;
m_txnId = txnId;
m_hashinatorVersion = versionedHashinatorConfig.getFirst();
m_hashinatorConfig = versionedHashinatorConfig.getSecond();
}
public long getRequestId()
{
return m_requestId;
}
public int getSequence()
{
return m_sequence;
}
public int getOfTotal()
{
return m_ofTotal;
}
public long getHandle()
{
return m_handle;
}
public long getTxnId() {
return m_txnId;
}
public VoltMessage getPayload()
{
return m_payload;
}
/**
* Get version/config with the config in compressed (wire) format.
* @return version/config pair
*/
public Pair<Long, byte[]> getHashinatorVersionedConfig()
{
return Pair.of(m_hashinatorVersion, m_hashinatorConfig);
}
public boolean hasHashinatorConfig()
{
return m_sequence == 0 && m_hashinatorConfig.length > 0;
}
@Override
public int getSerializedSize()
{
int msgsize = super.getSerializedSize();
msgsize += 8; // requestId
msgsize += 4; // sequence
msgsize += 4; // ofTotal
msgsize += 8; // spHandle
msgsize += 8; // txnId
if (m_payload != null) {
msgsize += m_payload.getSerializedSize();
}
if (m_hashinatorConfig.length > 0) {
msgsize += 8; // hashinator version
msgsize += 4; // config size
msgsize += m_hashinatorConfig.length;
}
return msgsize;
}
@Override
public void flattenToBuffer(ByteBuffer buf) throws IOException
{
buf.put(VoltDbMessageFactory.IV2_REPAIR_LOG_RESPONSE);
buf.putLong(m_requestId);
buf.putInt(m_sequence);
buf.putInt(m_ofTotal);
buf.putLong(m_handle);
buf.putLong(m_txnId);
if (m_payload != null) {
ByteBuffer paybuf = ByteBuffer.allocate(m_payload.getSerializedSize());
m_payload.flattenToBuffer(paybuf);
if (paybuf.position() != 0) {
paybuf.flip();
}
buf.put(paybuf);
}
if (m_hashinatorConfig.length > 0) {
buf.putLong(m_hashinatorVersion);
buf.putInt(m_hashinatorConfig.length);
buf.put(m_hashinatorConfig);
}
assert(buf.capacity() == buf.position());
buf.limit(buf.position());
}
@Override
protected void initFromBuffer(ByteBuffer buf) throws IOException {
m_requestId = buf.getLong();
m_sequence = buf.getInt();
m_ofTotal = buf.getInt();
m_handle = buf.getLong();
m_txnId = buf.getLong();
// going inception.
// The first message in the repair log response stream is always a null
// ack, so don't try to deserialize a message that won't exist.
if (m_sequence != 0) {
VoltDbMessageFactory messageFactory = new VoltDbMessageFactory();
m_payload = messageFactory.createMessageFromBuffer(buf, m_sourceHSId);
}
// only the first packet with sequence 0 has the hashinator configurations
else {
m_payload = null;
m_hashinatorVersion = buf.getLong();
m_hashinatorConfig = new byte[buf.getInt()];
buf.get(m_hashinatorConfig);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("IV2 REPAIR_LOG_RESPONSE (FROM ");
sb.append(CoreUtils.hsIdToString(m_sourceHSId));
sb.append(" REQID: ");
sb.append(m_requestId);
sb.append(" SEQ: ");
sb.append(m_sequence);
sb.append(" OF TOTAL: ");
sb.append(m_ofTotal);
sb.append(" SP HANDLE: ");
sb.append(TxnEgo.txnIdToString(m_handle));
sb.append(" TXNID: ");
sb.append(TxnEgo.txnIdToString(m_txnId));
sb.append(" PAYLOAD: ");
if (m_payload == null) {
sb.append("null");
}
else {
sb.append(m_payload.toString());
}
if (m_hashinatorConfig.length > 0)
{
sb.append( " HASHINATOR VERSION: ");
sb.append(m_hashinatorVersion);
}
return sb.toString();
}
}