package proj.zoie.store;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Comparator;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.apache.log4j.Logger;
import org.apache.lucene.util.BytesRef;
import proj.zoie.impl.indexing.ZoieConfig;
public abstract class AbstractZoieStore implements ZoieStore {
private static Logger logger = Logger.getLogger(AbstractZoieStore.class);
private boolean _dataCompressed = true;
private Comparator<String> _versionComparator = ZoieConfig.DEFAULT_VERSION_COMPARATOR;
private volatile String _version = null;
private final Long2ObjectLinkedOpenHashMap<byte[]> _dataMap = new Long2ObjectLinkedOpenHashMap<byte[]>();
private final ReentrantReadWriteLock _dataMapLock = new ReentrantReadWriteLock();
private final WriteLock _writeLock = _dataMapLock.writeLock();
private final ReadLock _readLock = _dataMapLock.readLock();
public void setVersionComparator(Comparator<String> versionComparator) {
_versionComparator = versionComparator;
}
public Comparator<String> getVersionComparator() {
return _versionComparator;
}
public void setDataCompressed(boolean dataCompressed) {
_dataCompressed = dataCompressed;
}
public boolean isDataCompressed() {
return _dataCompressed;
}
protected abstract void persist(long uid, byte[] data) throws IOException;
protected abstract void persistDelete(long uid) throws IOException;
protected abstract BytesRef getFromStore(long uid) throws IOException;
protected abstract void commitVersion(String version) throws IOException;
@Override
public abstract void close() throws IOException;
@Override
public abstract void open() throws IOException;
public static byte[] compress(byte[] src) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
GZIPOutputStream gzipStream = new GZIPOutputStream(bout);
gzipStream.write(src);
gzipStream.flush();
gzipStream.close();
bout.flush();
return bout.toByteArray();
}
public static byte[] uncompress(byte[] src) throws IOException {
byte[] buffer = new byte[1024]; // 1k buffer
ByteArrayInputStream bin = new ByteArrayInputStream(src);
GZIPInputStream gzipIn = new GZIPInputStream(bin);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
while (gzipIn.available() > 0) {
int len = gzipIn.read(buffer);
if (len <= 0) break;
if (len < buffer.length) {
bout.write(buffer, 0, len);
} else {
bout.write(buffer);
}
}
bout.flush();
return bout.toByteArray();
}
@Override
public void commit() throws IOException {
_writeLock.lock();
try {
commitVersion(_version);
_dataMap.clear();
} finally {
_writeLock.unlock();
}
}
@Override
public void delete(long uid, String version) throws IOException {
_writeLock.lock();
try {
persistDelete(uid);
_dataMap.remove(uid);
_version = version;
} finally {
_writeLock.unlock();
}
}
@Override
public final void put(long uid, byte[] data, String version) throws IOException {
if (_dataCompressed) {
data = compress(data);
}
_writeLock.lock();
try {
persist(uid, data);
_dataMap.put(uid, data);
_version = version;
} finally {
_writeLock.unlock();
}
}
private final byte[] innerGet(long uid) throws IOException {
byte[] data = null;
try {
_readLock.lock();
data = _dataMap.get(uid);
} finally {
_readLock.unlock();
}
if (data == null) {
BytesRef dataBytesRef = getFromStore(uid);
if (dataBytesRef != null) {
data = dataBytesRef.bytes;
}
}
if (data != null && _dataCompressed) {
data = uncompress(data);
}
return data;
}
@Override
public final byte[] get(long uid) throws IOException {
_readLock.lock();
try {
return innerGet(uid);
} finally {
_readLock.unlock();
}
}
@Override
public final String getVersion() {
return _version;
}
@Override
public byte[][] get(long[] uids) {
byte[][] dataList = new byte[uids.length][];
int idx = 0;
for (long uid : uids) {
try {
dataList[idx++] = innerGet(uid);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
return dataList;
}
}