/* 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.iv2;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import org.voltcore.messaging.Mailbox;
import org.voltcore.messaging.VoltMessage;
import org.voltdb.messaging.FragmentResponseMessage;
import org.voltdb.messaging.InitiateResponseMessage;
public class BufferedReadLog
{
public static class Item {
final InitiateResponseMessage m_initiateMsg;
final FragmentResponseMessage m_fragmentMsg;
final long m_safeSpHandle;
Item(InitiateResponseMessage msg) {
m_initiateMsg = msg;
m_fragmentMsg = null;
// SP transaction's SpHandle is the same as its transaction Id
m_safeSpHandle = msg.getSpHandle();
}
Item(FragmentResponseMessage msg, long txnId) {
m_initiateMsg = null;
m_fragmentMsg = msg;
// multi-fragments MP read's spHandle may be advanced between each fragment
// by scheduling any SP writes.
// we should use it's first SpHandle as a safe point to release reads instead.
m_safeSpHandle = txnId;
}
long getSafeSpHandle() {
return m_safeSpHandle;
}
long getResponseHSId() {
if (m_initiateMsg != null) {
return m_initiateMsg.getInitiatorHSId();
}
return m_fragmentMsg.getDestinationSiteId();
}
VoltMessage getMessage() {
if (m_initiateMsg != null) {
return m_initiateMsg;
}
return m_fragmentMsg;
}
@Override
public String toString() {
String msg = "Buffered read safe SpHandle " + TxnEgo.txnIdToString(m_safeSpHandle) + ", ";
msg += m_initiateMsg != null ? m_initiateMsg.toString() : m_fragmentMsg.toString();
return msg;
}
}
private static final int INIT_BUFFER_CAPACITY = 64;
final Deque<Item> m_bufferedReads;
BufferedReadLog()
{
m_bufferedReads = new ArrayDeque<Item>(INIT_BUFFER_CAPACITY);
}
public void offer(Mailbox mailbox, InitiateResponseMessage msg, long handle)
{
offerInternal(mailbox, new Item(msg), handle);
}
public void offer(Mailbox mailbox, FragmentResponseMessage msg, long txnId, long handle)
{
offerInternal(mailbox, new Item(msg, txnId), handle);
}
// SPI offers a new message.
private void offerInternal(Mailbox mailbox, Item item, long handle) {
m_bufferedReads.add(item);
releaseBufferedReads(mailbox, handle);
}
public void releaseBufferedReads(Mailbox mailbox, long spHandle)
{
Deque<Item> deq = m_bufferedReads;
Item item = null;
while ((item = deq.peek()) != null) {
if (item.getSafeSpHandle() <= spHandle) {
// when the sp reads' handle is less equal than truncation handle
// we know any previous write has been confirmed and it's safe to release.
mailbox.send(item.getResponseHSId(), item.getMessage());
deq.poll();
} else {
break;
}
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("BufferedReadLog size:").append(m_bufferedReads.size());
if (m_bufferedReads.size() > 0) {
sb.append(", contents:\n");
Iterator<Item> itr = m_bufferedReads.iterator();
for(int i = 0; itr.hasNext(); i++) {
sb.append("BufferedReadLog entry[").append(i).append("]:").append(itr.next().toString()).append("\n");
}
}
return sb.toString();
}
}