com.bagri.server.hazelcast.store.MemoryMappedStore Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bagri-server-hazelcast Show documentation
Show all versions of bagri-server-hazelcast Show documentation
Bagri DB Cache: Hazelcast implementation
The newest version!
package com.bagri.server.hazelcast.store;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.hazelcast.core.IMap;
public abstract class MemoryMappedStore {
protected final Logger logger = LoggerFactory.getLogger(getClass());
protected static final int szInt = 4;
protected Map pointers = new HashMap<>();
private List buffers = new ArrayList<>(8);
protected AtomicInteger cntActive = new AtomicInteger(0);
protected String dataPath;
protected String nodeNum;
protected boolean initialized;
protected int buffSize;
protected abstract String getBufferName(int section);
protected abstract K getEntryKey(E entry);
protected abstract int getEntrySize(E entry);
protected abstract boolean isEntryActive(E entry);
protected abstract E readEntry(MappedByteBuffer buff);
protected abstract void writeEntry(MappedByteBuffer buff, E entry);
protected abstract void deactivateEntry(MappedByteBuffer buff, E entry);
public MemoryMappedStore(String dataPath, String nodeNum, int buffSize) {
this.dataPath = dataPath;
this.nodeNum = nodeNum;
this.buffSize = buffSize;
}
public void init(IMap cache) {
//
initialized = true;
}
public void close() {
for (FileBuffer fb: buffers) {
try {
fb.close();
} catch (IOException ex) {
logger.error("close.error: ", ex);
}
}
}
public Collection getEntryKeys() {
return pointers.keySet();
}
public E getEntry(K key) {
E result = null;
Integer pointer = pointers.get(key);
if (pointer != null) {
int sect = toSection(pointer);
int pos = toPosition(pointer);
FileBuffer fb = buffers.get(sect);
fb.lock();
try {
fb.buff.position(pos);
result = readEntry(fb.buff);
} finally {
fb.unlock();
}
} else {
logger.debug("getEntry; cann't find entry for key: {}", key);
}
return result;
}
public boolean putEntry(K key, E entry, boolean expectExists) {
boolean result = clearEntry(key, entry, expectExists);
if (!result) {
return false;
}
FileBuffer fb = getLockedBuffer(entry);
try {
fb.reset();
int pos = fb.buff.position();
int point = toPointer(pos, fb.section);
pointers.put(key, point);
int cnt = fb.buff.getInt(0);
cnt++;
fb.buff.putInt(0, cnt);
writeEntry(fb.buff, entry);
fb.setTail();
if (isEntryActive(entry)) {
cntActive.incrementAndGet();
}
} finally {
fb.unlock();
}
return true;
}
public boolean clearEntry(K key, E entry, boolean expectExists) {
Integer pointer = pointers.get(key);
if (pointer != null) {
if (!expectExists) {
// already exists, but not expected
logger.debug("clearEntry; entry already exists, but not expected; key: {}", key);
return false;
}
int sect = toSection(pointer);
int pos = toPosition(pointer);
FileBuffer fb = buffers.get(sect);
fb.lock();
try {
fb.buff.position(pos);
//mark entry as inactive..
deactivateEntry(fb.buff, entry);
cntActive.decrementAndGet();
} finally {
fb.unlock();
}
} else {
if (expectExists) {
// not exists, but expected
logger.debug("clearEntry; entry not found, but expected; key: {}", key);
return false;
}
}
return true;
}
protected int getSection(String fileName) {
int pos1 = fileName.indexOf("_") + 1;
int pos2 = fileName.indexOf(".", pos1);
return Integer.parseInt(fileName.substring(pos1, pos2));
}
protected synchronized FileBuffer initBuffer(String fileName, int section) throws IOException {
FileBuffer fb = new FileBuffer(fileName, buffSize, section);
buffers.add(fb);
int expected = buffers.size() - 1;
if (expected != section) {
logger.warn("initBuffer; added buffer at the wrong position: {}; expected: {}", expected, section);
}
fb.reset();
return fb;
}
protected int readEntries(FileBuffer fb) {
logger.trace("readEntries.enter; file buffer: {}", fb);
int idx = 0;
int actCount = 0;
int sect = fb.section;
fb.buff.position(0);
int docCount = fb.buff.getInt();
while (idx < docCount) {
int pos = fb.buff.position();
pos = toPointer(pos, sect);
E entry = readEntry(fb.buff);
pointers.put(getEntryKey(entry), pos);
idx++;
if (isEntryActive(entry)) {
actCount++;
}
}
fb.setTail();
logger.trace("readEntries.exit; active entries: {}; pointers: {}", actCount, pointers.size());
cntActive.addAndGet(actCount);
return actCount;
}
protected int loadEntries(IMap cache) {
logger.trace("loadEntries.enter; entry count: {}", cache.size());
int actCount = 0;
int sect = 0;
int cnt = 0;
FileBuffer fb = null;
for (E entry: cache.values()) {
if (fb == null) {
fb = getLockedBuffer(entry);
}
int pos = fb.buff.position();
pos = toPointer(pos, sect);
pointers.put(getEntryKey(entry), pos);
writeEntry(fb.buff, entry);
if (isEntryActive(entry)) {
actCount++;
}
cnt++;
if (fb.buff.remaining() < getEntrySize(entry)) {
fb.setTail();
fb.buff.putInt(0, cnt);
fb.unlock();
fb = null;
cnt = 0;
}
}
if (fb != null) {
fb.setTail();
fb.buff.putInt(0, cnt);
fb.unlock();
}
logger.trace("loadEntries.exit; active entries: {}; pointers: {}", actCount, pointers.size());
cntActive.addAndGet(actCount);
return actCount;
}
private synchronized FileBuffer getLockedBuffer(E entry) {
FileBuffer fb = buffers.get(buffers.size() - 1);
if (fb.buff.remaining() < getEntrySize(entry)) {
int sect = fb.section + 1;
String fName = getBufferName(sect);
try {
fb = initBuffer(fName, sect);
} catch (IOException ex) {
logger.error("getLockedBuffer.error:", ex);
throw new RuntimeException(ex);
}
}
fb.lock();
return fb;
}
private int toPointer(int position, int section) {
int result = position << 6;
return result | section;
}
private int toPosition(int pointer) {
return pointer >> 6;
}
private int toSection(int pointer) {
return pointer & 0x0000003F;
}
protected int[] getIntArray(MappedByteBuffer buff) {
int len = buff.getInt();
int[] val = new int[len];
for (int i=0; i < len; i++) {
val[i] = buff.getInt();
}
return val;
}
protected void putIntArray(MappedByteBuffer buff, int[] val) {
buff.putInt(val.length);
for (int i=0; i < val.length; i++) {
buff.putInt(val[i]);
}
}
protected String getString(MappedByteBuffer buff) {
int len = buff.getInt();
//if (len > 100) {
// logger.info("getString; too long: {}", len);
//}
byte[] str = new byte[len];
buff.get(str);
return new String(str);
}
protected void putString(MappedByteBuffer buff, String val) {
byte[] str = val.getBytes();
buff.putInt(str.length);
buff.put(str);
}
protected class FileBuffer {
private int tail;
private int section;
private Lock lock;
private FileChannel fc;
private RandomAccessFile raf;
private MappedByteBuffer buff;
FileBuffer(String fileName, int size, int section) throws IOException {
this.raf = new RandomAccessFile(fileName, "rw");
this.fc = raf.getChannel();
size = Math.max(size, (int) raf.length());
this.buff = fc.map(MapMode.READ_WRITE, 0, size);
// get section from filename ?
this.section = section;
this.lock = new ReentrantLock(); //true ?
this.tail = szInt;
}
void close() throws IOException {
fc.close();
raf.close();
}
int getCount() {
return buff.getInt(0);
}
//int getTail() {
// return tail;
//}
void setTail() {
tail = buff.position();
}
void reset() {
buff.position(tail);
}
void lock() {
this.lock.lock();
}
void unlock() {
this.lock.unlock();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy