/* This file is part of VoltDB.
* Copyright (C) 2008-2014 VoltDB Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.voltdb.iv2;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import junit.framework.TestCase;
import org.json_voltpatches.JSONException;
import org.json_voltpatches.JSONObject;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.voltcore.messaging.Mailbox;
import org.voltcore.messaging.TransactionInfoBaseMessage;
import org.voltcore.zk.MapCache;
import org.voltdb.CommandLog;
import org.voltdb.ProcedureRunner;
import org.voltdb.SnapshotCompletionMonitor;
import org.voltdb.StarvationTracker;
import org.voltdb.VoltDBInterface;
import org.voltdb.messaging.CompleteTransactionMessage;
import com.google_voltpatches.common.collect.ImmutableMap;
public class TestSpSchedulerSpHandle extends TestCase
{
Mailbox mbox;
SnapshotCompletionMonitor snapMonitor;
MapCache iv2masters;
VoltDBInterface vdbi;
ProcedureRunner runner;
Scheduler dut;
RandomMsgGenerator msgGen;
static final String MockSPName = "MOCKSP";
static final long dut_hsid = 11223344l;
private static SiteTaskerQueue getSiteTaskerQueue() {
SiteTaskerQueue queue = new SiteTaskerQueue();
queue.setStarvationTracker(new StarvationTracker(0));
return queue;
}
@Override
public void setUp()
{
msgGen = new RandomMsgGenerator();
}
public void createObjs() throws JSONException
{
mbox = mock(Mailbox.class);
when(mbox.getHSId()).thenReturn(dut_hsid);
iv2masters = mock(MapCache.class);
snapMonitor = mock(SnapshotCompletionMonitor.class);
// make fake MapCache of iv2masters
HashMap<String,JSONObject> fakecache = new HashMap<String, JSONObject>();
fakecache.put("0", new JSONObject("{hsid:0}"));
when(iv2masters.pointInTimeCache()).thenReturn(ImmutableMap.copyOf(fakecache));
dut = new SpScheduler(0, getSiteTaskerQueue(), snapMonitor);
dut.setMailbox(mbox);
dut.setCommandLog(mock(CommandLog.class));
dut.setLock(mbox);
}
// Validate the contract on the SP handles generated by the SpScheduler at the master for a partition.
// Every new message replicated by the partition master to its partition
// replicas should have a unique, constantly increasing SP handle.
// Read-only invocations and fragments are not replicated but advance the internal SP handle
// CompleteTransactionMessages get farmed out everywhere for every MP transaction, regardless of
// type
@Test
public void testBasicSpHandleMessageStream() throws Exception
{
TxnEgo currentHandle = TxnEgo.makeZero(0);
// SpScheduler calls advance before assignment
createObjs();
dut.setLeaderState(true);
List<Long> replicas = new ArrayList<Long>();
replicas.add(2l);
dut.updateReplicas(replicas, null);
int msgcount = 0;
for (int i = 0; i < 4000; i++) {
TransactionInfoBaseMessage msg = msgGen.generateRandomMessageInStream();
dut.deliver(msg);
// only non-reads should do checks, all others just keep moving
// Capture the InitiateTaskMessage that gets sent to the replica so we can test it,
// use it for response construction, etc.
if (!msg.isReadOnly() || msg instanceof CompleteTransactionMessage)
{
currentHandle = currentHandle.makeNext();
msgcount++;
ArgumentCaptor<TransactionInfoBaseMessage> replmsg =
ArgumentCaptor.forClass(TransactionInfoBaseMessage.class);
verify(mbox, times(msgcount)).send(eq(new long[] {2l}), replmsg.capture());
assertEquals("Failed on msg: " + replmsg.getValue(),
currentHandle.getTxnId(), replmsg.getValue().getSpHandle());
}
}
}
}