/* This file is part of VoltDB. * Copyright (C) 2008-2017 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.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; 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.utils.CoreUtils; 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.Iv2InitiateTaskMessage; 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)); final CommandLog cl = mock(CommandLog.class); doReturn(CoreUtils.COMPLETED_FUTURE).when(cl).log(any(Iv2InitiateTaskMessage.class), anyLong(), any(int[].class), any(CommandLog.DurabilityListener.class), any(TransactionTask.class)); dut = new SpScheduler(0, getSiteTaskerQueue(), snapMonitor); dut.setMailbox(mbox); dut.setCommandLog(cl); 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 or not 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); ArgumentCaptor<TransactionInfoBaseMessage> replmsg = ArgumentCaptor.forClass(TransactionInfoBaseMessage.class); if (msg.isReadOnly()) { // Read-only invocations and fragments are not replicated verify(mbox, times(msgcount)).send(eq(new long[] {2l}), replmsg.capture()); } else { msgcount++; // Capture the InitiateTaskMessage that gets sent to the replica so we can test it, // use it for response construction, etc. currentHandle = currentHandle.makeNext(); verify(mbox, times(msgcount)).send(eq(new long[] {2l}), replmsg.capture()); // assertEquals("Failed on msg: " + replmsg.getValue(), // currentHandle.getTxnId(), replmsg.getValue().getSpHandle()); } } } }