org.voovan.tools.buffer.RingDirectBuffer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of voovan-common Show documentation
Show all versions of voovan-common Show documentation
Voovan is a java framwork and it not depends on any third-party framework.
package org.voovan.tools.buffer;
import org.voovan.tools.*;
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.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeoutException;
/**
* 环形缓冲区
*
* @author: helyho
* Voovan Framework.
* WebSite: https://github.com/helyho/Voovan
* Licence: Apache v2 License
*/
public class RingDirectBuffer {
private static int BYTEBUFFERCHANNEL_MAX_SIZE = TProperties.getInt("framework", "ByteBufferChannelMaxSize", 1024*1024*2);
private int maxSize = BYTEBUFFERCHANNEL_MAX_SIZE==0 ? 1024*1024*2 : BYTEBUFFERCHANNEL_MAX_SIZE;
private static Unsafe unsafe = TUnsafe.getUnsafe();
private ByteBuffer byteBuffer;
private long address = 0;
private int readPositon = 0;
private int writePositon = 0;
private int capacity;
/**
* 使用默认容量构造一个环形缓冲区
*/
public RingDirectBuffer(){
this(TByteBuffer.DEFAULT_BYTE_BUFFER_SIZE);
}
/**
* 使用指定容量构造一个环形缓冲区
* @param capacity 分配的容量
*/
public RingDirectBuffer(int capacity){
this(TByteBuffer.allocateDirect(capacity));
}
/**
* 使用指定容量构造一个环形缓冲区
* @param byteBuffer ByteBuffer 对象
*/
public RingDirectBuffer(ByteBuffer byteBuffer){
if(byteBuffer.hasArray()){
throw new UnsupportedOperationException();
}
this.capacity = byteBuffer.capacity();
this.byteBuffer = byteBuffer;
try {
this.address = TByteBuffer.getAddress(byteBuffer);
} catch (ReflectiveOperationException e) {
Logger.error("Get bytebuffer address error.");
}
}
/**
* 获得环形缓冲区的基地址
* @return 环形缓冲区的基地址
*/
public long getAddress() {
return address;
}
/**
* 获得读指针位置
* @return 读指针位置
*/
public int getReadPositon() {
return readPositon;
}
/**
* 获得写指针位置
* @return 写指针位置
*/
public int getWritePositon() {
return writePositon;
}
/**
* 获得容量
* @return 容量
*/
public int getCapacity() {
return capacity;
}
/**
* 读指针跳过特定的偏移量
* @param offset 偏移量
* @return true: 成功, false: 失败
*/
public boolean skip(int offset){
checkRelease();
if(remaining() < offset || offset < 0){
return false;
}
readPositon = ( readPositon + offset ) % capacity;
return true;
}
/**
* 缓冲区空判断
* @return true: 缓冲区无可用数据, false: 缓冲区有可用数据
*/
public Boolean isEmpty() {
return readPositon == writePositon;
}
/**
* 缓冲区满判断
* @return true: 缓冲区已满, false: 缓冲区未满
*/
public Boolean isFull() {
return (writePositon + 1) % capacity == readPositon;
}
/**
* 清理缓冲区
*/
public void clear() {
checkRelease();
this.readPositon = 0;
this.writePositon = 0;
}
/**
* 获得基于索引位置的数据
* @param offset 偏移量
* @return byte 数据
*/
public byte get(int offset) {
checkRelease();
if(offset < remaining()) {
int realOffset = (readPositon + offset) % capacity;
return unsafe.getByte(address + realOffset);
} else {
throw new IndexOutOfBoundsException();
}
}
/**
* 读取所有缓冲区的数据
* 不影响读写位置
* @param byteBuffer ByteBuffer 对象
* @return 读取数据大小
*/
public int get(ByteBuffer byteBuffer) {
checkRelease();
int size = byteBuffer.remaining();
if(size > remaining()){
size = remaining();
}
for(int i=0;i remaining()){
length = remaining();
}
for(int i=offset;i 0){
write(byteBuffer.get());
size++;
writeSize--;
}
return size;
}
/**
* 缓冲区可读数据量
* @return 缓冲区可用数据量
*/
public int remaining() {
checkRelease();
if(writePositon == readPositon){
return 0;
} else if(writePositon < readPositon){
return capacity - readPositon + writePositon;
} else {
return writePositon - readPositon;
}
}
/**
* 缓冲区可写空间
* @return 缓冲区可写空间
*/
public int avaliable() {
checkRelease();
return capacity - remaining() - 1;
}
/**
* 读取一个 byte
* @return byte 数据
*/
public byte read() {
checkRelease();
if (isEmpty()) {
throw new BufferUnderflowException();
}
byte result = unsafe.getByte(address + readPositon);
readPositon = (readPositon + 1) % capacity;
if(isEmpty() && readPositon!=0){
clear();
}
return result;
}
/**
* 读取缓冲区的数据
* @param byteBuffer ByteBuffer 对象
* @return 读取数据大小
*/
public int read(ByteBuffer byteBuffer) {
checkRelease();
int size = byteBuffer.remaining();
if(size > remaining()){
size = remaining();
}
for(int i=0;i remaining()){
length = remaining();
}
for(int i=offset;i{
if(remaining() >= length){
return false;
} else {
supplier.run();
return remaining() < length;
}
});
}
/**
* 从头部开始判断是否收到期望的数据
* @param mark 期望出现的数据
* @param timeout 超时时间,单位: 毫秒
* @param supplier 每次等待数据所做的操作
* @return true: 具备期望长度的数据, false: 等待数据超时
*/
public boolean waitData(byte[] mark, int timeout, Runnable supplier){
checkRelease();
return TEnv.wait(timeout, ()->{
if(indexOf(mark) != -1) {
return false;
} else {
supplier.run();
return indexOf(mark) == -1;
}
});
}
/**
* 读取一行
* @return 字符串
*/
public String readLine() {
checkRelease();
if(remaining() == 0){
return null;
}
String lineStr = null;
int index = indexOf("\n".getBytes());
int size = -1;
if (index >= 0) {
if(readPositon > index) {
size = capacity - readPositon + index;
} else {
size = index - readPositon;
}
size++;
}
if(remaining()>0 && index==-1){
size = remaining();
}
byte[] temp = new byte[size];
for(int i=0;i 0) {
loadSize = length > bufferSize ? bufferSize : Long.valueOf(length).intValue();
tempByteBuffer.limit(loadSize);
this.read(tempByteBuffer);
randomAccessFile.write(buffer, 0, loadSize);
length = length - loadSize;
tempByteBuffer.clear();
}
} catch (IOException e) {
throw e;
} finally {
randomAccessFile.close();
}
}
/**
* 测试是否被释放
*/
private void checkRelease(){
if(isReleased()){
throw new MemoryReleasedException("ByteBufferChannel is released.");
}
}
public boolean isReleased(){
if(address == 0 || byteBuffer == null){
return true;
}else{
return false;
}
}
/**
* 释放内存中的数据
*/
public synchronized void release(){
address = 0;
byteBuffer = null;
TByteBuffer.release(byteBuffer);
}
/**
* 重新分配内存空间的大小
* @param dataSize 重新分配的空间大小
* @return true:成功, false:失败
* @throws LargerThanMaxSizeException 通道容量不足的一场
*/
public boolean tryExpansion(int dataSize) throws LargerThanMaxSizeException {
checkRelease();
if(dataSize > avaliable()) {
getByteBuffer();
int newCapacity = capacity + dataSize;
//检查分配内存是否超过限额
if (maxSize < dataSize) {
throw new LargerThanMaxSizeException("Max size: " + maxSize + ", expect size: " + newCapacity);
}
if (TByteBuffer.reallocate(byteBuffer, newCapacity)) {
this.capacity = newCapacity;
resetAddress();
return true;
} else {
return false;
}
} else {
return false;
}
}
public void resetAddress(){
try {
this.address = TByteBuffer.getAddress(byteBuffer);
} catch (ReflectiveOperationException e) {
Logger.error("Get bytebuffer address error.");
}
}
@Override
public String toString(){
return "readPositon=" + readPositon+", writePositon="+writePositon+", capacity="+capacity+", remaining="+remaining()+", avaliable="+avaliable()+", address="+address;
}
}