com.linkedin.databus.core.TestDbusEventBufferAppendEvents.java Source code

Java tutorial

Introduction

Here is the source code for com.linkedin.databus.core.TestDbusEventBufferAppendEvents.java

Source

/**
 *
 */
package com.linkedin.databus.core;
/*
 *
 * Copyright 2013 LinkedIn Corp. All rights reserved
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

import static org.testng.AssertJUnit.assertEquals;

import java.io.File;
import java.util.Arrays;
import java.util.Vector;

import junit.framework.Assert;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import com.linkedin.databus.core.DbusEventBuffer.AllocationPolicy;
import com.linkedin.databus.core.DbusEventBuffer.QueuePolicy;
import com.linkedin.databus.core.test.DbusEventAppender;
import com.linkedin.databus.core.test.DbusEventBufferReflector;
import com.linkedin.databus.core.test.DbusEventGenerator;
import com.linkedin.databus.core.util.BufferPositionParser;
import com.linkedin.databus.core.util.InvalidConfigException;
import com.linkedin.databus2.core.AssertLevel;
import com.linkedin.databus2.test.TestUtil;

/**
 * Seperate some tests from TestDbusEventBuffer since it has grown a lot.
 */
public class TestDbusEventBufferAppendEvents {

    @BeforeClass
    public void setupClass() {
        TestUtil.setupLogging(true, "TestDbusEventBufferAppendEvents" + System.currentTimeMillis() + ".log",
                Level.INFO);
    }

    @Test
    /**
     * Test the case where we have a big event that overlaps both the DbusEventBuffer head and the
     * limit of the current buffer.
     */
    public void testAppendBigEventsHeadScnOverlap() throws Exception {
        final Logger log = Logger.getLogger("TestDbusEventBuffer.testAppendBigEventsHeadScnOverlap");
        log.setLevel(Level.INFO);
        log.info("starting");
        final DbusEventBuffer dbusBuf = new DbusEventBuffer(TestDbusEventBuffer.getConfig(1200, 500, 100, 500,
                AllocationPolicy.HEAP_MEMORY, QueuePolicy.OVERWRITE_ON_WRITE, AssertLevel.ALL));
        BufferPositionParser parser = dbusBuf.getBufferPositionParser();
        log.info("append initial events");
        DbusEventGenerator generator = new DbusEventGenerator();
        Vector<DbusEvent> events = new Vector<DbusEvent>();
        generator.generateEvents(7, 1, 120, 39, events);

        // Add events to the EventBuffer. Now the buffer is full
        DbusEventAppender appender = new DbusEventAppender(events, dbusBuf, null);
        appender.run(); // running in the same thread
        log.info("Head:" + parser.toString(dbusBuf.getHead()) + ", Tail:" + parser.toString(dbusBuf.getTail()));
        log.info("Num buffers: " + dbusBuf.getBuffer().length);
        log.info("Buffer: " + Arrays.toString(dbusBuf.getBuffer()));

        long headPos = dbusBuf.getHead();
        long tailPos = dbusBuf.getTail();
        long headGenId = parser.bufferGenId(headPos);
        long headIndexId = parser.bufferIndex(headPos);
        long headOffset = parser.bufferOffset(headPos);
        long tailGenId = parser.bufferGenId(tailPos);
        long tailIndexId = parser.bufferIndex(tailPos);
        long tailOffset = parser.bufferOffset(tailPos);

        assertEquals(0, headGenId);
        assertEquals(0, headIndexId);
        assertEquals(222, headOffset);
        assertEquals(1, tailGenId);
        assertEquals(0, tailIndexId);
        assertEquals(61, tailOffset);

        log.info("append windows with one small and one big event");
        generator = new DbusEventGenerator(100);
        events = new Vector<DbusEvent>();
        generator.generateEvents(1, 1, 280, 139, events);
        generator.generateEvents(1, 1, 480, 339, events);

        // Add events to the EventBuffer. Now the buffer is full
        appender = new DbusEventAppender(events, dbusBuf, null);
        appender.run(); // running in the same thread
        log.info("Head:" + parser.toString(dbusBuf.getHead()) + ", Tail:" + parser.toString(dbusBuf.getTail()));
        log.info("Num buffers: " + dbusBuf.getBuffer().length);
        log.info("Buffer: " + Arrays.toString(dbusBuf.getBuffer()));

        headPos = dbusBuf.getHead();
        tailPos = dbusBuf.getTail();
        headGenId = parser.bufferGenId(headPos);
        headIndexId = parser.bufferIndex(headPos);
        headOffset = parser.bufferOffset(headPos);
        tailGenId = parser.bufferGenId(tailPos);
        tailIndexId = parser.bufferIndex(tailPos);
        tailOffset = parser.bufferOffset(tailPos);

        assertEquals(0, headGenId);
        assertEquals(2, headIndexId);
        assertEquals(61, headOffset);
        assertEquals(1, tailIndexId);
        assertEquals(461, tailOffset);
        assertEquals(322, dbusBuf.getBuffer()[0].limit());

        log.info("finished");
    }

    @Test
    /**
     * Test the following case:
     * A buffer (one of 3) has CWP = 222 and head at 383. Limit is 483 (capacity 500)
     * we create one event of size 211 (61 + 150 payload).
     * we call appender.run() which will add one EOP event (61) and the newly created event 211.
     * The end of event offset will be 222 + 211 + 61 = 494. It should update limit to this value.
     * because of the bug (DDSDBUS-1515) it used to fail when end of event goes beyond current limit
     * but less than the capacity
     * Now it should pass
     */
    public void testAppendEventWhenLimitLessThanCapacity() throws Exception {
        final Logger log = Logger.getLogger("TestDbusEventBuffer.testAppendEventWhenLimitLessThanCapacity");
        log.setLevel(Level.INFO);
        log.info("starting");
        final DbusEventBuffer dbusBuf = new DbusEventBuffer(TestDbusEventBuffer.getConfig(1200, 500, 100, 500,
                AllocationPolicy.HEAP_MEMORY, QueuePolicy.OVERWRITE_ON_WRITE, AssertLevel.ALL));
        BufferPositionParser parser = dbusBuf.getBufferPositionParser();
        log.info("append initial events");
        DbusEventGenerator generator = new DbusEventGenerator();
        Vector<DbusEvent> events = new Vector<DbusEvent>();
        generator.generateEvents(11, 1, 120, 39, events);

        // Add events to the EventBuffer. Now the buffer is full
        DbusEventAppender appender = new DbusEventAppender(events, dbusBuf, null);
        appender.run(); // running in the same thread
        log.info("Head:" + parser.toString(dbusBuf.getHead()) + ",Tail:" + parser.toString(dbusBuf.getTail()));
        log.info("Num buffers :" + dbusBuf.getBuffer().length);
        log.info("Buffer :" + Arrays.toString(dbusBuf.getBuffer()));

        long headPos = dbusBuf.getHead();
        long tailPos = dbusBuf.getTail();
        long headGenId = parser.bufferGenId(headPos);
        long headIndexId = parser.bufferIndex(headPos);
        long headOffset = parser.bufferOffset(headPos);
        long tailGenId = parser.bufferGenId(tailPos);
        long tailIndexId = parser.bufferIndex(tailPos);
        long tailOffset = parser.bufferOffset(tailPos);

        // current writing position should be 222 (id=1)
        assertEquals(0, headGenId);
        assertEquals(1, headIndexId);
        assertEquals(383, headOffset);
        assertEquals(1, tailGenId);
        assertEquals(1, tailIndexId);
        assertEquals(222, tailOffset);

        log.info("append event to stretch beyond limit but less than capacity");
        generator = new DbusEventGenerator(100);
        events = new Vector<DbusEvent>();
        generator.generateEvents(1, 1, 400, 150, events); // will add two event 61 + 150

        // Add events. this will cause limit increased
        appender = new DbusEventAppender(events, dbusBuf, null);
        appender.run();
        log.info("Head:" + parser.toString(dbusBuf.getHead()) + ",Tail:" + parser.toString(dbusBuf.getTail()));
        log.info("Num buffers :" + dbusBuf.getBuffer().length);
        log.info("Buffer :" + Arrays.toString(dbusBuf.getBuffer()));

        headPos = dbusBuf.getHead();
        tailPos = dbusBuf.getTail();
        headGenId = parser.bufferGenId(headPos);
        headIndexId = parser.bufferIndex(headPos);
        headOffset = parser.bufferOffset(headPos);
        tailGenId = parser.bufferGenId(tailPos);
        tailIndexId = parser.bufferIndex(tailPos);
        tailOffset = parser.bufferOffset(tailPos);

        assertEquals(1, headGenId);
        assertEquals(0, headIndexId);
        assertEquals(61, headOffset);
        assertEquals(2, tailIndexId);
        assertEquals(61, tailOffset);
        assertEquals(494, dbusBuf.getBuffer()[1].limit());

        log.info("finished");
    }

    @Test
    /**
     * verify that changes to the buffer (appendEvent, endEvent, clear) after the buffer is closed
     * are ignored (and rolled back)
     * we do this by creating buffer (or loading from mmap files from the previous run), adding one window,
     * then doing append, close , append/endEvents (which should throw an exception)
     * then loading again and verifying that it has our events
     */
    public void testAppendEventsWithCloseInMiddle() throws Exception {
        final Logger log = Logger.getLogger("TestDbusEventBuffer.testAppendEventsWithCloseInMiddle");
        log.setLevel(Level.DEBUG);
        log.info("starting");

        // mmap dir
        File mmapDir = initMmapDir("/tmp/tmp_mmapDir");

        DbusEventBuffer.StaticConfig config = getConfig(1200, 500, 100, 500, AllocationPolicy.MMAPPED_MEMORY,
                mmapDir.getAbsolutePath(), true);
        DbusEventBuffer dbusBuf = new DbusEventBuffer(config);

        DbusEventBufferReflector bufferReflector = new DbusEventBufferReflector(dbusBuf);
        // BufferPositionParser parser = dbusBuf.getBufferPositionParser();
        log.info("append initial events");
        DbusEventGenerator generator = new DbusEventGenerator();
        Vector<DbusEvent> events = new Vector<DbusEvent>();
        generator.generateEvents(12, 2, 120, 39, events);

        // add first window with 2 events
        dbusBuf.start(-1);
        int i = 0;

        addOneEvent(events.get(i++), dbusBuf, EventType.START);
        addOneEvent(events.get(i++), dbusBuf, EventType.END);
        checkEventsInBuffer(bufferReflector, 3); // 2 + 1(EOW)

        // add first event of the second window
        addOneEvent(events.get(i++), dbusBuf, EventType.START);
        checkEventsInBuffer(bufferReflector, 3); // 2 + 1(EOW)

        // now close the buffer
        dbusBuf.closeBuffer(true);
        checkEventsInBuffer(bufferReflector, 3); // 2 + 1(EOW)

        // now add the end
        try {
            addOneEvent(events.get(i), dbusBuf, EventType.END);
        } catch (Throwable ex) {
            log.info("Got e: ", ex);
        }
        checkEventsInBuffer(bufferReflector, 3); // 2 + 1(EOW)

        // create new buffer
        dbusBuf = new DbusEventBuffer(config); // should load from mmap
        bufferReflector = new DbusEventBufferReflector(dbusBuf);
        checkEventsInBuffer(bufferReflector, 3); // 2 + 1(EOW)

        addOneEvent(events.get(i++), dbusBuf, EventType.START);
        addOneEvent(events.get(i++), dbusBuf, EventType.END);
        checkEventsInBuffer(bufferReflector, 6); // 4 + 2(EOW)

        // add two more events but don't do endEvents
        addOneEvent(events.get(i++), dbusBuf, EventType.START);
        addOneEvent(events.get(i++), dbusBuf, EventType.REG); // no endEvents()
        // now close the buffer
        dbusBuf.closeBuffer(true);
        dbusBuf.closeBuffer(true); // should be ok (WARN in the logs)
        checkEventsInBuffer(bufferReflector, 6); // 4 + 2(EOW)

        // call endEvents(on a closed buffer);
        try {
            dbusBuf.endEvents(events.get(i - 1).sequence());
        } catch (Throwable ex) {
            log.info("Got e2: ", ex);
        }
        checkEventsInBuffer(bufferReflector, 6); // 4 + 2(EOW)

        // create new buffer
        dbusBuf = new DbusEventBuffer(config); // should load from mmap
        bufferReflector = new DbusEventBufferReflector(dbusBuf);
        checkEventsInBuffer(bufferReflector, 6); // 4 + 2(EOW)

        addOneEvent(events.get(i++), dbusBuf, EventType.START);
        addOneEvent(events.get(i++), dbusBuf, EventType.END);
        checkEventsInBuffer(bufferReflector, 9); // 6 + 3(EOW)

        // add two more events but don't do endEvents
        addOneEvent(events.get(i++), dbusBuf, EventType.START);
        addOneEvent(events.get(i++), dbusBuf, EventType.REG); // no endEvents()
        // now close the buffer
        dbusBuf.closeBuffer(true);
        checkEventsInBuffer(bufferReflector, 9); // 6 + 3(EOW)

        // call endEvents(on a closed buffer);
        try {
            dbusBuf.clear(); //should fail
        } catch (Throwable ex) {
            log.info("Got e3: ", ex);
        }
        checkEventsInBuffer(bufferReflector, 9); // 6 + 3(EOW)

        // make sure it is still valid
        dbusBuf = new DbusEventBuffer(config); // should load from mmap
        bufferReflector = new DbusEventBufferReflector(dbusBuf);
        checkEventsInBuffer(bufferReflector, 9); // 6 + 3(EOW)

    }

    DbusEventBuffer.StaticConfig getConfig(long maxEventBufferSize, int maxIndividualBufferSize, int maxIndexSize,
            int maxReadBufferSize, AllocationPolicy allocationPolicy, String mmapDirectory,
            boolean restoreMMappedBuffers) throws InvalidConfigException {
        DbusEventBuffer.Config config = new DbusEventBuffer.Config();
        config.setMaxSize(maxEventBufferSize);
        config.setMaxIndividualBufferSize(maxIndividualBufferSize);
        config.setScnIndexSize(maxIndexSize);
        config.setAverageEventSize(maxReadBufferSize);
        config.setAllocationPolicy(allocationPolicy.name());
        config.setRestoreMMappedBuffers(restoreMMappedBuffers);
        config.setMmapDirectory(mmapDirectory);
        //config.setQueuePolicy(policy.toString());
        //config.setAssertLevel(null != assertLevel ? assertLevel.toString(): AssertLevel.NONE.toString());
        config.setAssertLevel(AssertLevel.NONE.toString());
        return config.build();
    }

    enum EventType {
        START, END, REG
    };

    private void checkEventsInBuffer(DbusEventBufferReflector bufferReflector, int expCount) {

        Assert.assertTrue(bufferReflector.validateBuffer());
        DbusEventBuffer buf = bufferReflector.getDbusEventBuffer();

        DbusEventBuffer.DbusEventIterator iter = buf.acquireIterator("myIter1");
        Assert.assertNotNull(iter);
        int count = 0;
        while (iter.hasNext()) {
            DbusEvent e = iter.next();
            Assert.assertNotNull(e);
            System.out.println("seq=" + e.sequence() + "sys:" + e.isEndOfPeriodMarker());
            count++;
        }
        iter.close();
        Assert.assertEquals("doesn't match expected number of events in the buffer", expCount, count);
    }

    private void addOneEvent(DbusEvent ev, DbusEventBuffer buf, EventType eventType) {
        if (eventType.equals(EventType.START))
            buf.startEvents();

        byte[] payload = new byte[((DbusEventInternalReadable) ev).payloadLength()];
        ev.value().get(payload);
        buf.appendEvent(new DbusEventKey(ev.key()), ev.physicalPartitionId(), ev.logicalPartitionId(),
                ev.timestampInNanos(), ev.srcId(), ev.schemaId(), payload, false, null);

        if (eventType.equals(EventType.END))
            buf.endEvents(ev.sequence());
    }

    private File initMmapDir(String path) throws Exception {
        File d = new File(path);
        if (d.exists()) {
            FileUtils.cleanDirectory(d);
        } else {
            d.mkdir();
        }
        d.deleteOnExit();
        return d;
    }
}