org.lmdbjava.ByteBufProxy.java Source code

Java tutorial

Introduction

Here is the source code for org.lmdbjava.ByteBufProxy.java

Source

/*-
 * #%L
 * LmdbJava
 * %%
 * Copyright (C) 2016 - 2017 The LmdbJava Open Source Project
 * %%
 * 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.
 * #L%
 */

package org.lmdbjava;

import io.netty.buffer.ByteBuf;
import static io.netty.buffer.PooledByteBufAllocator.DEFAULT;
import static java.lang.Class.forName;
import static java.lang.ThreadLocal.withInitial;
import java.lang.reflect.Field;
import java.util.ArrayDeque;
import jnr.ffi.Pointer;
import static org.lmdbjava.UnsafeAccess.UNSAFE;

/**
 * A buffer proxy backed by Netty's {@link ByteBuf}.
 *
 * <p>
 * This class requires {@link UnsafeAccess} and netty-buffer must be in the
 * classpath.
 */
public final class ByteBufProxy extends BufferProxy<ByteBuf> {

    private static final long ADDRESS_OFFSET;

    /**
     * A thread-safe pool for a given length. If the buffer found is bigger then
     * the buffer in the pool creates a new buffer. If no buffer is found creates
     * a new buffer.
     */
    private static final ThreadLocal<ArrayDeque<ByteBuf>> BUFFERS = withInitial(() -> new ArrayDeque<>(16));

    private static final String FIELD_NAME_ADDRESS = "memoryAddress";
    private static final String FIELD_NAME_LENGTH = "length";
    private static final long LENGTH_OFFSET;
    private static final String NAME = "io.netty.buffer.PooledUnsafeDirectByteBuf";

    static {
        try {
            // create buffer (first is SimpleLeakAwareByteBuff but we need PooledUDBB)
            DEFAULT.directBuffer(0);
            final Field address = findField(NAME, FIELD_NAME_ADDRESS);
            final Field length = findField(NAME, FIELD_NAME_LENGTH);
            ADDRESS_OFFSET = UNSAFE.objectFieldOffset(address);
            LENGTH_OFFSET = UNSAFE.objectFieldOffset(length);
        } catch (final SecurityException e) {
            throw new LmdbException("Field access error", e);
        }
    }

    static Field findField(final String c, final String name) {
        Class<?> clazz;
        try {
            clazz = forName(c);
        } catch (final ClassNotFoundException e) {
            throw new LmdbException(c + " class unavailable", e);
        }
        do {
            try {
                final Field field = clazz.getDeclaredField(name);
                field.setAccessible(true);
                return field;
            } catch (final NoSuchFieldException e) {
                clazz = clazz.getSuperclass();
            }
        } while (clazz != null);
        throw new LmdbException(name + " not found");
    }

    @Override
    protected ByteBuf allocate() {
        final ArrayDeque<ByteBuf> queue = BUFFERS.get();
        final ByteBuf buffer = queue.poll();

        if (buffer != null && buffer.capacity() >= 0) {
            return buffer;
        } else {
            return DEFAULT.directBuffer(0);
        }
    }

    @Override
    protected void deallocate(final ByteBuf buff) {
        final ArrayDeque<ByteBuf> queue = BUFFERS.get();
        if (!queue.offer(buff)) {
            buff.release();
        }
    }

    @Override
    protected byte[] getBytes(final ByteBuf buffer) {
        final byte[] dest = new byte[buffer.capacity()];
        buffer.getBytes(0, dest);
        return dest;
    }

    @Override
    protected void in(final ByteBuf buffer, final Pointer ptr, final long ptrAddr) {
        UNSAFE.putLong(ptrAddr + STRUCT_FIELD_OFFSET_SIZE, buffer.writerIndex() - buffer.readerIndex());
        UNSAFE.putLong(ptrAddr + STRUCT_FIELD_OFFSET_DATA, buffer.memoryAddress() + buffer.readerIndex());
    }

    @Override
    protected void in(final ByteBuf buffer, final int size, final Pointer ptr, final long ptrAddr) {
        UNSAFE.putLong(ptrAddr + STRUCT_FIELD_OFFSET_SIZE, size);
        UNSAFE.putLong(ptrAddr + STRUCT_FIELD_OFFSET_DATA, buffer.memoryAddress() + buffer.readerIndex());
    }

    @Override
    protected ByteBuf out(final ByteBuf buffer, final Pointer ptr, final long ptrAddr) {
        final long addr = UNSAFE.getLong(ptrAddr + STRUCT_FIELD_OFFSET_DATA);
        final long size = UNSAFE.getLong(ptrAddr + STRUCT_FIELD_OFFSET_SIZE);
        UNSAFE.putLong(buffer, ADDRESS_OFFSET, addr);
        UNSAFE.putLong(buffer, LENGTH_OFFSET, (int) size);
        buffer.readerIndex(0).writerIndex((int) size);
        return buffer;
    }
}