
org.mapdb20.StoreArchive Maven / Gradle / Ivy
package org.mapdb20;
import java.io.DataInput;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.NavigableMap;
/**
* Store without index table.
* Recid is actual physical offset in file.
* Very space efficient, but read-only, must be created with Data Pump
*/
//TODO modifications are thread unsafe
//TODO boundary overlaps
//TODO instance cache for reads
public final class StoreArchive extends Store{
protected static final long FILE_SIZE_OFFSET = 16;
protected static final long FIRST_RESERVED_RECID_OFFSET = FILE_SIZE_OFFSET+9*8;
protected static final long DATA_START_OFFSET = FIRST_RESERVED_RECID_OFFSET+7*8;
public StoreArchive(
String fileName,
Volume.VolumeFactory volumeFactory,
boolean readonly){
this(
fileName,
volumeFactory,
null,
1,
0,
false,
false,
null,
readonly,
false,
false,
null
);
}
public StoreArchive(
String fileName,
Volume.VolumeFactory volumeFactory,
Cache cache,
int lockScale,
int lockingStrategy,
boolean checksum,
boolean compress,
byte[] password,
boolean readonly,
boolean snapshotEnable,
boolean fileLockDisable,
DataIO.HeartbeatFileLock fileLockHeartbeat) {
super(
fileName,
volumeFactory,
cache,
lockScale,
lockingStrategy,
checksum,
compress,
password,
readonly,
snapshotEnable,
fileLockDisable,
fileLockHeartbeat);
}
protected Volume vol;
protected long volSize;
@Override
public void init() {
boolean empty = Volume.isEmptyFile(fileName);
vol = volumeFactory.makeVolume(
fileName,
readonly);
if(empty){
volSize = DATA_START_OFFSET;
vol.ensureAvailable(volSize);
//fill recids
for(long recid=1;recid>>4;
}
}
@Override
protected A get2(long recid, Serializer serializer) {
if(recid<=Engine.RECID_LAST_RESERVED) {
//special case for reserved recid
recid = DataIO.parity4Get(
vol.getLong(FIRST_RESERVED_RECID_OFFSET+recid*8-8))>>>4;
if(recid==0)
return null;
}
if(recid>volSize)
throw new DBException.EngineGetVoid();
//read size, extract number of bytes read
long recSize = vol.getPackedLong(recid);
long recSizeBytesRead = recSize>>>60;
recSize &= DataIO.PACK_LONG_RESULT_MASK;
if(recSize==0) {
throw new DBException.EngineGetVoid();
}
//do parity check, normalize
recSize = (DataIO.parity1Get(recSize)>>>1)-1;
if(recSize==-1) {
return null;
}
if(recid + recSizeBytesRead + recSize>volSize){
throw new DBException.DataCorruption("Record goes beyond EOF");
}
DataInput in = vol.getDataInputOverlap(recid + recSizeBytesRead, (int) recSize);
return deserialize(serializer, (int) recSize, in);
}
@Override
public long put(A value, Serializer serializer) {
if(readonly) {
throw new UnsupportedOperationException("StoreArchive is read-only");
}
if(value==null){
//null record, write zero and we are done
long ret = volSize;
vol.ensureAvailable(volSize+1);
volSize+=vol.putPackedLong(volSize, DataIO.parity1Set(0<<1));
return ret;
}
DataIO.DataOutputByteArray out = serialize(value, serializer);
return add2(out);
}
protected long add2(DataIO.DataOutputByteArray out) {
long size = DataIO.parity1Set((1L + out.pos) << 1);
//make sure that size will not overlap, there must be at least 10 bytes before overlap
if(volSize>>>CC.VOLUME_PAGE_SHIFT!=(volSize+5)>>CC.VOLUME_PAGE_SHIFT){
volSize = Fun.roundUp(volSize, 1L< catalog) {
if(readonly) {
throw new UnsupportedOperationException("StoreArchive is read-only");
}
long offset = Pump.buildTreeMap(
(Iterator) catalog.descendingMap().entrySet().iterator(),
this,
Fun.extractMapEntryKey(),
Fun.extractMapEntryValue(),
true,
32,
false,
0L,
BTreeKeySerializer.STRING,
Serializer.BASIC, //TODO attach this to DB serialization, update POJO class catalog if needed
null
);
offset = DataIO.parity4Set(offset<<4);
vol.putLong(StoreArchive.FIRST_RESERVED_RECID_OFFSET + Engine.RECID_NAME_CATALOG*8-8,offset);
}
@Override
public long getCurrSize() {
return volSize;
}
@Override
protected void update2(long recid, DataIO.DataOutputByteArray out) {
if(readonly) {
throw new UnsupportedOperationException("StoreArchive is read-only");
}
if(recid<=Engine.RECID_LAST_RESERVED) {
//special case for reserved recid
long recidVal = out==null ? 0 : add2(out); //insert new data
vol.putLong(FIRST_RESERVED_RECID_OFFSET+recid*8-8,
DataIO.parity4Set(recidVal<<4)); //and update index micro-table
return;
}
//update only if old record has the same size, and record layout does not have to be changed
if(recid>volSize)
throw new DBException.EngineGetVoid();
//read size, extract number of bytes read
long recSize = vol.getPackedLong(recid);
long recSizeBytesRead = recSize>>>60;
recSize &= DataIO.PACK_LONG_RESULT_MASK;
if(recSize==0) {
throw new DBException.EngineGetVoid();
}
//do parity check, normalize
recSize = (DataIO.parity1Get(recSize)>>>1)-1;
if(recSize==-1 && out!=null) {
//TODO better exception
throw new DBException.WrongConfig(
"StoreArchive supports updates only if old and new record has the same size." +
"But here old=null, new!=null");
}
if(recSize!=out.pos){
//TODO better exception
throw new DBException.WrongConfig(
"StoreArchive supports updates only if old and new record has the same size." +
"But here oldSize="+recSize+", newSize="+out.pos);
}
//overwrite data
vol.putDataOverlap(recid + recSizeBytesRead, out.buf, 0, out.pos);
}
@Override
protected void delete2(long recid, Serializer serializer) {
throw new UnsupportedOperationException("StoreArchive is read-only");
}
@Override
public long getFreeSize() {
return 0;
}
@Override
public boolean fileLoad() {
return vol.fileLoad();
}
@Override
public void backup(OutputStream out, boolean incremental) {
throw new UnsupportedOperationException("StoreArchive has different RECID layout");
}
@Override
public void backupRestore(InputStream[] in) {
throw new UnsupportedOperationException("StoreArchive has different RECID layout");
}
@Override
public long preallocate() {
throw new UnsupportedOperationException("StoreArchive is read-only");
}
@Override
public void rollback() throws UnsupportedOperationException {
throw new UnsupportedOperationException("StoreArchive is read-only");
}
@Override
public boolean canRollback() {
return false;
}
@Override
public Engine snapshot() throws UnsupportedOperationException {
return this;
}
@Override
public void compact() {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy