163 lines
4.6 KiB
Java
163 lines
4.6 KiB
Java
package org.apache.jdbm;
|
|
|
|
import javax.crypto.Cipher;
|
|
import java.io.IOError;
|
|
import java.io.IOException;
|
|
import java.util.Comparator;
|
|
import java.util.Iterator;
|
|
|
|
/**
|
|
* Abstract class with common cache functionality
|
|
*/
|
|
abstract class DBCache extends DBStore{
|
|
|
|
static final int NUM_OF_DIRTY_RECORDS_BEFORE_AUTOCOMIT = 1024;
|
|
|
|
static final byte NONE = 1;
|
|
static final byte MRU = 2;
|
|
static final byte WEAK = 3;
|
|
static final byte SOFT = 4;
|
|
static final byte HARD = 5;
|
|
|
|
static final class DirtyCacheEntry {
|
|
long _recid; //TODO recid is already part of _hashDirties, so this field could be removed to save memory
|
|
Object _obj;
|
|
Serializer _serializer;
|
|
}
|
|
|
|
|
|
/**
|
|
* Dirty status of _hash CacheEntry Values
|
|
*/
|
|
final protected LongHashMap<DirtyCacheEntry> _hashDirties = new LongHashMap<DirtyCacheEntry>();
|
|
|
|
private Serializer cachedDefaultSerializer = null;
|
|
|
|
|
|
/**
|
|
* Construct a CacheRecordManager wrapping another DB and
|
|
* using a given cache policy.
|
|
*/
|
|
public DBCache(String filename, boolean readonly, boolean transactionDisabled,
|
|
Cipher cipherIn, Cipher cipherOut, boolean useRandomAccessFile,
|
|
boolean deleteFilesAfterClose,boolean lockingDisabled){
|
|
|
|
super(filename, readonly, transactionDisabled,
|
|
cipherIn, cipherOut, useRandomAccessFile,
|
|
deleteFilesAfterClose,lockingDisabled);
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
public synchronized Serializer defaultSerializer(){
|
|
if(cachedDefaultSerializer==null)
|
|
cachedDefaultSerializer = super.defaultSerializer();
|
|
return cachedDefaultSerializer;
|
|
}
|
|
|
|
@Override
|
|
boolean needsAutoCommit() {
|
|
return super.needsAutoCommit()||
|
|
(transactionsDisabled && !commitInProgress && _hashDirties.size() > NUM_OF_DIRTY_RECORDS_BEFORE_AUTOCOMIT);
|
|
}
|
|
|
|
|
|
|
|
public synchronized <A> long insert(final A obj, final Serializer<A> serializer, final boolean disableCache)
|
|
throws IOException {
|
|
checkNotClosed();
|
|
|
|
if(super.needsAutoCommit())
|
|
commit();
|
|
|
|
if(disableCache)
|
|
return super.insert(obj, serializer, disableCache);
|
|
|
|
|
|
//prealocate recid so we have something to return
|
|
final long recid = super.insert(PREALOCATE_OBJ, null, disableCache);
|
|
|
|
// super.update(recid, obj,serializer);
|
|
|
|
// return super.insert(obj,serializer,disableCache);
|
|
|
|
//and create new dirty record for future update
|
|
final DirtyCacheEntry e = new DirtyCacheEntry();
|
|
e._recid = recid;
|
|
e._obj = obj;
|
|
e._serializer = serializer;
|
|
_hashDirties.put(recid,e);
|
|
|
|
return recid;
|
|
}
|
|
|
|
|
|
|
|
public synchronized void commit() {
|
|
try{
|
|
commitInProgress = true;
|
|
updateCacheEntries();
|
|
super.commit();
|
|
}finally {
|
|
commitInProgress = false;
|
|
}
|
|
}
|
|
|
|
public synchronized void rollback(){
|
|
cachedDefaultSerializer = null;
|
|
_hashDirties.clear();
|
|
super.rollback();
|
|
}
|
|
|
|
|
|
private static final Comparator<DirtyCacheEntry> DIRTY_COMPARATOR = new Comparator<DirtyCacheEntry>() {
|
|
final public int compare(DirtyCacheEntry o1, DirtyCacheEntry o2) {
|
|
return (int) (o1._recid - o2._recid);
|
|
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Update all dirty cache objects to the underlying DB.
|
|
*/
|
|
protected void updateCacheEntries() {
|
|
try {
|
|
synchronized(_hashDirties){
|
|
|
|
while(!_hashDirties.isEmpty()){
|
|
//make defensive copy of values as _db.update() may trigger changes in db
|
|
//and this would modify dirties again
|
|
DirtyCacheEntry[] vals = new DirtyCacheEntry[_hashDirties.size()];
|
|
Iterator<DirtyCacheEntry> iter = _hashDirties.valuesIterator();
|
|
|
|
for(int i = 0;i<vals.length;i++){
|
|
vals[i] = iter.next();
|
|
}
|
|
iter = null;
|
|
|
|
java.util.Arrays.sort(vals,DIRTY_COMPARATOR);
|
|
|
|
|
|
for(int i = 0;i<vals.length;i++){
|
|
final DirtyCacheEntry entry = vals[i];
|
|
vals[i] = null;
|
|
super.update(entry._recid, entry._obj, entry._serializer);
|
|
_hashDirties.remove(entry._recid);
|
|
|
|
}
|
|
|
|
//update may have triggered more records to be added into dirties, so repeat until all records are written.
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
throw new IOError(e);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|