package org.opencloudb.mpp.tmp;
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel.MapMode;
/**
* 基于虚拟内存的固定长度数据项Array<br/>
* 非HotSpotVM需要重写release函<br/>
* 数释放文件句柄 <br/>
*
* @author Czp
*
*/
public class MemMapLongArray {
private int size;
private boolean isClose;
private File swapFilePath;
private MappedByteBuffer curBuf;
private LinkedList<File> mapFiles;
private ArrayList<MappedByteBuffer> bufs;
private LinkedList<RandomAccessFile> foss;
/**
* 每次扩容的大小,必须是long字节数的倍数
*/
private static final int INIT_SIZE = 8 * 30 * 1024 * 1024;
public MemMapLongArray(String swapPath) {
mapFiles = new LinkedList<File>();
bufs = new ArrayList<MappedByteBuffer>();
foss = new LinkedList<RandomAccessFile>();
createSwapPath(swapPath);
createBuffer();
}
public synchronized boolean add(long data) {
int capacity = curBuf.capacity();
int remain = 8 + curBuf.position();
if (capacity == remain) {
curBuf.putLong(data);
createBuffer();
} else if (capacity < remain) {
createBuffer();
curBuf.putLong(data);
} else if (capacity > remain) {
curBuf.putLong(data);
}
size++;
return true;
}
public synchronized long get(int index) {
MemMapUtil.checkRangeState(index, size, isClose);
int pos = index * 8;// index << 3;
int bufIndex = pos / INIT_SIZE;// pos >> MOD_NUM;
MappedByteBuffer buf = bufs.get(bufIndex);
int oldPos = buf.position();
buf.position(pos % INIT_SIZE);// pos & ((1 << MOD_NUM) - 1)
long data = buf.getLong();
buf.position(oldPos);
return data;
}
public synchronized long set(int index, long data) {
MemMapUtil.checkRangeState(index, size, isClose);
int pos = index * 8;
int bufIndex = pos / INIT_SIZE;
MappedByteBuffer buf = bufs.get(bufIndex);
int oldPos = buf.position();
buf.position(pos % INIT_SIZE);
buf.putLong(data);
buf.position(oldPos);
return data;
}
public synchronized int size() {
return size;
}
public synchronized void release() {
isClose = true;
for (RandomAccessFile fos : foss) {
MemMapUtil.close(fos);
}
for (MappedByteBuffer mbuf : bufs) {
MemMapUtil.releaseMemory(mbuf);
}
for (File f : mapFiles) {
if (!f.delete())
System.out.println("release mapbuf fail");
}
foss.clear();
bufs.clear();
mapFiles.clear();
}
private void createSwapPath(String swapPath) {
swapFilePath = new File(swapPath);
if (!swapFilePath.exists())
swapFilePath.mkdirs();
}
private void createBuffer() {
File file = null;
RandomAccessFile mapFos = null;
try {
file = File.createTempFile("mapl-", ".dat", swapFilePath);
mapFos = new RandomAccessFile(file, "rw");
curBuf = mapFos.getChannel().map(MapMode.READ_WRITE, 0, INIT_SIZE);
foss.add(mapFos);
bufs.add(curBuf);
mapFiles.add(file);
} catch (Exception e) {
MemMapUtil.close(mapFos);
if (file != null)
file.delete();
throw new RuntimeException(e);
}
}
}