Package org.voltdb.iv2

Source Code of org.voltdb.iv2.TestRepairLog

/* 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 junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import org.junit.BeforeClass;
import org.junit.Test;
import org.voltcore.messaging.TransactionInfoBaseMessage;
import org.voltcore.messaging.VoltMessage;
import org.voltdb.TheHashinator;
import org.voltdb.TheHashinator.HashinatorType;
import org.voltdb.messaging.CompleteTransactionMessage;
import org.voltdb.messaging.FragmentTaskMessage;
import org.voltdb.messaging.Iv2InitiateTaskMessage;
import org.voltdb.messaging.Iv2RepairLogResponseMessage;

public class TestRepairLog
{
    VoltMessage truncInitMsg(long truncPt, long handle)
    {
        Iv2InitiateTaskMessage msg = mock(Iv2InitiateTaskMessage.class);
        when(msg.getTruncationHandle()).thenReturn(truncPt);
        when(msg.getSpHandle()).thenReturn(handle);
        return msg;
    }

    VoltMessage nonTruncInitMsg()
    {
        return truncInitMsg(Long.MIN_VALUE, 0);
    }

    VoltMessage truncFragMsg(long truncPt, long mpTxnId)
    {
        FragmentTaskMessage msg = mock(FragmentTaskMessage.class);
        when(msg.getTxnId()).thenReturn(mpTxnId);
        when(msg.getTruncationHandle()).thenReturn(truncPt);
        return msg;
    }

    VoltMessage truncCompleteMsg(long truncPt, long mpTxnId)
    {
        CompleteTransactionMessage msg = mock(CompleteTransactionMessage.class);
        when(msg.getTxnId()).thenReturn(mpTxnId);
        when(msg.getTruncationHandle()).thenReturn(truncPt);
        return msg;
    }

    // a message that should never be logged.
    private static class FooMessage extends VoltMessage
    {
        @Override
        protected void initFromBuffer(ByteBuffer buf) throws IOException {
        }

        @Override
        public void flattenToBuffer(ByteBuffer buf) throws IOException {
        }
    }

    @BeforeClass
    static public void initializeHashinator() {
        TheHashinator.setConfiguredHashinatorType(HashinatorType.ELASTIC);
        TheHashinator.initialize(TheHashinator.getConfiguredHashinatorClass(), TheHashinator.getConfigureBytes(8));
    }

    @Test
    public void testOffer()
    {
        // offer some various messages to log and check
        // that it keeps the expected ones.
        RepairLog rl = new RepairLog();
        VoltMessage m1 = nonTruncInitMsg();
        VoltMessage m2 = nonTruncInitMsg();

        rl.deliver(m1);
        rl.deliver(m2);

        List<Iv2RepairLogResponseMessage> contents = rl.contents(1l, false);
        assertEquals(3, contents.size());
        assertEquals(m1, contents.get(1).getPayload());
        assertEquals(m2, contents.get(2).getPayload());
    }

    @Test
    public void testOfferWithTruncation()
    {
        RepairLog rl = new RepairLog();

        // add m1
        VoltMessage m1 = truncInitMsg(0L, 1L);
        rl.deliver(m1);
        assertEquals(2, rl.contents(1L, false).size());

        // add m2
        VoltMessage m2 = truncInitMsg(0L, 2L);
        rl.deliver(m2);
        assertEquals(3, rl.contents(1L, false).size());

        // trim m1. add m3
        VoltMessage m3 = truncInitMsg(1L, 3L);
        rl.deliver(m3);
        assertEquals(3, rl.contents(1L, false).size());
        assertEquals(m2, rl.contents(1L, false).get(1).getPayload());
        assertEquals(2L, rl.contents(1L, false).get(1).getHandle());
        assertEquals(m3, rl.contents(1L, false).get(2).getPayload());
        assertEquals(3L, rl.contents(1L, false).get(2).getHandle());

    }

    @Test
    public void testOfferUneededMessage()
    {
        RepairLog rl = new RepairLog();
        VoltMessage m1 = truncInitMsg(0L, 1L);
        rl.deliver(m1);
        // deliver a non-logged message (this is the test).
        rl.deliver(new FooMessage());
        VoltMessage m2 = truncInitMsg(0L, 2L);
        rl.deliver(m2);
        assertEquals(3, rl.contents(1L, false).size());
        assertEquals(m1, rl.contents(1L, false).get(1).getPayload());
        assertEquals(m2, rl.contents(1L, false).get(2).getPayload());
    }

    @Test
    public void testOfferFragmentTaskMessage()
    {
        RepairLog rl = new RepairLog();

        // trunc(trunc point, txnId).
        VoltMessage m1 = truncFragMsg(0L, 1L);
        rl.deliver(m1);
        assertEquals(2, rl.contents(1L, false).size());

        VoltMessage m2 = truncFragMsg(0L, 2L);
        rl.deliver(m2);
        assertEquals(3, rl.contents(1L, false).size());

        // only the first message for a transaction is logged.
        VoltMessage m2b = truncFragMsg(0L, 2L);
        rl.deliver(m2b);
        assertEquals(3, rl.contents(1L, false).size());

        // trim m1. add m3
        VoltMessage m3 = truncFragMsg(1L, 3L);
        rl.deliver(m3);
        assertEquals(3, rl.contents(1L, false).size());
        assertEquals(m2, rl.contents(1L, false).get(1).getPayload());
        assertEquals(2L, rl.contents(1L, false).get(1).getTxnId());
        assertEquals(m3, rl.contents(1L, false).get(2).getPayload());
        assertEquals(3L, rl.contents(1L, false).get(2).getTxnId());
    }

    @Test
    public void testOfferCompleteMessage()
    {
        RepairLog rl = new RepairLog();

        // trunc(trunc point, txnId).
        VoltMessage m1 = truncCompleteMsg(0L, 1L);
        rl.deliver(m1);
        assertEquals(2, rl.contents(1L, false).size());

        VoltMessage m2 = truncCompleteMsg(0L, 2L);
        rl.deliver(m2);
        assertEquals(3, rl.contents(1L, false).size());

        // trim m1. add m3
        VoltMessage m3 = truncCompleteMsg(1L, 3L);
        rl.deliver(m3);
        assertEquals(3, rl.contents(1L, false).size());
        assertEquals(m2, rl.contents(1L, false).get(1).getPayload());
        assertEquals(2L, rl.contents(1L, false).get(1).getTxnId());
        assertEquals(m3, rl.contents(1L, false).get(2).getPayload());
        assertEquals(3L, rl.contents(1L, false).get(2).getTxnId());
    }


    @Test
    public void testTruncationAfterPromotion()
    {
        RepairLog rl = new RepairLog();
        VoltMessage m1 = truncInitMsg(0L, 1L);
        rl.deliver(m1);
        VoltMessage m2 = truncInitMsg(0L, 2L);
        rl.deliver(m2);
        assertEquals(3, rl.contents(1L, false).size());
        rl.setLeaderState(true);
        assertEquals(1, rl.contents(1L, false).size());
    }

    // validate the invariants on the RepairLog contents:
    // Every entry in the log should have a unique, constantly increasing SP handle.
    // There should be only one FragmentTaskMessage per MP TxnID
    // There should be at most one FragmentTaskMessage uncovered by a CompleteTransactionMessage
    // There should be no CompleteTransactionMessages indicating restart
    private void validateRepairLog(List<Iv2RepairLogResponseMessage> stuff)
    {
        long prevHandle = Long.MIN_VALUE;
        Long mpTxnId = null;
        for (Iv2RepairLogResponseMessage imsg : stuff) {
            if (imsg.getSequence() > 0) {
                assertTrue(imsg.getHandle() > prevHandle);
                prevHandle = imsg.getHandle();
                if (imsg.getPayload() instanceof FragmentTaskMessage) {
                    assertEquals(null, mpTxnId);
                    mpTxnId = imsg.getTxnId();
                } else if (imsg.getPayload() instanceof CompleteTransactionMessage) {
                    // can see bare CompleteTransactionMessage, but if we've got an MP
                    // in progress this should close it
                    assertFalse(((CompleteTransactionMessage)imsg.getPayload()).isRestart());
                    if (mpTxnId != null) {
                        assertEquals((long)mpTxnId, imsg.getTxnId());
                    }
                    mpTxnId = null;
                }
            } else {
                assertTrue(imsg.hasHashinatorConfig());
            }
        }
    }

    @Test
    public void testFuzz()
    {
        TxnEgo sphandle = TxnEgo.makeZero(0);
        sphandle = sphandle.makeNext();
        RandomMsgGenerator msgGen = new RandomMsgGenerator();
        RepairLog dut = new RepairLog();
        for (int i = 0; i < 4000; i++) {
            // get next message, update the sphandle according to SpScheduler rules,
            // but only submit messages that would have been forwarded by the master
            // to the repair log.
            TransactionInfoBaseMessage msg = msgGen.generateRandomMessageInStream();
            msg.setSpHandle(sphandle.getTxnId());
            sphandle = sphandle.makeNext();
            if (!msg.isReadOnly() || msg instanceof CompleteTransactionMessage) {
                dut.deliver(msg);
            }
        }
        List<Iv2RepairLogResponseMessage> stuff = dut.contents(1l, false);
        validateRepairLog(stuff);
        // Also check the MP version
        stuff = dut.contents(1l, true);
        validateRepairLog(stuff);
    }

    @Test
    public void testPerformance()
    {
        RepairLog dut = new RepairLog();
        // First, add and truncate SP transactions with no MPs
        dut.deliver(truncInitMsg(Long.MIN_VALUE, 0));
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++)
        {
            VoltMessage msg = truncInitMsg(i, i + 1);
            dut.deliver(msg);
        }
        long end = System.currentTimeMillis();
        long duration1 = end - start;
        System.out.println("Time to deliver 100,000 SPs: " + duration1);

        // Now, add 40000 MP messages and then see how long it takes to do the SPs
        dut = new RepairLog();
        dut.deliver(truncInitMsg(Long.MIN_VALUE, 0));
        for (int i = 0; i < 40000; i++) {
            dut.deliver(truncCompleteMsg(Long.MIN_VALUE, i));
        }
        start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++)
        {
            VoltMessage msg = truncInitMsg(i, i + 1);
            dut.deliver(msg);
        }
        end = System.currentTimeMillis();
        long duration2 = end - start;
        System.out.println("Time to deliver 100,000 SPs: " + duration2);
        // rough check, verify that the two don't differ by more than 20%
        if (duration2 > duration1) {
            long delta = Math.abs(duration2 - duration1);
            float deltaPercent = delta / (float)duration1;
            assertTrue("SP deliver performance with stored MP logs exceeds allowed hit of 20%, was: " +
                    (deltaPercent * 100) + "%.",
                    deltaPercent < .20);
        }
    }

    @Test
    public void testComparator()
    {
        RepairLog dut = new RepairLog();
        Random rand = new Random();
        List<RepairLog.Item> items = new ArrayList<RepairLog.Item>();
        for (int i = 0; i < 1000000; i++) {
            RepairLog.Item item = new RepairLog.Item(true, null, rand.nextInt(), i);
            items.add(item);
        }
        Collections.sort(items, dut.m_handleComparator);
    }
}
TOP

Related Classes of org.voltdb.iv2.TestRepairLog

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.