From: Bryan T. <tho...@us...> - 2007-02-17 21:34:30
|
Update of /cvsroot/cweb/bigdata/src/java/com/bigdata/isolation In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv12401/src/java/com/bigdata/isolation Modified Files: IsolatedBTree.java IValue.java UnisolatedBTree.java Log Message: Working through transactional isolation. Index: UnisolatedBTree.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/isolation/UnisolatedBTree.java,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** UnisolatedBTree.java 15 Feb 2007 22:01:18 -0000 1.4 --- UnisolatedBTree.java 17 Feb 2007 21:34:21 -0000 1.5 *************** *** 112,117 **** public class UnisolatedBTree extends BTree implements IIsolatableIndex { protected final IConflictResolver conflictResolver; ! /** * The delegate that handles write-write conflict resolution during backward --- 112,128 ---- public class UnisolatedBTree extends BTree implements IIsolatableIndex { + /** + * The optional conflict resolver. + */ protected final IConflictResolver conflictResolver; ! ! /** ! * True iff this is an instanceof {@link IIsolatedIndex}. This effects ! * which value we use for the version counter in ! * {@link #insert(Object, Object)} when there is no pre-existing entry for a ! * key. ! */ ! final boolean isIsolated = this instanceof IsolatedBTree; ! /** * The delegate that handles write-write conflict resolution during backward *************** *** 137,140 **** --- 148,163 ---- * @param store * @param branchingFactor + */ + public UnisolatedBTree(IRawStore store, int branchingFactor) { + + this(store,branchingFactor, null); + + } + + /** + * Create an isolated btree. + * + * @param store + * @param branchingFactor * @param conflictResolver * An optional object that handles write-write conflict *************** *** 203,206 **** --- 226,245 ---- /** + * This method breaks isolatation to return the {@link Value} for a key. It + * is used by {@link IsolatedBTree#validate(UnisolatedBTree)} to test + * version counters when a key already exists in the global scope. + * + * @todo make protected and refactor tests so that we do not need public + * access to this method. there should be tests in this package that + * examine the specific version counters that are assigned such that + * we do not need to expose this method as public. + */ + final public Value getValue(byte[] key) { + + return (Value) super.lookup(key); + + } + + /** * True iff the key does not exist or if it exists but is marked as * {@link IValue#isDeleted()}. *************** *** 216,222 **** throw new IllegalArgumentException(); ! Value value = (Value)super.lookup(key); ! ! if(value==null||value.deleted) return false; return true; --- 255,262 ---- throw new IllegalArgumentException(); ! Value value = (Value) super.lookup(key); ! ! if (value == null || value.deleted) ! return false; return true; *************** *** 241,247 **** throw new IllegalArgumentException(); ! Value value = (Value)super.lookup(key); ! if(value==null||value.deleted) return null; return value.datum; --- 281,288 ---- throw new IllegalArgumentException(); ! Value value = (Value) super.lookup(key); ! if (value == null || value.deleted) ! return null; return value.datum; *************** *** 276,283 **** /** ! * If the key does not exists or if the key exists, then insert/update an ! * entry under that key with a new version counter. Otherwise, update the ! * entry under that key in order to increment the version counter (this ! * includes the case where the key is paired with a deletion marker). * * @param key --- 317,325 ---- /** ! * If the key does not exists or if the key exists but the entry is marked ! * as deleted, then insert/update an entry under that key with a new version ! * counter. Otherwise, update the entry under that key in order to increment ! * the version counter (this includes the case where the key is paired with ! * a deletion marker). * * @param key *************** *** 298,303 **** if (value == null) { ! super.insert(key, new Value(IValue.FIRST_VERSION_UNISOLATED, false, ! (byte[]) val)); return null; --- 340,351 ---- if (value == null) { ! /* ! * No entry exists for that key (not even a deleted entry). ! */ ! ! short versionCounter = isIsolated ? IValue.FIRST_VERSION_ISOLATED ! : IValue.FIRST_VERSION_UNISOLATED; ! ! super.insert(key, new Value(versionCounter, false, (byte[]) val)); return null; *************** *** 305,308 **** --- 353,362 ---- } + /* + * An entry exists for that key (the entry may be marked as deleted, but + * that does not effect the behavior of insert). We assign the next + * version counter to the entry, clear the deleted flag, and set the new + * value on the entry. + */ super.insert(key, new Value(value.nextVersionCounter(), false, (byte[]) val)); Index: IValue.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/isolation/IValue.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** IValue.java 13 Feb 2007 23:01:02 -0000 1.1 --- IValue.java 17 Feb 2007 21:34:21 -0000 1.2 *************** *** 50,55 **** * and version counters. * <p> ! * Deletion markers are required by both transactions (so that the entry may be ! * removed from the unisolated tree when the transaction commits) and * partitioned indices (so that a key deleted in an unisolated index may be * removed during a compacting merge with existing index segments). --- 50,55 ---- * and version counters. * <p> ! * Deletion markers are required both by transactions (so that the entry may be ! * removed from the unisolated tree when the transaction commits) and by * partitioned indices (so that a key deleted in an unisolated index may be * removed during a compacting merge with existing index segments). *************** *** 59,72 **** * tree. When a transaction isolates an index it does so by creating a fused * view that reads from a historical committed state of the corresponding ! * unisolated index and writes on an isolated index. When a value is written on ! * in the isolated index, the version counter from the unisolated index is ! * copied into the isolated index. When the transaction commits, it validates ! * the writes by testing the version counter in the then current unisolated ! * index. If the version counter for an entry in the isolated index does not ! * agree with the version counter on the unisolated index then an intervening ! * commit has already overwritten that entry and a write-write conflict exists. ! * Either the write-write conflict can be resolved or the transaction must ! * abort. In the special case where there are no intervening commits since the ! * transaction began validation is unecessary and should be skipped. * <p> * A delete is handled as a write that sets a "deleted" flag. Eventually the --- 59,73 ---- * tree. When a transaction isolates an index it does so by creating a fused * view that reads from a historical committed state of the corresponding ! * unisolated index and writes on an isolated index. The first time a value is ! * written on the isolated index for which there is a pre-existing value in the ! * unisolated index, the version counter from the unisolated index is copied ! * into the isolated index. When the transaction commits, it validates writes by ! * testing the version counter in the <em>then current</em> unisolated index. ! * If the version counter for an entry in the isolated index does not agree with ! * the version counter on the unisolated index then an intervening commit has ! * already overwritten that entry and a write-write conflict exists. Either the ! * write-write conflict can be resolved or the transaction must abort. In the ! * special case where there are no intervening commits since the transaction ! * began validation is unecessary and should be skipped. * <p> * A delete is handled as a write that sets a "deleted" flag. Eventually the *************** *** 90,93 **** --- 91,118 ---- * The value of the version counter that is used the first time a data * version is written for a key in an unisolated index: ONE (1). + * <p> + * Note: The first version counter written on the unisolated index (1) is + * larger than the {@link #FIRST_VERSION_ISOLATED first version counter} + * written on an isolated index (0). The reason is that this approach + * essentially presumes a version counter of zero (0) if a key does not + * exist in the unisolated index, which is then copied into the isolated + * index as a zero(0) version counter. + * <p> + * If the transaction validates and the isolated write is copied onto the + * unisolated index then the version counter is handled in one of the + * following ways. + * <ol> + * <li> If there is still no key for the entry, then the + * {@link #FIRST_VERSION_UNISOLATED} version counter (1) is used and we have + * effectively incremented from a zero (0) version counter for a + * non-existing key to an one (1) version counter on the first write.</li> + * <li> If another transaction has committed, then the version counter in + * the global scope will now be GTE one (1). This will cause a write-write + * conflict to be detected during validation. If the write-write conflict is + * resolved, then the copy down onto the global scope will assign the next + * version counter, e.g., the new version counter will be two (2) (if there + * was only one intervening commit) or greater (if there was more than one + * intervening commit).</li> + * </ol> */ public static short FIRST_VERSION_UNISOLATED = (short) 1; Index: IsolatedBTree.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/java/com/bigdata/isolation/IsolatedBTree.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** IsolatedBTree.java 15 Feb 2007 22:01:18 -0000 1.3 --- IsolatedBTree.java 17 Feb 2007 21:34:21 -0000 1.4 *************** *** 135,147 **** * Typically, it is the unisolated btree from the last committed * state on the {@link Journal} before the {@link Tx} starts. - * - * FIXME The isolated btree needs to start from the committed stable state - * of another btree (a possible exception is the first transaction to create - * a given btree). In order to verify that the source btree meets those - * requirements we need to know that it was loaded from a historical - * metadata record, e.g., as found in a root block or a read-only root names - * index found in a root block. Merely having a persistent root is NOT - * enough since just writing the tree onto the store does not make it - * restart safe. The {@link Tx} class needs to handle this. */ public IsolatedBTree(IRawStore store, UnisolatedBTree src) { --- 135,138 ---- *************** *** 170,173 **** --- 161,169 ---- * @param metadata * @param src + * + * @todo This constructor is somewhat different since it requires access to + * a persistence capable parameter in order to reconstruct the view. + * Consider whether or not this can be refactored per + * {@link BTreeMetadata#load(IRawStore, long)}. */ public IsolatedBTree(IRawStore store, BTreeMetadata metadata, UnisolatedBTree src) { *************** *** 254,261 **** * write through to the isolated index). */ ! public Object insert(Object key,Object value) { ! ! return super.insert(key,value); ! } --- 250,255 ---- * write through to the isolated index). */ ! public Object insert(Object key, Object val) { ! return super.insert(key,val); } *************** *** 405,413 **** * scanning both indices in order. * ! * Note: we must use the implementation of this method on the super ! * class in order to visit the IValue objects and see both deleted and ! * undeleted entries. */ ! final IEntryIterator itr = super.entryIterator(); while (itr.hasNext()) { --- 399,406 ---- * scanning both indices in order. * ! * Note: the iterator is chosen carefully in order to visit the IValue ! * objects and see both deleted and undeleted entries. */ ! final IEntryIterator itr = root.rangeIterator(null, null, null); while (itr.hasNext()) { *************** *** 420,424 **** // Lookup the entry in the global scope. ! Value baseEntry = (Value) globalScope.lookup(key); /* --- 413,417 ---- // Lookup the entry in the global scope. ! Value baseEntry = (Value) globalScope.getValue(key); /* *************** *** 488,492 **** } ! if(tmp!=null) { /* --- 481,485 ---- } ! if (tmp != null) { /* *************** *** 526,534 **** /* ! * Note: we must use the implementation of this method on the super ! * class in order to visit the IValue objects and see both deleted ! * and undeleted entries. */ ! final IEntryIterator itr = super.entryIterator(); while (itr.hasNext()) { --- 519,526 ---- /* ! * Note: the iterator is chosen carefully in order to visit the IValue ! * objects and see both deleted and undeleted entries. */ ! final IEntryIterator itr = root.rangeIterator(null, null, null); while (itr.hasNext()) { *************** *** 538,542 **** // The corresponding key. ! final byte[] id = (byte[]) itr.getKey(); if (entry.deleted) { --- 530,534 ---- // The corresponding key. ! final byte[] key = (byte[]) itr.getKey(); if (entry.deleted) { *************** *** 549,559 **** */ ! if (globalScope.contains(id)) { /* * Mark the entry in the unisolated index as deleted. */ ! globalScope.insert(id, new Value( ! entry.nextVersionCounter(), true, null)); } else { --- 541,552 ---- */ ! if (globalScope.contains(key)) { /* * Mark the entry in the unisolated index as deleted. */ ! // globalScope.insert(key, new Value( ! // entry.nextVersionCounter(), true, null)); ! globalScope.remove(key); } else { *************** *** 571,576 **** * Copy the entry down onto the global scope. */ ! globalScope.insert(id, new Value(entry.nextVersionCounter(), ! false, entry.datum)); } --- 564,570 ---- * Copy the entry down onto the global scope. */ ! // globalScope.insert(key, new Value(entry.nextVersionCounter(), ! // false, entry.datum)); ! globalScope.insert(key,entry.datum); } |