com.jivesoftware.os.amza.service.storage.binary.BinaryRowReaderWriterTest.java Source code

Java tutorial

Introduction

Here is the source code for com.jivesoftware.os.amza.service.storage.binary.BinaryRowReaderWriterTest.java

Source

/*
 * Copyright 2013 Jive Software, Inc
 *
 * 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.
 */
package com.jivesoftware.os.amza.service.storage.binary;

import com.google.common.collect.Lists;
import com.google.common.io.Files;
import com.jivesoftware.os.amza.api.filer.UIO;
import com.jivesoftware.os.amza.api.scan.RowStream;
import com.jivesoftware.os.amza.api.stream.RowType;
import com.jivesoftware.os.amza.api.wal.WALWriter;
import com.jivesoftware.os.amza.service.filer.HeapByteBufferFactory;
import com.jivesoftware.os.amza.service.filer.MultiAutoGrowingByteBufferBackedFiler;
import com.jivesoftware.os.amza.api.IoStats;
import com.jivesoftware.os.amza.service.storage.filer.DiskBackedWALFiler;
import com.jivesoftware.os.amza.service.storage.filer.MemoryBackedWALFiler;
import com.jivesoftware.os.amza.service.storage.filer.WALFiler;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.lang.mutable.MutableInt;
import org.testng.Assert;
import org.testng.annotations.Test;

/**
 * @author jonathan
 */
public class BinaryRowReaderWriterTest {

    private final WALWriter.IndexableKeys indexableKeys = stream -> true;
    private final WALWriter.TxKeyPointerFpStream txKeyPointerFpStream = (txId, prefix, key, value, valueTimestamp,
            valueTombstoned, valueVersion, fp) -> true;

    @Test
    public void testValidateDiskBacked() throws Exception {

        File dir = Files.createTempDir();
        IoStats ioStats = new IoStats();
        DiskBackedWALFiler filer = new DiskBackedWALFiler(new File(dir, "booya").getAbsolutePath(), "rw", false, 0);
        validate(filer, ioStats);

    }

    @Test
    public void testValidateHeapBacked() throws Exception {

        IoStats ioStats = new IoStats();
        WALFiler filer = new MemoryBackedWALFiler(
                new MultiAutoGrowingByteBufferBackedFiler(1_024, 1_024 * 1_024, new HeapByteBufferFactory()));
        validate(filer, ioStats);

    }

    private void validate(WALFiler filer, IoStats ioStats) throws Exception {
        BinaryRowReader binaryRowReader = new BinaryRowReader(filer);
        BinaryRowWriter binaryRowWriter = new BinaryRowWriter(filer);

        binaryRowWriter.write(ioStats, 0L, RowType.primary, 1, 4,
                stream -> stream.stream(new byte[] { 1, 2, 3, 4 }), indexableKeys, txKeyPointerFpStream, true,
                false);
        binaryRowWriter.write(ioStats, 1L, RowType.primary, 1, 4,
                stream -> stream.stream(new byte[] { 1, 2, 3, 5 }), indexableKeys, txKeyPointerFpStream, true,
                false);
        binaryRowWriter.write(ioStats, 2L, RowType.primary, 1, 4,
                stream -> stream.stream(new byte[] { 1, 2, 3, 6 }), indexableKeys, txKeyPointerFpStream, true,
                false);
        binaryRowWriter.write(ioStats, -1L, RowType.end_of_merge, 1, 4,
                stream -> stream.stream(new byte[] { 1, 2, 3, 7 }), indexableKeys, txKeyPointerFpStream, true,
                false);

        MutableInt truncations = new MutableInt();
        binaryRowReader.validate(ioStats, true, true,
                (long rowFP, long rowTxId, RowType rowType, byte[] row) -> rowType == RowType.end_of_merge ? rowFP
                        : -1,
                (long rowFP, long rowTxId, RowType rowType,
                        byte[] row) -> rowType == RowType.end_of_merge ? -(rowFP + 1) : -1,
                (truncatedAtFP) -> truncations.increment());
        binaryRowReader.validate(ioStats, false, false,
                (long rowFP, long rowTxId, RowType rowType, byte[] row) -> rowType == RowType.end_of_merge ? rowFP
                        : -1,
                (long rowFP, long rowTxId, RowType rowType,
                        byte[] row) -> rowType == RowType.end_of_merge ? -(rowFP + 1) : -1,
                (truncatedAtFP) -> truncations.increment());
        Assert.assertEquals(truncations.intValue(), 0);

        //filer.seek(filer.length());
        long corruptionOffset = filer.length();
        UIO.writeByte(filer.appender(), (byte) 56, "corrupt");

        binaryRowReader.validate(ioStats, true, true,
                (long rowFP, long rowTxId, RowType rowType, byte[] row) -> rowType == RowType.end_of_merge ? rowFP
                        : -1,
                (long rowFP, long rowTxId, RowType rowType,
                        byte[] row) -> rowType == RowType.end_of_merge ? -(rowFP + 1) : -1,
                (truncatedAtFP) -> {
                    Assert.assertEquals(truncatedAtFP, corruptionOffset);
                    truncations.increment();
                });
        Assert.assertEquals(truncations.intValue(), 1);

        UIO.writeByte(filer.appender(), (byte) 56, "corrupt");

        binaryRowReader.validate(ioStats, false, false,
                (long rowFP, long rowTxId, RowType rowType, byte[] row) -> rowType == RowType.end_of_merge ? rowFP
                        : -1,
                (long rowFP, long rowTxId, RowType rowType,
                        byte[] row) -> rowType == RowType.end_of_merge ? -(rowFP + 1) : -1,
                (truncatedAtFP) -> {
                    Assert.assertEquals(truncatedAtFP, corruptionOffset);
                    truncations.increment();
                });
        Assert.assertEquals(truncations.intValue(), 2);
    }

    @Test
    public void testDiskBackedRead() throws Exception {
        File dir = Files.createTempDir();
        IoStats ioStats = new IoStats();
        DiskBackedWALFiler filer = new DiskBackedWALFiler(new File(dir, "booya").getAbsolutePath(), "rw", false, 0);
        read(filer, ioStats);

    }

    @Test
    public void testMemoryBackedRead() throws Exception {
        IoStats ioStats = new IoStats();
        WALFiler filer = new MemoryBackedWALFiler(
                new MultiAutoGrowingByteBufferBackedFiler(1_024, 1_024 * 1_024, new HeapByteBufferFactory()));
        read(filer, ioStats);

    }

    private void read(WALFiler filer, IoStats ioStats) throws Exception {
        BinaryRowReader binaryRowReader = new BinaryRowReader(filer);
        BinaryRowWriter binaryRowWriter = new BinaryRowWriter(filer);

        ReadStream readStream = new ReadStream();
        binaryRowReader.reverseScan(ioStats, readStream);
        Assert.assertTrue(readStream.rows.isEmpty());
        readStream.clear();

        binaryRowReader.scan(ioStats, 0, false, readStream);
        Assert.assertTrue(readStream.rows.isEmpty());
        readStream.clear();

        binaryRowWriter.write(ioStats, 0L, RowType.primary, 1, 4,
                stream -> stream.stream(new byte[] { 1, 2, 3, 4 }), indexableKeys, txKeyPointerFpStream, true,
                false);
        binaryRowReader.scan(ioStats, 0, false, readStream);
        Assert.assertEquals(readStream.rows.size(), 1);
        readStream.clear();

        binaryRowReader.reverseScan(ioStats, readStream);
        Assert.assertEquals(readStream.rows.size(), 1);
        readStream.clear();

        binaryRowWriter.write(ioStats, 2L, RowType.primary, 1, 4,
                stream -> stream.stream(new byte[] { 2, 3, 4, 5 }), indexableKeys, txKeyPointerFpStream, true,
                false);
        binaryRowReader.scan(ioStats, 0, false, readStream);
        Assert.assertEquals(readStream.rows.size(), 2);
        readStream.clear();

        binaryRowReader.reverseScan(ioStats, readStream);
        Assert.assertEquals(readStream.rows.size(), 2);
        Assert.assertTrue(Arrays.equals(readStream.rows.get(0), new byte[] { 2, 3, 4, 5 }));
        Assert.assertTrue(Arrays.equals(readStream.rows.get(1), new byte[] { 1, 2, 3, 4 }));
        readStream.clear();
    }

    @Test(enabled = false)
    public void testReverseReadPerformance() throws Exception {
        File dir = Files.createTempDir();
        IoStats ioStats = new IoStats();
        DiskBackedWALFiler filer = new DiskBackedWALFiler(new File(dir, "booya").getAbsolutePath(), "rw", false, 0);
        BinaryRowReader binaryRowReader = new BinaryRowReader(filer);
        BinaryRowWriter binaryRowWriter = new BinaryRowWriter(filer);

        ReadStream readStream = new ReadStream();
        binaryRowReader.reverseScan(ioStats, readStream);
        Assert.assertTrue(readStream.rows.isEmpty());
        readStream.clear();

        int numEntries = 1_000_000;
        for (long i = 0; i < numEntries; i++) {
            byte[] row = (String.valueOf(i) + "k" + (i % 1000)).getBytes();
            binaryRowWriter.write(ioStats, i, RowType.primary, 1, row.length, stream -> stream.stream(row),
                    indexableKeys, txKeyPointerFpStream, true, false);
        }

        for (int i = 0; i < 10; i++) {
            long start = System.currentTimeMillis();
            binaryRowReader.scan(ioStats, 0, false, readStream);
            System.out.println("Forward scan in " + (System.currentTimeMillis() - start) + " ms");
            Assert.assertEquals(readStream.rows.size(), numEntries);
            readStream.clear();

            start = System.currentTimeMillis();
            binaryRowReader.reverseScan(ioStats, readStream);
            System.out.println("Reverse scan in " + (System.currentTimeMillis() - start) + " ms");
            Assert.assertEquals(readStream.rows.size(), numEntries);
            readStream.clear();
        }
    }

    @Test
    public void testOpenCloseAppend() throws Exception {
        File dir = Files.createTempDir();

        IoStats ioStats = new IoStats();
        Random rand = new Random();
        for (long i = 0; i < 1000; i++) {
            DiskBackedWALFiler filer = new DiskBackedWALFiler(new File(dir, "foo").getAbsolutePath(), "rw", false,
                    0);
            BinaryRowReader binaryRowReader = new BinaryRowReader(filer);
            BinaryRowWriter binaryRowWriter = new BinaryRowWriter(filer);

            ReadStream readStream = new ReadStream();

            if (i > 0) {
                binaryRowReader.reverseScan(ioStats, readStream);
                Assert.assertEquals(readStream.rows.size(), i);
            }
            readStream.clear();

            byte[] row = new byte[4];
            rand.nextBytes(row);
            binaryRowWriter.write(ioStats, i, RowType.primary, 1, row.length, stream -> stream.stream(row),
                    indexableKeys, txKeyPointerFpStream, true, false);
            filer.close();
        }

    }

    @Test(enabled = false)
    public void testConcurrency() throws Exception {
        MemoryBackedWALFiler walFiler = new MemoryBackedWALFiler(
                new MultiAutoGrowingByteBufferBackedFiler(32, 1_024 * 1_024, new HeapByteBufferFactory()));
        IoStats ioStats = new IoStats();
        BinaryRowReader binaryRowReader = new BinaryRowReader(walFiler);
        BinaryRowWriter binaryRowWriter = new BinaryRowWriter(walFiler);

        ExecutorService executors = Executors.newFixedThreadPool(9);
        AtomicBoolean running = new AtomicBoolean(true);
        AtomicLong scanned = new AtomicLong();
        List<Future<?>> futures = Lists.newArrayList();
        for (int i = 0; i < 8; i++) {
            futures.add(executors.submit(() -> {
                try {
                    while (running.get()) {
                        binaryRowReader.scan(ioStats, 0, false, (rowFP, rowTxId, rowType, row) -> {
                            scanned.incrementAndGet();
                            return true;
                        });
                    }
                    return true;
                } catch (Throwable t) {
                    t.printStackTrace();
                    throw t;
                }
            }));
        }
        futures.add(executors.submit(() -> {
            try {
                for (int i = 0; i < 1_000_000; i++) {
                    byte[] row = UIO.intBytes(i);
                    binaryRowWriter.write(ioStats, i, RowType.primary, 1, 16, stream -> stream.stream(row),
                            stream -> true,
                            (txId, prefix, key, value, valueTimestamp, valueTombstoned, valueVersion, fp) -> true,
                            false, false);
                    if (i % 10_000 == 0) {
                        System.out.println("Finished i:" + i + " scanned:" + scanned.get());
                    }
                }
            } finally {
                running.set(false);
            }
            return null;
        }));

        for (Future<?> future : futures) {
            future.get();
        }
    }

    static class ReadStream implements RowStream {

        int clears = 0;
        final ArrayList<byte[]> rows = new ArrayList<>();

        @Override
        public boolean row(long rowFp, long rwoTxId, RowType rowType, byte[] row) throws Exception {
            rows.add(row);
            return true;
        }

        void clear() {
            clears++;
            rows.clear();
        }
    }

}