From: Bryan T. <tho...@us...> - 2007-03-12 18:06:19
|
Update of /cvsroot/cweb/bigdata/src/java/com/bigdata/journal In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv21164/src/java/com/bigdata/journal Modified Files: CommitRecord.java Name2Addr.java ReadCommittedTx.java Tx.java CommitRecordIndex.java IAtomicStore.java Journal.java TemporaryStore.java Log Message: Working on canonicalizing mappings to improve resource utilization. Index: CommitRecord.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/journal/CommitRecord.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** CommitRecord.java 8 Mar 2007 18:14:06 -0000 1.3 --- CommitRecord.java 12 Mar 2007 18:06:11 -0000 1.4 *************** *** 48,51 **** --- 48,52 ---- package com.bigdata.journal; + /** * A read-only view of an {@link ICommitRecord}. Index: Name2Addr.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/journal/Name2Addr.java,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** Name2Addr.java 11 Mar 2007 11:42:45 -0000 1.5 --- Name2Addr.java 12 Mar 2007 18:06:11 -0000 1.6 *************** *** 25,28 **** --- 25,38 ---- * known {@link Addr address} of the {@link BTreeMetadata} record for the named * index. + * <p> + * Note: The {@link Journal} maintains an instance of this class that evolves + * with each {@link Journal#commit()}. However, the journal also makes use of + * historical states for the {@link Name2Addr} index in order to resolve the + * historical state of a named index. Of necessity, the {@link Name2Addr} + * objects used for this latter purpose MUST be distinct from the evolving + * instance otherwise the current version of the named index would be resolved. + * Note further that the historical {@link Name2Addr} states are accessed using + * a canonicalizing mapping but that current evolving {@link Name2Addr} instance + * is NOT part of that mapping. */ public class Name2Addr extends BTree { *************** *** 35,67 **** * synchonization interface for multi-threaded use or move an instance onto * the store since it already has a single-threaded contract for its api? ! */ private KeyBuilder keyBuilder = new KeyBuilder(); /** ! * Cache of added/retrieved btrees. Only btrees found in this cache are ! * candidates for the commit protocol. The use of this cache also minimizes ! * the use of the {@link #keyBuilder} and therefore minimizes the relatively ! * expensive operation of encoding unicode names to byte[] keys. * ! * FIXME This is the place to solve the resource (RAM) burden for indices is ! * Name2Addr. Currently, indices are never closed once opened which is a ! * resource leak. We need to close them out eventually based on LRU plus ! * timeout plus NOT IN USE. The way to approach this is a weak reference ! * cache combined with an LRU or hard reference queue that tracks reference ! * counters (just like the BTree hard reference cache for leaves). Eviction ! * events lead to closing an index iff the reference counter is zero. ! * Touches keep recently used indices from closing even though they may have ! * a zero reference count. */ ! private Map<String,IIndex> name2BTree = new HashMap<String,IIndex>(); ! public Name2Addr(IRawStore store) { super(store, DEFAULT_BRANCHING_FACTOR, ValueSerializer.INSTANCE); } /** ! * Load from the store. * * @param store --- 45,81 ---- * synchonization interface for multi-threaded use or move an instance onto * the store since it already has a single-threaded contract for its api? ! */ private KeyBuilder keyBuilder = new KeyBuilder(); /** ! * Cache of added/retrieved btrees by _name_. This cache is ONLY used by the ! * "live" {@link Name2Addr} instance. Only the indices found in this cache ! * are candidates for the commit protocol. The use of this cache also ! * minimizes the use of the {@link #keyBuilder} and therefore minimizes the ! * relatively expensive operation of encoding unicode names to byte[] keys. * ! * FIXME This never lets go of an unisolated index once it has been looked ! * up and placed into this cache. Therefore, modify this class to use a ! * combination of a weak value cache (so that we can let go of the ! * unisolated named indices) and a commit list (so that we have hard ! * references to any dirty indices up to the next invocation of ! * {@link #handleCommit()}. This will require a protocol by which we notice ! * writes on the named index, probably using a listener API so that we do ! * not have to wrap up the index as a different kind of object. */ ! private Map<String, IIndex> indexCache = new HashMap<String, IIndex>(); ! ! // protected final Journal journal; ! public Name2Addr(IRawStore store) { super(store, DEFAULT_BRANCHING_FACTOR, ValueSerializer.INSTANCE); + // this.journal = store; + } /** ! * Load from the store (de-serialization constructor). * * @param store *************** *** 74,77 **** --- 88,93 ---- super(store, metadata); + // this.journal = store; + } *************** *** 92,96 **** * current commit. */ ! Iterator<Map.Entry<String,IIndex>> itr = name2BTree.entrySet().iterator(); while(itr.hasNext()) { --- 108,112 ---- * current commit. */ ! Iterator<Map.Entry<String,IIndex>> itr = indexCache.entrySet().iterator(); while(itr.hasNext()) { *************** *** 108,111 **** --- 124,130 ---- insert(getKey(name),new Entry(name,addr)); + // // place into the object cache on the journal. + // journal.touch(addr, btree); + } *************** *** 141,145 **** public IIndex get(String name) { ! IIndex btree = name2BTree.get(name); if (btree != null) --- 160,164 ---- public IIndex get(String name) { ! IIndex btree = indexCache.get(name); if (btree != null) *************** *** 154,162 **** } // re-load btree from the store. btree = BTree.load(this.store, entry.addr); ! // save name -> btree mapping in transient cache. ! name2BTree.put(name,btree); // return btree. --- 173,187 ---- } + // /* + // * Reload the index from the store using the object cache to ensure a + // * canonicalizing mapping. + // */ + // btree = journal.getIndex(entry.addr); + // re-load btree from the store. btree = BTree.load(this.store, entry.addr); ! // save name -> btree mapping in transient cache. ! indexCache.put(name,btree); // return btree. *************** *** 164,167 **** --- 189,246 ---- } + + /** + * Return the {@link Addr address} from which the historical state of the + * named index may be loaded. + * <p> + * Note: This is a lower-level access mechanism that is used by + * {@link Journal#getIndex(String, ICommitRecord)} when accessing historical + * named indices from an {@link ICommitRecord}. + * + * @param name + * The index name. + * + * @return The address or <code>0L</code> if the named index was not + * registered. + */ + protected long getAddr(String name) { + + /* + * Note: This uses a private cache to reduce the Unicode -> key + * translation burden. We can not use the normal cache since that maps + * the name to the index and we have to return the address not the index + * in order to support a canonicalizing mapping in the Journal. + */ + synchronized (addrCache) { + + Long addr = addrCache.get(name); + + if (addr == null) { + + final Entry entry = (Entry) super.lookup(getKey(name)); + + if (entry == null) { + + addr = 0L; + + } else { + + addr = entry.addr; + + } + + addrCache.put(name, addr); + + } + + return addr; + + } + + } + /** + * A private cache used only by {@link #getAddr(String)}. + */ + private HashMap<String/* name */, Long/* Addr */> addrCache = new HashMap<String, Long>(); /** *************** *** 210,215 **** super.insert(key,new Entry(name,addr)); // add name -> btree mapping to the transient cache. ! name2BTree.put(name, btree); } --- 289,297 ---- super.insert(key,new Entry(name,addr)); + // // touch the btree in the journal's object cache. + // journal.touch(addr, btree); + // add name -> btree mapping to the transient cache. ! indexCache.put(name, btree); } *************** *** 234,238 **** // remove the name -> btree mapping to the transient cache. ! name2BTree.remove(name); // remove the entry from the persistent index. --- 316,320 ---- // remove the name -> btree mapping to the transient cache. ! indexCache.remove(name); // remove the entry from the persistent index. Index: IAtomicStore.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/journal/IAtomicStore.java,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** IAtomicStore.java 8 Mar 2007 18:14:07 -0000 1.5 --- IAtomicStore.java 12 Mar 2007 18:06:11 -0000 1.6 *************** *** 133,138 **** * the basis for its operations. * ! * @param timestamp ! * Typically, the timestamp assigned to a transaction. * * @return The {@link ICommitRecord} for the most recent committed state --- 133,138 ---- * the basis for its operations. * ! * @param commitTime ! * Typically, the commit time assigned to a transaction. * * @return The {@link ICommitRecord} for the most recent committed state Index: Journal.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/journal/Journal.java,v retrieving revision 1.60 retrieving revision 1.61 diff -C2 -d -r1.60 -r1.61 *** Journal.java 11 Mar 2007 11:42:46 -0000 1.60 --- Journal.java 12 Mar 2007 18:06:11 -0000 1.61 *************** *** 62,71 **** --- 62,79 ---- import org.apache.log4j.Logger; + import com.bigdata.cache.LRUCache; + import com.bigdata.cache.WeakValueCache; + import com.bigdata.isolation.ReadOnlyIsolatedIndex; import com.bigdata.isolation.UnisolatedBTree; + import com.bigdata.journal.ReadCommittedTx.ReadCommittedIndex; import com.bigdata.objndx.BTree; import com.bigdata.objndx.IIndex; import com.bigdata.objndx.IndexSegment; + import com.bigdata.objndx.ReadOnlyIndex; import com.bigdata.rawstore.Addr; import com.bigdata.rawstore.Bytes; + import com.bigdata.rawstore.IRawStore; + import com.bigdata.scaleup.MasterJournal; + import com.bigdata.scaleup.SlaveJournal; import com.bigdata.scaleup.MasterJournal.Options; import com.bigdata.util.concurrent.DaemonThreadFactory; *************** *** 1127,1130 **** --- 1135,1140 ---- final public long getRootAddr(int index) { + assertOpen(); + if (_commitRecord == null) { *************** *** 1298,1301 **** --- 1308,1313 ---- public IIndex registerIndex(String name, IIndex btree) { + assertOpen(); + if (getIndex(name) != null) { *************** *** 1314,1317 **** --- 1326,1331 ---- public void dropIndex(String name) { + assertOpen(); + name2Addr.dropIndex(name); *************** *** 1327,1330 **** --- 1341,1346 ---- public IIndex getIndex(String name) { + assertOpen(); + if (name == null) throw new IllegalArgumentException(); *************** *** 1341,1370 **** * handling this. */ ! public ICommitRecord getCommitRecord(long comitTime) { ! ! return _commitRecordIndex.find(comitTime); } /** ! * Returns a read-only named index loaded from the given root block. Writes ! * on the index will NOT be made persistent and the index will NOT ! * participate in commits. */ ! public IIndex getIndex(String name, ICommitRecord commitRecord) { /* ! * Note: since this is always a request for historical read-only data, ! * this method MUST NOT register a committer and the returned btree MUST ! * NOT participate in the commit protocol. ! * ! * @todo cache these results in a weak value cache. */ ! return ((Name2Addr) BTree.load(this, commitRecord ! .getRootAddr(ROOT_NAME2ADDR))).get(name); } /* * ITransactionManager and friends. --- 1357,1522 ---- * handling this. */ ! public ICommitRecord getCommitRecord(long commitTime) { ! ! assertOpen(); ! ! return _commitRecordIndex.find(commitTime); } /** ! * Returns a read-only named index loaded from the given root block. This ! * method imposes a canonicalizing mapping and contracts that there will be ! * at most one instance of the historical index at a time. This contract is ! * used to facilitate buffer management. Writes on the index will NOT be ! * made persistent and the index will NOT participate in commits. ! * <p> ! * Note: since this is always a request for historical read-only data, this ! * method MUST NOT register a committer and the returned btree MUST NOT ! * participate in the commit protocol. ! * <p> ! * Note: The caller MUST take care not to permit writes since they could be ! * visible to other users of the same read-only index. This is typically ! * accomplished by wrapping the returned object in class that will throw an ! * exception for writes such as {@link ReadOnlyIndex}, ! * {@link ReadOnlyIsolatedIndex}, or {@link ReadCommittedIndex}. */ ! protected IIndex getIndex(String name, ICommitRecord commitRecord) { ! ! assertOpen(); ! ! if(name == null) throw new IllegalArgumentException(); + if(commitRecord == null) throw new IllegalArgumentException(); + /* ! * The address of an historical Name2Addr mapping used to resolve named ! * indices for the historical state associated with this commit record. */ + final long metaAddr = commitRecord.getRootAddr(ROOT_NAME2ADDR); ! /* ! * Resolve the address of the historical Name2Addr object using the ! * canonicalizing object cache. This prevents multiple historical ! * Name2Addr objects springing into existance for the same commit ! * record. ! */ ! Name2Addr name2Addr = (Name2Addr)getIndex(metaAddr); ! ! /* ! * The address at which the named index was written for that historical ! * state. ! */ ! final long indexAddr = name2Addr.getAddr(name); ! ! // No such index by name for that historical state. ! if(indexAddr==0L) return null; ! ! /* ! * Resolve the named index using the object cache to impose a ! * canonicalizing mapping on the historical named indices based on the ! * address on which it was written in the store. ! */ ! return getIndex(indexAddr); ! ! } ! ! /** ! * A cache that is used by the {@link Journal} to provide a canonicalizing ! * mapping from an {@link Addr address} to the instance of a read-only ! * historical object loaded from that {@link Addr address}. ! * <p> ! * Note: the "live" version of an object MUST NOT be placed into this cache ! * since its state will continue to evolve with additional writes while the ! * cache is intended to provide a canonicalizing mapping to only the ! * historical states of the object. This means that objects such as indices ! * and the {@link Name2Addr} index MUST NOT be inserted into the cache if ! * the are being read from the store for "live" use. For this reason ! * {@link Name2Addr} uses its own caching mechanisms. ! * ! * @todo discard cache on abort? that should not be necessary. even through ! * it can contain objects whose addresses were not made restart safe ! * those addresses should not be accessible to the application and ! * hence the objects should never be looked up and will be evicted in ! * due time from the cache. (this does rely on the fact that the store ! * never reuses an address.) ! * ! * FIXME This is the place to solve the resource (RAM) burden for indices is ! * Name2Addr. Currently, indices are never closed once opened which is a ! * resource leak. We need to close them out eventually based on LRU plus ! * timeout plus NOT IN USE. The way to approach this is a weak reference ! * cache combined with an LRU or hard reference queue that tracks reference ! * counters (just like the BTree hard reference cache for leaves). Eviction ! * events lead to closing an index iff the reference counter is zero. ! * Touches keep recently used indices from closing even though they may have ! * a zero reference count. ! * ! * @todo the {@link MasterJournal} needs to do similar things with ! * {@link IndexSegment}. ! * ! * @todo review the metadata index lookup in the {@link SlaveJournal}. This ! * is a somewhat different case since we only need to work with the ! * current metadata index as along as we make sure not to reclaim ! * resources (journals and index segments) until there are no more ! * transactions which can read from them. ! * ! * @todo support metering of index resources and timeout based shutdown of ! * indices. note that the "live" {@link Name2Addr} has its own cache ! * for the unisolated indices and that metering needs to pay attention ! * to the indices in that cache as well. Also, those indices can be ! * shutdown as long as they are not dirty (pending a commit). ! */ ! final private WeakValueCache<Long, ICommitter> objectCache = new WeakValueCache<Long, ICommitter>( ! new LRUCache<Long, ICommitter>(20)); ! ! /** ! * A canonicalizing mapping for index objects. ! * ! * @param addr ! * The {@link Addr address} of the index object. ! * ! * @return The index object. ! */ ! final protected IIndex getIndex(long addr) { ! ! synchronized (objectCache) { ! ! IIndex obj = (IIndex) objectCache.get(addr); + if (obj == null) { + + obj = BTree.load(this,addr); + + } + + objectCache.put(addr, (ICommitter)obj, false/*dirty*/); + + return obj; + + } + } + // /** + // * Insert or touch an object in the object cache. + // * + // * @param addr + // * The {@link Addr address} of the object in the store. + // * @param obj + // * The object. + // * + // * @see #getIndex(long), which provides a canonicalizing mapping for index + // * objects using the object cache. + // */ + // final protected void touch(long addr,Object obj) { + // + // synchronized(objectCache) { + // + // objectCache.put(addr, (ICommitter)obj, false/*dirty*/); + // + // } + // + // } + /* * ITransactionManager and friends. Index: TemporaryStore.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/journal/TemporaryStore.java,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** TemporaryStore.java 8 Mar 2007 18:14:06 -0000 1.7 --- TemporaryStore.java 12 Mar 2007 18:06:11 -0000 1.8 *************** *** 48,52 **** package com.bigdata.journal; - import com.bigdata.objndx.AbstractBTree; import com.bigdata.objndx.BTree; import com.bigdata.objndx.ByteArrayValueSerializer; --- 48,51 ---- Index: Tx.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/journal/Tx.java,v retrieving revision 1.35 retrieving revision 1.36 diff -C2 -d -r1.35 -r1.36 *** Tx.java 11 Mar 2007 11:42:44 -0000 1.35 --- Tx.java 12 Mar 2007 18:06:11 -0000 1.36 *************** *** 58,64 **** import com.bigdata.objndx.BTree; import com.bigdata.objndx.IIndex; - import com.bigdata.objndx.IndexSegment; import com.bigdata.rawstore.Bytes; - import com.bigdata.scaleup.MetadataIndex; import com.bigdata.scaleup.PartitionedIndexView; --- 58,62 ---- *************** *** 360,363 **** --- 358,362 ---- } else { + // writeable index backed by the temp. store. index = new IsolatedBTree(tmpStore,src); Index: ReadCommittedTx.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/journal/ReadCommittedTx.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** ReadCommittedTx.java 28 Feb 2007 13:59:09 -0000 1.1 --- ReadCommittedTx.java 12 Mar 2007 18:06:11 -0000 1.2 *************** *** 212,216 **** this.commitRecord = currentCommitRecord; ! // lookup the current index view against that commit record. this.index = (IIsolatableIndex) tx.journal.getIndex(name, commitRecord); --- 212,219 ---- this.commitRecord = currentCommitRecord; ! /* ! * Lookup the current committed index view against that commit ! * record. ! */ this.index = (IIsolatableIndex) tx.journal.getIndex(name, commitRecord); Index: CommitRecordIndex.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/journal/CommitRecordIndex.java,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** CommitRecordIndex.java 21 Feb 2007 20:17:21 -0000 1.2 --- CommitRecordIndex.java 12 Mar 2007 18:06:11 -0000 1.3 *************** *** 7,10 **** --- 7,12 ---- import org.CognitiveWeb.extser.LongPacker; + import com.bigdata.cache.LRUCache; + import com.bigdata.cache.WeakValueCache; import com.bigdata.objndx.BTree; import com.bigdata.objndx.BTreeMetadata; *************** *** 18,22 **** * integers. The values are {@link Entry} objects recording the commit time of * the index and the {@link Addr address} of the {@link ICommitRecord} for that ! * commit time. */ public class CommitRecordIndex extends BTree { --- 20,27 ---- * integers. The values are {@link Entry} objects recording the commit time of * the index and the {@link Addr address} of the {@link ICommitRecord} for that ! * commit time. A canonicalizing cache is maintained such that the caller will ! * never observe distinct concurrent instances of the same {@link ICommitRecord}. ! * This in turn facilitates canonicalizing caches for objects loaded from that ! * {@link ICommitRecord}. */ public class CommitRecordIndex extends BTree { *************** *** 26,38 **** */ private KeyBuilder keyBuilder = new KeyBuilder(); ! ! // /** ! // * Cache of added/retrieved commit records. ! // * ! // * @todo This only works for exact timestamp matches so the cache might not ! // * be very useful here. Also, this must be a weak value cache or it will ! // * leak memory. ! // */ ! // private Map<Long, ICommitRecord> cache = new HashMap<Long, ICommitRecord>(); public CommitRecordIndex(IRawStore store) { --- 31,50 ---- */ private KeyBuilder keyBuilder = new KeyBuilder(); ! ! /** ! * A weak value cache for {@link ICommitRecord}s. Note that lookup may be ! * by exact match -or- by the record have the largest timestamp LTE to the ! * given probe. For the latter, we have to determine the timestamp of the ! * matching record and use that to test the cache (after we have already ! * done the lookup in the index). ! * <p> ! * The main purpose of this cache is not to speed up access to historical ! * {@link ICommitRecord}s but rather to establish a canonicalizing lookup ! * service for {@link ICommitRecord}s so that we can in turn establish a ! * canonicalizing mapping for read-only objects (typically the unnamed ! * indices) loaded from a given {@link ICommitRecord}. ! */ ! final private WeakValueCache<Long, ICommitRecord> cache = new WeakValueCache<Long, ICommitRecord>( ! new LRUCache<Long, ICommitRecord>(10)); public CommitRecordIndex(IRawStore store) { *************** *** 74,83 **** /** ! * Existence test for a commit record with the specified commit timestamp. * * @param commitTime * The commit timestamp. * @return true iff such an {@link ICommitRecord} exists in the index with ! * that commit timestamp. */ synchronized public boolean hasTimestamp(long commitTime) { --- 86,97 ---- /** ! * Existence test for a commit record with the specified commit timestamp ! * (exact match). * * @param commitTime * The commit timestamp. + * * @return true iff such an {@link ICommitRecord} exists in the index with ! * that commit timestamp (exact match(. */ synchronized public boolean hasTimestamp(long commitTime) { *************** *** 89,94 **** /** * Return the {@link ICommitRecord} with the given timestamp (exact match). - * This method tests a cache of the named btrees and will return the same - * instance if the index is found in the cache. * * @param commitTime --- 103,106 ---- *************** *** 101,110 **** ICommitRecord commitRecord; ! // commitRecord = cache.get(commitTime); ! // ! // if (commitRecord != null) ! // return commitRecord; final Entry entry = (Entry) super.lookup(getKey(commitTime)); --- 113,124 ---- ICommitRecord commitRecord; + + // exact match cache test. + commitRecord = cache.get(commitTime); ! if (commitRecord != null) ! return commitRecord; + // exact match index lookup. final Entry entry = (Entry) super.lookup(getKey(commitTime)); *************** *** 120,129 **** commitRecord = loadCommitRecord(store,entry.addr); ! // /* ! // * save commit time -> commit record mapping in transient cache (this ! // * only works for for exact matches on the timestamp so the cache may ! // * not be very useful here). ! // */ ! // cache.put(commitRecord.getTimestamp(),commitRecord); // return btree. --- 134,141 ---- commitRecord = loadCommitRecord(store,entry.addr); ! /* ! * save commit time -> commit record mapping in transient cache. ! */ ! cache.put(commitRecord.getTimestamp(),commitRecord,false/*dirty*/); // return btree. *************** *** 134,138 **** /** * Return the {@link ICommitRecord} having the largest timestamp that is ! * strictly less than the given timestamp. * * @param timestamp --- 146,154 ---- /** * Return the {@link ICommitRecord} having the largest timestamp that is ! * less than or equal to the given timestamp. This is used primarily to ! * locate the commit record that will serve as the ground state for a ! * transaction having <i>timestamp</i> as its start time. In this context ! * the LTE search identifies the most recent commit state that is never the ! * less earlier than the start time of the transaction. * * @param timestamp *************** *** 140,144 **** * * @return The commit record -or- <code>null</code> iff there are no ! * {@link ICommitRecord}s in the that satisify the probe. * * @see #get(long) --- 156,160 ---- * * @return The commit record -or- <code>null</code> iff there are no ! * {@link ICommitRecord}s in the index that satisify the probe. * * @see #get(long) *************** *** 146,149 **** --- 162,166 ---- synchronized public ICommitRecord find(long timestamp) { + // find (first less than or equal to). final int index = findIndexOf(timestamp); *************** *** 156,164 **** } ! // return the matched record. ! Entry entry = (Entry) super.valueAt( index ); ! return loadCommitRecord(store,entry.addr); } --- 173,207 ---- } ! /* ! * Retrieve the entry for the commit record from the index. This ! * also stores the actual commit time for the commit record. ! */ Entry entry = (Entry) super.valueAt( index ); + + /* + * Test the cache for this commit record using its actual commit time. + */ + ICommitRecord commitRecord = cache.get(entry.commitTime); + + if(commitRecord == null) { + + /* + * Load the commit record from the store using the address stored in + * the entry. + */ ! commitRecord = loadCommitRecord(store,entry.addr); ! ! assert entry.commitTime == commitRecord.getTimestamp(); ! ! /* ! * Insert the commit record into the cache usings its actual commit ! * time. ! */ ! cache.put(entry.commitTime,commitRecord,false/* dirty */); ! ! } ! ! return commitRecord; } *************** *** 268,273 **** super.insert(key,new Entry(commitTime,commitRecordAddr)); ! // // add to the transient cache. ! // cache.put(commitTime, commitRecord); } --- 311,319 ---- super.insert(key,new Entry(commitTime,commitRecordAddr)); ! // should not be an existing entry for that commit time. ! assert cache.get(commitTime) == null; ! ! // add to the transient cache. ! cache.put(commitTime, commitRecord, false/*dirty*/); } |