Package org.apache.directmemory.memory.allocator

Source Code of org.apache.directmemory.memory.allocator.SlabByteBufferAllocatorImpl

package org.apache.directmemory.memory.allocator;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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 java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Map;
import java.util.NavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;


/**
* {@link ByteBufferAllocator} implementation that uses {@link FixedSizeByteBufferAllocatorImpl}
* of different size to allocate best matching's size {@link ByteBuffer}
*
* @since 0.6
*/
public class SlabByteBufferAllocatorImpl
    extends AbstractByteBufferAllocator
{

    // Tells if it returns null when no buffers are available
    private boolean returnNullWhenNoBufferAvailable = true;

    // Internal slabs sorted by sliceSize
    private final NavigableMap<Integer, FixedSizeByteBufferAllocatorImpl> slabs =
        new ConcurrentSkipListMap<Integer, FixedSizeByteBufferAllocatorImpl>();

    // Tells if it is allowed to look in a bigger slab to perform the request.
    private final boolean allowAllocationToBiggerSlab;

    /**
     * Constructor.
     *
     * @param number                      : internal allocator identifier
     * @param slabs                       : {@link FixedSizeByteBufferAllocatorImpl} to use for allocation
     * @param allowAllocationToBiggerSlab : tells if it is allowed to look in a bigger slab to perform the request.
     */
    public SlabByteBufferAllocatorImpl( final int number, final Collection<FixedSizeByteBufferAllocatorImpl> slabs,
                                        final boolean allowAllocationToBiggerSlab )
    {
        super( number );

        this.allowAllocationToBiggerSlab = allowAllocationToBiggerSlab;

        for ( FixedSizeByteBufferAllocatorImpl slab : slabs )
        {
            this.slabs.put( slab.getSliceSize(), slab );
        }

    }


    /**
     * @param size
     * @return the slab that best match the given size
     */
    private FixedSizeByteBufferAllocatorImpl getSlabThatMatchTheSize( final int size )
    {
        // Find the slab that can carry the wanted size. -1 is used because higherEntry returns a strictly higher entry.
        final Map.Entry<Integer, FixedSizeByteBufferAllocatorImpl> entry = slabs.higherEntry( size - 1 );

        if ( entry != null )
        {
            return entry.getValue();
        }

        // If an entry has not been found, this means that no slabs has bigger enough slices to allocate the given size
        return null;
    }

    @Override
    public void free( final ByteBuffer byteBuffer )
    {

        final FixedSizeByteBufferAllocatorImpl slab = getSlabThatMatchTheSize( byteBuffer.capacity() );

        if ( slab == null )
        {
            // Hu ? where this bytebuffer come from ??
            return;
        }

        slab.free( byteBuffer );

    }

    @Override
    public ByteBuffer allocate( final int size )
    {

        final FixedSizeByteBufferAllocatorImpl slab = getSlabThatMatchTheSize( size );

        if ( slab == null )
        {
            // unable to store such big objects
            if ( returnNullWhenNoBufferAvailable )
            {
                return null;
            }
            else
            {
                throw new BufferOverflowException();
            }
        }

        // Try to allocate the given size
        final ByteBuffer byteBuffer = slab.allocate( size );

        // If allocation succeed, return the buffer
        if ( byteBuffer != null )
        {
            return byteBuffer;
        }

        // Otherwise we have the option to allow in a bigger slab.
        if ( !allowAllocationToBiggerSlab )
        {
            if ( returnNullWhenNoBufferAvailable )
            {
                return null;
            }
            else
            {
                throw new BufferOverflowException();
            }
        }
        else
        {
            // We can try to allocate to a bigger slab.
            // size + 1 here because getSlabThatMatchTheSize do a size -1 and thus will return the same slab
            final int biggerSize = slab.getSliceSize() + 1;
            final FixedSizeByteBufferAllocatorImpl biggerSlab = getSlabThatMatchTheSize( biggerSize );
            if ( biggerSlab == null )
            {
                // We were already trying to allocate in the biggest slab
                if ( returnNullWhenNoBufferAvailable )
                {
                    return null;
                }
                else
                {
                    throw new BufferOverflowException();
                }
            }

            final ByteBuffer secondByteBuffer = biggerSlab.allocate( size );

            if ( secondByteBuffer == null )
            {
                if ( returnNullWhenNoBufferAvailable )
                {
                    return null;
                }
                else
                {
                    throw new BufferOverflowException();
                }
            }
            else
            {
                return secondByteBuffer;
            }
        }
    }

    @Override
    public void clear()
    {
        for ( final Map.Entry<Integer, FixedSizeByteBufferAllocatorImpl> entry : slabs.entrySet() )
        {
            entry.getValue().clear();
        }
    }

    @Override
    public int getCapacity()
    {
        int totalSize = 0;
        for ( final Map.Entry<Integer, FixedSizeByteBufferAllocatorImpl> entry : slabs.entrySet() )
        {
            totalSize += entry.getValue().getCapacity();
        }
        return totalSize;
    }

    @Override
    public void close()
        throws IOException
    {
        for ( final Map.Entry<Integer, FixedSizeByteBufferAllocatorImpl> entry : slabs.entrySet() )
        {
            entry.getValue().close();
        }
    }
}
TOP

Related Classes of org.apache.directmemory.memory.allocator.SlabByteBufferAllocatorImpl

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.