All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.persistit.JournalManagerBench Maven / Gradle / Ivy

There is a newer version: 3.3.0
Show newest version
/**
 * Copyright © 2012 Akiban Technologies, Inc.  All rights reserved.
 * 
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which
 * accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * This program may also be available under different license terms.
 * For more information, see www.akiban.com or contact [email protected].
 * 
 * Contributors:
 * Akiban Technologies, Inc.
 */

package com.persistit;

import static com.persistit.util.Util.NS_PER_S;

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import com.persistit.util.ArgParser;

/**
 * Benchmark for primitive I/O simulating HARD (durable) commit. This code is
 * intended to explore two elements:
 * 
 * (1) Pre-extending the journal file (so that FileChannel.force(false) usually
 * does not need to write any metadata.
 * 
 * (2) Performing I/O in fixed-length blocks so that to write a some bytes the
 * file system does not first need to read existing data from disk.
 * 
 * Parameters
 * 
 * align - smallest unit of I/O (default = 1) datapath - directory in which fake
 * journal file will be written (default = /tmp/persistit_test_data) buffersize
 * - emulated journal buffer size (default = 64M)
 * 
 * 
 * @author peter
 * 
 */
public class JournalManagerBench {

    private final byte[] NULLS = new byte[65536];

    private final String[] ARG_TEMPLATE = new String[] { "duration|int:10:10:86400|Duration of test in seconds",
            "policy|String:HARD|Commit policy: SOFT, HARD or GROUP",
            "datapath|String:/tmp/persistit_test_data|Datapath property",
            "buffersize|int:64:1:1024|Emulated journal buffer size in MBytes",
            "extension|int:0:0:1024|MBytes by which to extend file when full",
            "prealloc|int:0:0:1024|Preallocated file size in MBytes",
            "align|int:1:1:65536|Blocking factor for I/O size",
            "recsize|int:123:64:65536|Emulated transaction record size" };

    final ByteBuffer buffer;
    final ArgParser ap;

    private File file;
    private FileChannel fc;

    private long writeAddress = 0;
    private long currentAddress = 0;

    long count = 0;
    long minTime = Long.MAX_VALUE;
    long maxTime = Long.MIN_VALUE;

    final byte[] bytes = new byte[65536];

    public static void main(final String[] args) throws Exception {
        final JournalManagerBench jmb = new JournalManagerBench(args);
        jmb.runTest();
    }

    private JournalManagerBench(final String[] args) throws Exception {
        ap = new ArgParser("JournalManagerBench", args, ARG_TEMPLATE).strict();
        buffer = ByteBuffer.allocate(ap.getIntValue("buffersize") * 1024 * 1024);
    }

    @SuppressWarnings("resource")
    private void runTest() throws Exception {
        file = new File(ap.getStringValue("datapath"), "JManBench_TestFile");
        fc = new RandomAccessFile(file, "rw").getChannel();
        preallocateFile(ap.getIntValue("prealloc") * 1024 * 1024);
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) ('-');
        }
        final int align = ap.getIntValue("align");
        final long extension = ap.getIntValue("extension") * 1024 * 1024;

        final long start = System.nanoTime();
        final long expires = start + ap.getIntValue("duration") * NS_PER_S;
        long now = System.nanoTime();

        while (now < expires) {
            doOneCycle(now - start, align, extension, 100);
            final long then = System.nanoTime();
            count++;
            minTime = Math.min(minTime, then - now);
            maxTime = Math.max(maxTime, then - now);
            now = then;
        }
        final long elapsed = now - start;
        System.out.printf("%,d commits took %,dms at a rate of %,d/second minimum time=%,dns maximumTime=%,dns\n",
                count, elapsed, (count * NS_PER_S) / elapsed, minTime, maxTime);

    }

    private void preallocateFile(final long size) throws Exception {
        if (size > 0 && fc.size() > size) {
            System.out.printf("Truncating file %s from %,d to %,d\n", file, fc.size(), size);
            fc.truncate(size);
        } else if (fc.size() < size) {
            System.out.printf("Preallocating file %s to size %,d ", file, size);
            while (true) {
                long remaining = size - fc.size();
                if (remaining <= 0) {
                    break;
                }
                if (remaining > buffer.capacity()) {
                    remaining = buffer.capacity();
                    final long unaligned = fc.size() % 16384;
                    if (unaligned > 0) {
                        remaining = remaining - (16384 - unaligned);
                    }
                }
                buffer.position(0).limit((int) remaining);
                fc.write(buffer, fc.size());
                System.out.print(".");
            }
            fc.force(true);
            System.out.println("done");
        }
    }

    private void doOneCycle(final long time, final int align, final long extension, final int size) throws Exception {
        // Make a fake transaction record
        final String header = String.format("\nsize=%06d count=%06d time=%012d\n", size, count, time);
        final byte[] b = header.getBytes();
        System.arraycopy(b, 0, bytes, 0, b.length);

        // Add the record, possibly offset to maintaining alignment
        final int toRewrite = (int) (currentAddress - writeAddress);
        buffer.position(toRewrite);
        buffer.put(bytes, 0, size);
        boolean extended = false;

        int position = buffer.position();

        // If extension is needed, add those bytes
        long currentSize;
        if (extension > 0 && writeAddress + buffer.position() > (currentSize = fc.size())) {
            long newSize = currentSize + extension;
            if (newSize - writeAddress > buffer.capacity()) {
                newSize = writeAddress + buffer.capacity();
                assert newSize > currentSize;
            }
            int add = (int) (newSize - writeAddress - buffer.position());
            while (add > 0) {
                buffer.put(NULLS, 0, Math.min(NULLS.length, add));
                add -= NULLS.length;
            }
            extended = true;
        }

        // Write and force the buffer

        buffer.flip();
        fc.write(buffer, writeAddress);
        fc.force(extended);

        // Align the bytes to the beginning of the buffer as needed

        currentAddress = writeAddress + position;
        buffer.limit(position);
        position = (position / align) * align;
        buffer.position(position);
        buffer.compact();
        writeAddress += position;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy