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

org.voovan.tools.buffer.ByteBufferChannel Maven / Gradle / Ivy

There is a newer version: 4.3.8
Show newest version
package org.voovan.tools.buffer;

import org.voovan.Global;
import org.voovan.tools.TEnv;
import org.voovan.tools.TFile;
import org.voovan.tools.TProperties;
import org.voovan.tools.TUnsafe;
import org.voovan.tools.exception.LargerThanMaxSizeException;
import org.voovan.tools.exception.MemoryReleasedException;
import org.voovan.tools.log.Logger;
import sun.misc.Unsafe;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

/**
 * ByteBuffer双向通道
 *
 * @author helyho
 *
 * Voovan Framework.
 * WebSite: https://github.com/helyho/Voovan
 * Licence: Apache v2 License
 */
public class ByteBufferChannel {
    private static int BYTEBUFFERCHANNEL_MAX_SIZE = TProperties.getInt("framework", "ByteBufferChannelMaxSize", 1024*1024*2);
    private volatile AtomicLong address = new AtomicLong(0);
    private Unsafe unsafe = TUnsafe.getUnsafe();
    private ByteBuffer byteBuffer;
    private volatile int size;
    private AtomicBoolean borrowed = new AtomicBoolean(false);

    private int maxSize = BYTEBUFFERCHANNEL_MAX_SIZE;

    /**
     * 构造函数
     * @param capacity 分配的容量
     */
    public ByteBufferChannel(int capacity) {
        init(capacity);
    }

    /**
     * 构造函数
     * @param capacity 分配的容量
     * @param maxSize 通道地最大容量
     */
    public ByteBufferChannel(int capacity, Integer maxSize) {
        init(capacity);
        this.maxSize = maxSize;
    }

    /**
     * 构造函数
     * @param byteBuffer 分配的容量
     */
    public ByteBufferChannel(ByteBuffer byteBuffer) {
        init(byteBuffer);
    }


    /**
     * 构造函数
     */
    public ByteBufferChannel() {
        init(1024 * 16);
    }

    /**
     * 初始化函数
     * @param capacity 分配的容量
     */
    private void init(int capacity){
        this.byteBuffer = newByteBuffer(capacity);
        byteBuffer.limit(0);
        resetAddress();
        this.size = 0;
        this.maxSize = maxSize < capacity ? capacity : maxSize;
    }

    /**
     * 初始化函数
     * @param byteBuffer 初始化用的 ByteBuffer
     */
    public void init(ByteBuffer byteBuffer){
        this.byteBuffer = byteBuffer;
        resetAddress();
        this.size = byteBuffer.remaining();
    }

    /**
     * 构造一个ByteBuffer
     * @param capacity 分配的容量
     * @return ByteBuffer 对象
     */
    private ByteBuffer newByteBuffer(int capacity){
        try {

            ByteBuffer instance = TByteBuffer.allocateDirect(capacity);
            address.set(TByteBuffer.getAddress(instance));

            return instance;

        }catch(Exception e){
            Logger.error("Create ByteBufferChannel error. ", e);
            return null;
        }
    }

    public int getMaxSize() {
        return maxSize;
    }

    public void setMaxSize(int maxSize) {
        this.maxSize = maxSize;
    }

    /**
     * 缓冲通道是否已满
     * @return true: 通道已满, false: 通道未满
     */
    public boolean isFull(){
        return maxSize <= size;
    }

    /**
     * 是否已经释放
     * @return true 已释放, false: 未释放
     */
    public boolean isReleased(){
        if(address.get() == 0 || byteBuffer == null){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 测试是否被释放
     */
    private void checkRelease(){
        if(isReleased()){
            throw new MemoryReleasedException("ByteBufferChannel is released.");
        }
    }

    /**
     * 立刻释放内存
     */
    public void release(){
        if(byteBuffer==null){
            return;
        }

        //是否手工释放
        if(!Global.NO_HEAP_MANUAL_RELEASE || byteBuffer.getClass() != TByteBuffer.DIRECT_BYTE_BUFFER_CLASS) {
            return;
        }
;
		if (address.get() != 0) {
			TByteBuffer.release(byteBuffer);
			address.set(0);
			byteBuffer = null;
			size = -1;
		}
    }

    /**
     * 重新设置当前内存地址
     */
    private void resetAddress(){
        try {
            this.address.set(TByteBuffer.getAddress(byteBuffer));
        }catch (ReflectiveOperationException e){
            Logger.error("ByteBufferChannel resetAddress() Error: ", e);
        }
    }

    /**
     * 当前数组空闲的大小
     * @return 当前数组空闲的大小. -1: 已释放
     */
    public int available(){
        if(isReleased()){
            return -1;
        }

		return byteBuffer.capacity() - size;
    }

    /**
     * 返回当前分配的容量
     * @return 当前分配的容量. -1: 已释放
     */
    public int capacity(){
        if(isReleased()){
            return -1;
        }

		return byteBuffer.capacity();
    }

    /**
     * 当前数据大小
     * @return 数据大小 . -1: 已释放
     */
    public int size(){
        return size;
    }

    /**
     * 获取缓冲区有效字节数组的一个拷贝
     *        修改这个数组将不会影响当前对象
     *        返回 0 到 size 的有效数据
     *        从堆外复制到堆内
     * @return 缓冲区有效字节数组. null: 已释放
     */
    public byte[] array(){
        if(size()==0){
            return new byte[]{};
        }

		checkRelease();

		byte[] temp = new byte[size];
		get(temp, 0, size);
		return temp;
    }

    /**
     * 清空通道
     */
    public void clear() {
        if (isReleased()) {
            return;
        }

        if(size!=0) {
			if (byteBuffer != null) {
				byteBuffer.limit(0);
				size = 0;
			}
        }
    }

    /**
     * 从某一个偏移量位置开始收缩数据
     * @param shrinkPosition      收缩的偏移量位置
     * @param shrinkSize  收缩的数据大小, 大于0: 向尾部收缩, 小于0: 向头部收缩
     * @return true: 成功, false: 失败
     */
    public boolean shrink(int shrinkPosition, int shrinkSize){
		checkRelease();

		if(isReleased()){
			return false;
		}

		if(size()==0){
			return true;
		}

		if(shrinkSize==0){
			return true;
		}

		if(shrinkPosition < 0){
			return false;
		}

		if(shrinkSize < 0 && shrinkPosition + shrinkSize < 0){
			shrinkSize = shrinkPosition * -1;
		}

		if(shrinkSize > 0 && shrinkPosition + shrinkSize > size()){
			shrinkSize = size() - shrinkPosition;
		}

		if(Math.abs(shrinkSize) > size){
			return true;
		}

		int position = byteBuffer.position();
		byteBuffer.position(shrinkPosition);
		if(shrinkSize > 0){
			byteBuffer.position(shrinkPosition + shrinkSize);
		}
		if (TByteBuffer.moveData(byteBuffer, Math.abs(shrinkSize)*-1)) {
			if(position > shrinkPosition){
				position = position + shrinkPosition;
			}

			if(position < byteBuffer.limit()) {
				byteBuffer.position(position);
			}

			size = size - Math.abs(shrinkSize);
			return true;
		}else{
			//收缩失败了,重置原 position 的位置
			byteBuffer.position(position);
			return false;
		}
    }

    /**
     * 收缩通道内的数据
     *
     * @param shrinkSize 收缩的偏移量: 大于0: 从头部向尾部收缩数据, 小于0: 从尾部向头部收缩数据
     * @return true: 成功, false: 失败
     */
    public boolean shrink(int shrinkSize){
		if(shrinkSize==0){
			return true;
		}else if(shrinkSize > 0)
			return shrink(0, shrinkSize);
		else
			return shrink(size, shrinkSize);
    }


    /**
     * 获取某个位置的 byte 数据
     *     该操作不会导致通道内的数据发生变化
     * @param position 位置
     * @return byte 数据
     */
    public byte get(int position) throws IndexOutOfBoundsException {
		checkRelease();

		if(size()==0){
			throw new IndexOutOfBoundsException();
		}

		if(position >= 0 && position <= size) {
			byte result = unsafe.getByte(address.get() + position);
			return result;
		} else {
			checkRelease();
			throw new IndexOutOfBoundsException();
		}
    }

    /**
     * 获取某个位置的 byte 数据数组
     *     该操作不会导致通道内的数据发生变化
     * @param dst     目标数组
     * @param position  位置
     * @param length  长度
     * @return 获取数据的长度
     */
    public int get(byte[] dst, int position, int length) throws IndexOutOfBoundsException {
		checkRelease();

		if(size()==0){
			return 0;
		}

		int availableCount = size() - position;

		if(position >= 0 && availableCount >= 0) {

			if(availableCount == 0){
				return 0;
			}

			int arrSize = availableCount;

			if(length < availableCount){
				arrSize = length;
			}

			unsafe.copyMemory(null, address.get() + position, dst, Unsafe.ARRAY_BYTE_BASE_OFFSET, length);

			return arrSize;

		} else {
			checkRelease();
			throw new IndexOutOfBoundsException();
		}
    }

    /**
     * 获取某个偏移量位置的 byte 数据数组
     *     该操作不会导致通道内的数据发生变化
     * @param dst     目标数组
     * @return 获取数据的长度
     */
    public int get(byte[] dst){
        return get(dst, 0, dst.length);
    }

    /**
     * 获取缓冲区
     *     返回 0 到 size 的有效数据
     *	   为了保证数据一致性, 这里会加锁
     *	   在调用getByteBuffer()方法后,跨线程的读写操作都会被阻塞.
     *	   但在调用getByteBuffer()方法后,同一线程内的所有读写操作是可以操作,
     *	   为保证数据一致性,除非特殊需要,否则在编码时应当被严格禁止.
     *	   在调用getByteBuffer()方法后,所以必须配合 compact() 方法使用,
     *	   已保证对 byteBuffer 的所有读写操作都在 ByteBufferChannel上生效.
     * @return ByteBuffer 对象
     */
    public ByteBuffer getByteBuffer() {
        //这里上锁,在compact()方法解锁
//        lock.lock();
        try {
            checkRelease();

            borrowed.compareAndSet(false, true);
            return byteBuffer;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取 bytebuffer 的 hashcode
     * @param size slice 的数据大小
     * @return bytebuffer 的 hashcode
     */
    public ByteBuffer slice(int size){

        int oldLimit = byteBuffer.limit();
        try {
            checkRelease();

            byteBuffer.limit(byteBuffer.position()+size);
            return byteBuffer.slice();
        } finally {
            byteBuffer.limit(oldLimit);
        }
    }

    /**
     * 收缩通道
     *      将通过 getByteBuffer() 方法获得 ByteBuffer 对象的操作同步到 ByteBufferChannel
     * 		如果之前最后一次通过 getByteBuffer() 方法获得过 ByteBuffer,则使用这个 ByteBuffer 来收缩通道
     *      将 (position 到 limit) 之间的数据 移动到 (0  到 limit - position) 其他情形将不做任何操作
     *		所以 必须 getByteBuffer() 和 compact() 成对操作
     * @return 是否compact成功,true:成功, false:失败
     */
    public boolean compact(){
        if(isReleased()){
            return false;
        }

        if(size()==0 && !byteBuffer.hasRemaining()){
            return true;
        }

		if(byteBuffer.position() == 0){
			this.size = byteBuffer.limit();
			return true;
		}

		int position = byteBuffer.position();
		int limit = byteBuffer.limit();
		boolean result = false;
		if(TByteBuffer.moveData(byteBuffer, position*-1)) {
			byteBuffer.position(0);
			size = limit - position;
			byteBuffer.limit(size);

			result = true;
		}
		return result;

    }

    /**
     * 等待期望的数据长度
     * @param length  期望的数据长度
     * @param timeout 超时时间,单位: 毫秒
     * @param supplier 每次等待数据所做的操作
     * @return true: 具备期望长度的数据, false: 等待数据超时
     */
    public boolean waitData(int length,int timeout, Runnable supplier){
        try {
            TEnv.wait(timeout, ()->{
                checkRelease();

                if(size() >= length){
                	return false;
                } else {
	                supplier.run();
	                return size() < length;
                }
            });
            return true;
        } catch (TimeoutException e) {
            return false;
        }
    }


    /**
     * 从头部开始判断是否收到期望的数据
     * @param mark  期望出现的数据
     * @param timeout 超时时间,单位: 毫秒
     * @param supplier 每次等待数据所做的操作
     * @return true: 具备期望长度的数据, false: 等待数据超时
     */
    public boolean waitData(byte[] mark, int timeout, Runnable supplier){

        try {
            TEnv.wait(timeout, ()->{
                checkRelease();
                if(indexOf(mark) != -1) {
	               return false;
                } else {
	                supplier.run();
	                return indexOf(mark) == -1;
                }
            });
            return true;
        } catch (TimeoutException e) {
            return false;
        }
    }

    /**
     * 重新分配内存空间的大小
     * @param newSize  重新分配的空间大小
     * @return true:成功, false:失败
     * @throws LargerThanMaxSizeException 通道容量不足的一场
     */
    public boolean reallocate(int newSize) throws LargerThanMaxSizeException {
		checkRelease();

		//检查分配内存是否超过限额
		if(maxSize < newSize){
			throw new LargerThanMaxSizeException("Max size: " + maxSize + ", expect size: " + newSize);
		}

		if (TByteBuffer.reallocate(byteBuffer, newSize)) {
			resetAddress();
			return true;
		}else{
			return false;
		}
    }

    /**
     * 缓冲区某个位置写入数据
     * @param writePosition 缓冲区中的位置
     * @param src 需要写入的缓冲区 ByteBuffer 对象
     * @return 写入的数据大小
     */
    public int write(int writePosition, ByteBuffer src) {

		checkRelease();

		if(src.remaining() == 0){
			return 0;
		}

		if (src == null) {
			return -1;
		}

		int writeSize = src.limit() - src.position();

		if (writeSize > 0) {
			//是否扩容
			if (available() < writeSize) {
				int newSize = byteBuffer.capacity() + writeSize;
				reallocate(newSize);
			}

			int position = byteBuffer.position();
			byteBuffer.position(writePosition);

			if(TByteBuffer.moveData(byteBuffer, writeSize)){

				size = size + writeSize;
				byteBuffer.limit(size);
				byteBuffer.position(writePosition);
				byteBuffer.put(src);

				if (position > writePosition) {
					position = position + writeSize;
				}

				byteBuffer.position(position);
			} else {
				checkRelease();
				throw new RuntimeException("move data failed");
			}
		}

		return writeSize;

    }

    /**
     * 缓冲区头部写入
     * @param src 需要写入的缓冲区 ByteBuffer 对象
     * @return 写入的数据大小
     */
    public int writeEnd(ByteBuffer src) {
		checkRelease();

		return write(size(), src);
    }

    /**
     * 缓冲区尾部写入
     * @param src 需要写入的缓冲区 ByteBuffer 对象
     * @return 读出的数据大小
     */
    public int writeHead(ByteBuffer src) {
        return write(0, src);
    }

    /**
     * 从缓冲区头部读取数据
     * @param dst 需要读入数据的缓冲区ByteBuffer 对象
     * @return 读出的数据大小
     */
    public int readHead(ByteBuffer dst) {
        return read(0, dst);
    }

    /**
     * 从缓冲区尾部读取数据
     * @param dst 需要读入数据的缓冲区ByteBuffer 对象
     * @return 读出的数据大小
     */
    public int readEnd(ByteBuffer dst) {
		checkRelease();

		return read( size()-dst.limit(), dst );
    }

    /**
     * 从缓冲区某个位置开始读取数据
     * @param readPosition 缓冲区中的位置
     * @param dst 需要读入数据的缓冲区ByteBuffer 对象
     * @return 读出的数据大小
     */
    public int read(int readPosition, ByteBuffer dst) {
		checkRelease();

		if(dst.remaining() == 0){
			return 0;
		}

		if(dst==null){
			return -1;
		}

		int readSize = 0;

		//确定读取大小
		if (dst.remaining() > size - readPosition) {
			readSize = size - readPosition;
		} else {
			readSize = dst.remaining();
		}

		if (readSize != 0) {
			int position = byteBuffer.position();
			byteBuffer.position(readPosition);

			int dstRemain = dst.remaining();
			int oldLimit = byteBuffer.limit();
			if(dstRemain readPosition){
					position = position + (readSize*-1);
				}

				byteBuffer.position(position);
			} else {
				dst.reset();
			}
		}

		dst.flip();
		return readSize;
    }

    /**
     * 查找特定 byte 标识的位置
     *     byte 标识数组第一个字节的索引位置
     * @param mark byte 标识数组
     * @return 第一个字节的索引位置
     */
    public int indexOf(byte[] mark){
		checkRelease();

		if(size() == 0){
			return -1;
		}

		return TByteBuffer.indexOf(byteBuffer, mark);
    }

	public boolean startWith(byte[] mark){
		checkRelease();

		if(size() < mark.length){
			return false;
		}

		boolean result = true;

		for(int i=0;i= 0) {
            ByteBuffer byteBuffer = getByteBuffer();

            try {
                if (byteBuffer == null) {
                    return null;
                }

                int limit = byteBuffer.limit();
                byteBuffer.limit(index + 1);
                lineStr = TByteBuffer.toString(byteBuffer);
                byteBuffer.limit(limit);
                byteBuffer.position(index + 1);
            } finally {
                compact();
            }
        }

        if(size()>0 && index==-1){
            ByteBuffer byteBuffer = getByteBuffer();

            try {
                lineStr = TByteBuffer.toString(byteBuffer);
                byteBuffer.position(byteBuffer.limit());
            } finally {
                compact();
            }
        }

        return lineStr.isEmpty() && index==-1 ? null : lineStr;
    }


    /**
     * 读取一段,使用 byte数组 分割
     * 		返回的 byte数组中不包含分割 byte 数组的内容
     * @param splitByte 分割字节数组
     * @return 字节数组
     */
    public ByteBuffer readWithSplit(byte[] splitByte) {
        checkRelease();

        if(size() == 0){
            return TByteBuffer.EMPTY_BYTE_BUFFER;
        }

        int index = indexOf(splitByte);

        if (size() == 0) {
            return TByteBuffer.EMPTY_BYTE_BUFFER;
        }

        if (index == 0) {
            try {
                this.getByteBuffer().position(splitByte.length);
            } finally {
                compact();
            }

            index = indexOf(splitByte);
        }

        if (index == -1) {
            index = size();
        }

        ByteBuffer resultBuffer = TByteBuffer.allocateDirect(index);
        int readSize = readHead(resultBuffer);
        TByteBuffer.release(resultBuffer);

        //跳过分割符
        shrink(splitByte.length);

        return resultBuffer;

    }

    /**
     * 保存到文件
     * @param filePath 文件路径
     * @param length 需要保存的长度
     * @throws IOException Io 异常
     */
    public void saveToFile(String filePath, long length) throws IOException{
        checkRelease();

        if(size() == 0){
            return;
        }

        int bufferSize = 1024 * 1024;

        if (length < bufferSize) {
            bufferSize = Long.valueOf(length).intValue();
        }

        new File(TFile.getFileDirectory(filePath)).mkdirs();

        RandomAccessFile randomAccessFile = null;
        File file = new File(filePath);
        byte[] buffer = new byte[bufferSize];
        try {
            randomAccessFile = new RandomAccessFile(file, "rwd");
            //追加形式
            randomAccessFile.seek(randomAccessFile.length());

            int loadSize = bufferSize;
            ByteBuffer tempByteBuffer = ByteBuffer.wrap(buffer);
            while (length > 0) {
                loadSize = length > bufferSize ? bufferSize : Long.valueOf(length).intValue();

                tempByteBuffer.limit(loadSize);

                this.readHead(tempByteBuffer);

                randomAccessFile.write(buffer, 0, loadSize);

                length = length - loadSize;

                tempByteBuffer.clear();
            }

//			System.out.println(filePath);
        } catch (IOException e) {
            throw e;
        } finally {
            randomAccessFile.close();
        }

    }

    @Override
    public String toString(){
        return "{size="+size+", capacity="+capacity()+", released="+(address.get()==0)+", maxSize=" + maxSize + "}";
    }

    /**
     * 获取内容
     * @return 内容字符串
     */
    public String content(){
        return new String(array());
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy