From: <tho...@us...> - 2014-09-11 19:56:47
|
Revision: 8649 http://sourceforge.net/p/bigdata/code/8649 Author: thompsonbry Date: 2014-09-11 19:56:32 +0000 (Thu, 11 Sep 2014) Log Message: ----------- Merge in change set from the main development branch. Also, reduced log@WARN => log@INFO in CreateKBTask. @see #714 (openrdf 2.7) Modified Paths: -------------- branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/AbstractBTree.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/AbstractNode.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/BTree.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/DefaultEvictionListener.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/ICheckpointProtocol.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/UnisolatedReadWriteIndex.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/htree/AbstractHTree.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/htree/DefaultEvictionListener.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/htree/HTree.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/journal/AbstractCommitTimeIndex.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/journal/ICommitter.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/service/EventReceiver.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/service/LoadBalancerService.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/stream/Stream.java branches/SESAME_2_7/bigdata-blueprints/src/java/com/bigdata/blueprints/BigdataGraph.java branches/SESAME_2_7/bigdata-blueprints/src/java/com/bigdata/blueprints/BigdataGraphBulkLoad.java branches/SESAME_2_7/bigdata-blueprints/src/java/com/bigdata/blueprints/BigdataQueryProjection.java branches/SESAME_2_7/bigdata-sails/src/java/com/bigdata/rdf/sail/CreateKBTask.java branches/SESAME_2_7/bigdata-sails/src/test/com/bigdata/rdf/sail/tck/BigdataArbitraryLengthPathTest.java branches/SESAME_2_7/bigdata-sails/src/test/com/bigdata/rdf/sail/tck/BigdataSparqlTest.java Added Paths: ----------- branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/EvictionError.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/IReadWriteLockManager.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/IndexInconsistentError.java branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/ReadWriteLockManager.java branches/SESAME_2_7/bigdata-blueprints/src/java/com/bigdata/blueprints/PartialEdge.java branches/SESAME_2_7/bigdata-blueprints/src/java/com/bigdata/blueprints/PartialElement.java branches/SESAME_2_7/bigdata-blueprints/src/java/com/bigdata/blueprints/PartialVertex.java Property Changed: ---------------- branches/SESAME_2_7/ Index: branches/SESAME_2_7 =================================================================== --- branches/SESAME_2_7 2014-09-11 19:26:33 UTC (rev 8648) +++ branches/SESAME_2_7 2014-09-11 19:56:32 UTC (rev 8649) Property changes on: branches/SESAME_2_7 ___________________________________________________________________ Modified: svn:mergeinfo ## -1,6 +1,7 ## /branches/BIGDATA_MGC_HA1_HA5:8025-8122 /branches/BIGDATA_OPENRDF_2_6_9_UPDATE:6769-6785 /branches/BIGDATA_RELEASE_1_2_0:6766-7380 +/branches/BIGDATA_RELEASE_1_3_0:8636-8648 /branches/BTREE_BUFFER_BRANCH:2004-2045 /branches/DEV_BRANCH_27_OCT_2009:2270-2546,2548-2782 /branches/INT64_BRANCH:4486-4522 \ No newline at end of property Modified: branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/AbstractBTree.java =================================================================== --- branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/AbstractBTree.java 2014-09-11 19:26:33 UTC (rev 8648) +++ branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/AbstractBTree.java 2014-09-11 19:56:32 UTC (rev 8649) @@ -24,6 +24,7 @@ /* * Created on Dec 19, 2006 * + * RESYNC */ package com.bigdata.btree; @@ -40,6 +41,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.FutureTask; +import java.util.concurrent.locks.Lock; import org.apache.log4j.Level; import org.apache.log4j.Logger; @@ -133,7 +135,6 @@ * </p> * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> - * @version $Id$ * * @see KeyBuilder */ @@ -168,6 +169,15 @@ final protected static String ERROR_TRANSIENT = "Transient"; /** + * An unisolated index view is in an error state. It must be discarded and + * reloaded from the current checkpoint record. + * + * @see <a href="http://trac.bigdata.com/ticket/1005"> Invalidate BTree + * objects if error occurs during eviction </a> + */ + final protected static String ERROR_ERROR_STATE = "Index is in error state"; + + /** * Log for btree opeations. */ protected static final Logger log = Logger.getLogger(AbstractBTree.class); @@ -250,7 +260,7 @@ * mutation. */ final protected boolean readOnly; - + /** * Optional cache for {@link INodeData} and {@link ILeafData} instances and * always <code>null</code> if the B+Tree is transient. @@ -258,6 +268,14 @@ protected final ILRUCache<Long, Object> storeCache; /** + * Hard reference iff the index is mutable (aka unisolated) allows us to + * avoid patterns that create short life time versions of the object to + * protect {@link ICheckpointProtocol#writeCheckpoint2()} and similar + * operations. + */ + private final IReadWriteLockManager lockManager; + + /** * The branching factor for the btree. */ final protected int branchingFactor; @@ -547,6 +565,21 @@ protected volatile AbstractNode<?> root; /** + * This field is set if an error is encountered that renders an unisolated + * index object unusable. For example, this can occur if an error was + * detected during incremental eviction of dirty nodes for a mutable index + * view since that means that there are partly serialized (and possibly + * inconsistenly serialized) evicted pages. Once this becomes non- + * <code>null</code> the index MUST be reloaded from the most recent + * checkpoint before it can be used (that is, you need to obtain a new view + * of the unisolated index since this field is sticky once set). + * + * @see <a href="http://trac.bigdata.com/ticket/1005"> Invalidate BTree + * objects if error occurs during eviction </a> + */ + protected volatile Throwable error; + + /** * An optional bloom filter that will be used to filter point tests against * <i>this</i> {@link AbstractBTree}. A bloom filter provides a strong * guarantee when it reports that a key was not found, but only a weak @@ -960,7 +993,7 @@ this.store = store; this.readOnly = readOnly; - + // /* // * The Memoizer is not used by the mutable B+Tree since it is not safe // * for concurrent operations. @@ -1042,6 +1075,8 @@ } + lockManager = ReadWriteLockManager.getLockManager(this); + } /** @@ -1977,7 +2012,8 @@ } }; - + + @Override final public Object insert(Object key, Object value) { key = metadata.getTupleSerializer().serializeKey(key); @@ -1999,6 +2035,7 @@ } + @Override final public byte[] insert(final byte[] key, final byte[] value) { if (key == null) @@ -2120,6 +2157,7 @@ } + @Override final public Object remove(Object key) { key = metadata.getTupleSerializer().serializeKey(key); @@ -2147,6 +2185,7 @@ * Remove the tuple under that key (will write a delete marker if delete * markers are enabled). */ + @Override final public byte[] remove(final byte[] key) { final Tuple tuple; @@ -2232,8 +2271,10 @@ * and dropping indices vs removing the entries in an individual * {@link AbstractBTree}. */ + @Override abstract public void removeAll(); + @Override public Object lookup(Object key) { key = metadata.getTupleSerializer().serializeKey(key); @@ -2252,6 +2293,7 @@ } + @Override public byte[] lookup(final byte[] key) { final Tuple tuple = lookup(key, getLookupTuple()); @@ -2339,6 +2381,7 @@ } + @Override public boolean contains(Object key) { key = metadata.getTupleSerializer().serializeKey(key); @@ -2359,6 +2402,7 @@ * * @todo add unit test to btree suite w/ and w/o delete markers. */ + @Override public boolean contains(final byte[] key) { if (key == null) @@ -2405,6 +2449,7 @@ } + @Override public long indexOf(final byte[] key) { if (key == null) @@ -2419,6 +2464,7 @@ } + @Override public byte[] keyAt(final long index) { if (index < 0) @@ -2433,6 +2479,7 @@ } + @Override public byte[] valueAt(final long index) { final Tuple tuple = getLookupTuple(); @@ -2466,6 +2513,7 @@ * IRangeQuery */ + @Override final public long rangeCountExact(final byte[] fromKey, final byte[] toKey) { if (!metadata.getDeleteMarkers()) { @@ -2509,6 +2557,7 @@ } + @Override final public long rangeCount() { return rangeCount(null, null); @@ -2546,6 +2595,7 @@ * lookup of the both keys. If both keys are <code>null</code>, then the * cost is zero (no IOs). */ + @Override final public long rangeCount(final byte[] fromKey, final byte[] toKey) { if (fromKey == null && toKey == null) { @@ -2604,6 +2654,7 @@ * considering all sources at once. It uses a range iterator scan visiting * both deleted and undeleted tuples for that. */ + @Override public long rangeCountExactWithDeleted(final byte[] fromKey, final byte[] toKey) { @@ -2649,6 +2700,7 @@ } + @Override final public ITupleIterator rangeIterator() { return rangeIterator(null, null); @@ -2675,6 +2727,7 @@ } + @Override final public ITupleIterator rangeIterator(byte[] fromKey, byte[] toKey) { return rangeIterator(fromKey, toKey, 0/* capacity */, @@ -2767,6 +2820,7 @@ * @todo add support to the iterator construct for filtering by a tuple * revision timestamp range. */ + @Override public ITupleIterator rangeIterator(// final byte[] fromKey,// final byte[] toKey,// @@ -3115,6 +3169,7 @@ } + @Override public Object submit(final byte[] key, final ISimpleIndexProcedure proc) { // conditional range check on the key. @@ -3126,6 +3181,7 @@ } @SuppressWarnings("unchecked") + @Override public void submit(final byte[] fromKey, final byte[] toKey, final IKeyRangeIndexProcedure proc, final IResultHandler handler) { @@ -3147,6 +3203,7 @@ } @SuppressWarnings("unchecked") + @Override public void submit(final int fromIndex, final int toIndex, final byte[][] keys, final byte[][] vals, final AbstractKeyArrayIndexProcedureConstructor ctor, @@ -3369,8 +3426,68 @@ } - doSyncTouch(node); + /** + * At this point we know that the B+Tree object is a mutable data + * structure (!readOnly). If we can prove that the current thread is + * conducting a read-only operation on the B+Tree, then we DO NOT touch + * the node in order to prevent having read-only operations drive + * evictions. This test relies on the UnisolatedReadWriteIndex class to + * provide concurrency control for such interleaved read-only and + * mutation operations on an unisolated (aka mutable) index. + * + * There are three broad ways in which concurrency controls for the + * index classes are realized: + * + * (1) Explicit synchronization. For example, the AbstractJournal uses + * explicit synchronization to protect operations on the unisolated + * Name2Addr. + * + * (2) Explicit pre-declaration of ordered locks. The ConcurrencyManager + * and AbstractTask support this protection mechanism. The task runs + * once it has acquired the locks for the declared unisolated indices. + * + * (3) UnisolatedReadWriteIndex. This is used to provide transparent + * concurrency control for unisolated indices for the triple and quad + * store classes. + * + * The index is mutable (unisolated view). If the thread owns a + * read-only lock then the operation is read-only and we MUST NOT drive + * evictions from this thread. + * + * Note: The order in which we obtain the real read lock and increment + * (and decrement) the per-thread read lock counter on the AbstractBTree + * is not critical because AbstractBTree.touch() relies on the thread + * both owning the read lock and having the per-thread read lock counter + * incremented for that thread. + * + * @see <a href="http://trac.bigdata.com/ticket/855"> AssertionError: + * Child does not have persistent identity </a> + */ + final int rcount = lockManager.getReadLockCount(); + + if (rcount > 0) { + + /* + * The current thread is executing a read-only operation against the + * mutable index view. DO NOT TOUCH THE EVICTION QUEUE. + */ + + // NOP + + } else { + /* + * The current thread has not promised that it is using a read-only + * operation. Either the operation is a mutation or the index is + * being managed by one of the other two concurrency control + * patterns. In any of these cases, we touch the write retention + * queue for this node reference. + */ + + doSyncTouch(node); + + } + } /** @@ -3433,7 +3550,7 @@ */ // assert isReadOnly() || ndistinctOnWriteRetentionQueue > 0; - + node.referenceCount++; if (!writeRetentionQueue.add(node)) { @@ -3598,6 +3715,15 @@ } +// private void badNode(final AbstractNode<?> node) { +//// try { +//// Thread.sleep(50); +//// } catch (InterruptedException e) { +//// // ignore; +//// } +// throw new AssertionError("ReadOnly and identity: " + node.identity); +// } + /** * Codes the node and writes the coded record on the store (non-recursive). * The node MUST be dirty. If the node has a parent, then the parent is @@ -3617,7 +3743,10 @@ * @return The persistent identity assigned by the store. */ protected long writeNodeOrLeaf(final AbstractNode<?> node) { - + + if (error != null) + throw new IllegalStateException(ERROR_ERROR_STATE, error); + assert root != null; // i.e., isOpen(). assert node != null; assert node.btree == this; @@ -3641,6 +3770,9 @@ * TestMROWTransactions might also demonstrate an issue * occasionally. If so, then check for the same root cause. */ +// if (node.isReadOnly()) { +// badNode(node); // supports debugging +// } assert !node.isReadOnly(); assertNotReadOnly(); @@ -3741,6 +3873,14 @@ // No longer dirty (prevents re-coding on re-eviction). node.setDirty(false); +// if (node.writing == null) { +// log.warn("Concurrent modification of thread guard", new RuntimeException("WTF2: " + node.hashCode())); +// +// throw new AssertionError("Concurrent modification of thread guard"); +// } + +// node.writing = null; + return 0L; } @@ -3768,7 +3908,7 @@ btreeCounters.bytesWritten += nbytes; - btreeCounters.bytesOnStore_nodesAndLeaves.addAndGet(nbytes); + btreeCounters.bytesOnStore_nodesAndLeaves.addAndGet(nbytes); } @@ -3830,6 +3970,14 @@ } +// if (node.writing == null) { +// log.warn("Concurrent modification of thread guard", new RuntimeException("WTF2: " + node.hashCode())); +// +// throw new AssertionError("Concurrent modification of thread guard"); +// } +// +// node.writing = null; + return addr; } @@ -3856,40 +4004,6 @@ if (addr == IRawStore.NULL) throw new IllegalArgumentException(); -// final Long addr2 = Long.valueOf(addr); -// -// if (storeCache != null) { -// -// // test cache : will touch global LRU iff found. -// final IAbstractNodeData data = (IAbstractNodeData) storeCache -// .get(addr); -// -// if (data != null) { -// -// // Node and Leaf MUST NOT make it into the global LRU or store -// // cache! -// assert !(data instanceof AbstractNode<?>); -// -// final AbstractNode<?> node; -// -// if (data.isLeaf()) { -// -// node = nodeSer.nodeFactory.allocLeaf(this, addr, -// (ILeafData) data); -// -// } else { -// -// node = nodeSer.nodeFactory.allocNode(this, addr, -// (INodeData) data); -// -// } -// -// // cache hit. -// return node; -// -// } -// -// } final ByteBuffer tmp; { @@ -3946,21 +4060,6 @@ } -// if (storeCache != null) { -// -// // update cache : will touch global LRU iff cache is modified. -// final IAbstractNodeData data2 = (IAbstractNodeData) storeCache -// .putIfAbsent(addr2, data); -// -// if (data2 != null) { -// -// // concurrent insert, use winner's value. -// data = data2; -// -// } -// -// } - // wrap as Node or Leaf. final AbstractNode<?> node = nodeSer.wrap(this, addr, data); @@ -4061,6 +4160,7 @@ /** * Returns the hard reference. */ + @Override public T get() { return ref; @@ -4070,6 +4170,7 @@ /** * Overridden as a NOP. */ + @Override public void clear() { // NOP @@ -4163,7 +4264,7 @@ */ int getMaxRecLen() { - return metadata.getMaxRecLen(); + return metadata.getMaxRecLen(); } @@ -4304,4 +4405,24 @@ } + @Override + final public Lock readLock() { + + return lockManager.readLock(); + + } + + @Override + final public Lock writeLock() { + + return lockManager.writeLock(); + + } + + @Override + final public int getReadLockCount() { + + return lockManager.getReadLockCount(); + } + } Modified: branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/AbstractNode.java =================================================================== --- branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/AbstractNode.java 2014-09-11 19:26:33 UTC (rev 8648) +++ branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/AbstractNode.java 2014-09-11 19:56:32 UTC (rev 8649) @@ -23,7 +23,6 @@ */ /* * Created on Nov 15, 2006 - * */ package com.bigdata.btree; @@ -37,7 +36,6 @@ import com.bigdata.btree.data.IAbstractNodeData; import com.bigdata.btree.data.IKeysData; -import com.bigdata.btree.data.ISpannedTupleCountData; import com.bigdata.btree.filter.EmptyTupleIterator; import com.bigdata.btree.raba.IRaba; import com.bigdata.btree.raba.MutableKeyBuffer; @@ -51,7 +49,6 @@ * Abstract node supporting incremental persistence and copy-on-write semantics. * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> - * @version $Id$ */ public abstract class AbstractNode<T extends AbstractNode /* @@ -539,7 +536,7 @@ parent = (Node) parent.copyOnWrite(oldId); } - + /* * Replace the reference to this child with the reference to the * new child. This makes the old child inaccessible via Modified: branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/BTree.java =================================================================== --- branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/BTree.java 2014-09-11 19:26:33 UTC (rev 8648) +++ branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/BTree.java 2014-09-11 19:56:32 UTC (rev 8649) @@ -23,7 +23,6 @@ */ /* * Created on Nov 15, 2006 - * */ package com.bigdata.btree; @@ -288,7 +287,7 @@ * and otherwise <code>null</code>. */ private final ByteArrayBuffer recordAddrBuf; - + // /** // * The last address from which the {@link IndexMetadata} record was read or // * on which it was written. @@ -385,7 +384,7 @@ */ recordAddrBuf = readOnly ? null : new ByteArrayBuffer(Bytes.SIZEOF_LONG); - + } /** @@ -900,23 +899,31 @@ * @see https://sourceforge.net/apps/trac/bigdata/ticket/343 * @see https://sourceforge.net/apps/trac/bigdata/ticket/440 */ -// final Lock lock = new UnisolatedReadWriteIndex(this).writeLock(); - final Lock lock = UnisolatedReadWriteIndex.getReadWriteLock(this).writeLock(); - lock.lock(); - try { + final Lock lock = writeLock(); + lock.lock(); + try { + /** + * Do not permit checkpoint if the index is in an error state. + * + * @see <a href="http://trac.bigdata.com/ticket/1005"> Invalidate + * BTree objects if error occurs during eviction </a> + */ + if (error != null) + throw new IllegalStateException(ERROR_ERROR_STATE, error); + //synchronized(this) { + if (/* autoCommit && */needsCheckpoint()) { + + /* + * Flush the btree, write a checkpoint record, and return the + * address of that checkpoint record. The [checkpoint] reference + * is also updated. + */ + + return _writeCheckpoint2(); + + } + //} - if (/* autoCommit && */needsCheckpoint()) { - - /* - * Flush the btree, write a checkpoint record, and return the - * address of that checkpoint record. The [checkpoint] reference - * is also updated. - */ - - return _writeCheckpoint2(); - - } - /* * There have not been any writes on this btree or auto-commit is * disabled. @@ -1110,14 +1117,14 @@ @Override final public long getRecordVersion() { - return recordVersion; + return recordVersion; } @Override final public long getMetadataAddr() { - return metadata.getMetadataAddr(); + return metadata.getMetadataAddr(); } @@ -1313,7 +1320,7 @@ @Override public long handleCommit(final long commitTime) { - return writeCheckpoint2().getCheckpointAddr(); + return writeCheckpoint2().getCheckpointAddr(); } Modified: branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/DefaultEvictionListener.java =================================================================== --- branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/DefaultEvictionListener.java 2014-09-11 19:26:33 UTC (rev 8648) +++ branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/DefaultEvictionListener.java 2014-09-11 19:56:32 UTC (rev 8649) @@ -23,7 +23,6 @@ */ /* * Created on Nov 17, 2006 - * */ package com.bigdata.btree; @@ -61,88 +60,132 @@ } final AbstractBTree btree = node.btree; + + if (btree.error != null) { + /** + * This occurs if an error was detected against a mutable view of + * the index (the unisolated index view) and the caller has not + * discarded the index and caused it to be reloaded from the most + * recent checkpoint. + * + * @see <a href="http://trac.bigdata.com/ticket/1005"> Invalidate + * BTree objects if error occurs during eviction </a> + */ + throw new IllegalStateException(AbstractBTree.ERROR_ERROR_STATE, + btree.error); + } + + try { - // Note: This assert can be violated for a read-only B+Tree since there - // is less synchronization. - assert btree.isReadOnly() || btree.ndistinctOnWriteRetentionQueue > 0; + // Note: This assert can be violated for a read-only B+Tree since + // there is less synchronization. + assert btree.isReadOnly() || btree.ndistinctOnWriteRetentionQueue > 0; - btree.ndistinctOnWriteRetentionQueue--; - - if (node.deleted) { + btree.ndistinctOnWriteRetentionQueue--; - /* - * Deleted nodes are ignored as they are evicted from the queue. - */ + if (node.deleted) { - return; + /* + * Deleted nodes are ignored as they are evicted from the queue. + */ - } + return; - // this does not permit transient nodes to be coded. - if (node.dirty && btree.store != null) { -// // this causes transient nodes to be coded on eviction. -// if (node.dirty) { - - if (node.isLeaf()) { + } - /* - * A leaf is written out directly. - */ - - btree.writeNodeOrLeaf(node); + // this does not permit transient nodes to be coded. + if (node.dirty && btree.store != null) { + // // this causes transient nodes to be coded on eviction. + // if (node.dirty) { - } else { + if (node.isLeaf()) { - /* - * A non-leaf node must be written out using a post-order - * traversal so that all dirty children are written through - * before the dirty parent. This is required in order to - * assign persistent identifiers to the dirty children. - */ + /* + * A leaf is written out directly. + */ - btree.writeNodeRecursive(node); + btree.writeNodeOrLeaf(node); - } + } else { - // is a coded data record. - assert node.isCoded(); - - // no longer dirty. - assert !node.dirty; - - if (btree.store != null) { - - // object is persistent (has assigned addr). - assert ref.identity != PO.NULL; - - } - - } // isDirty + /* + * A non-leaf node must be written out using a post-order + * traversal so that all dirty children are written through + * before the dirty parent. This is required in order to + * assign persistent identifiers to the dirty children. + */ - // This does not insert into the cache. That is handled by writeNodeOrLeaf. -// if (btree.globalLRU != null) { + btree.writeNodeRecursive(node); + + } + + // is a coded data record. + assert node.isCoded(); + + // no longer dirty. + assert !node.dirty; + + if (btree.store != null) { + + // object is persistent (has assigned addr). + assert ref.identity != PO.NULL; + + } + + } // isDirty + + // This does not insert into the cache. That is handled by writeNodeOrLeaf. +// if (btree.globalLRU != null) { // -// /* -// * Add the INodeData or ILeafData object to the global LRU, NOT the -// * Node or Leaf. -// * -// * Note: The global LRU touch only occurs on eviction from the write -// * retention queue. This is nice because it limits the touches on -// * the global LRU, which could otherwise be a hot spot. We do a -// * touch whether or not the node was persisted since we are likely -// * to return to the node in either case. -// */ +// /* +// * Add the INodeData or ILeafData object to the global LRU, NOT the +// * Node or Leaf. +// * +// * Note: The global LRU touch only occurs on eviction from the write +// * retention queue. This is nice because it limits the touches on +// * the global LRU, which could otherwise be a hot spot. We do a +// * touch whether or not the node was persisted since we are likely +// * to return to the node in either case. +// */ // -// final IAbstractNodeData delegate = node.getDelegate(); +// final IAbstractNodeData delegate = node.getDelegate(); // -// assert delegate != null : node.toString(); +// assert delegate != null : node.toString(); // -// assert delegate.isCoded() : node.toString(); +// assert delegate.isCoded() : node.toString(); // -// btree.globalLRU.add(delegate); +// btree.globalLRU.add(delegate); // -// } +// } + } catch (Throwable e) { + + if (!btree.readOnly) { + + /** + * If the btree is mutable and an eviction fails, then the index + * MUST be discarded. + * + * @see <a href="http://trac.bigdata.com/ticket/1005"> + * Invalidate BTree objects if error occurs during eviction + * </a> + */ + + btree.error = e; + + // Throw as Error. + throw new EvictionError(e); + + } + + // Launder the throwable. + if (e instanceof RuntimeException) + throw (RuntimeException) e; + + throw new RuntimeException(e); + + } + } } Copied: branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/EvictionError.java (from rev 8648, branches/BIGDATA_RELEASE_1_3_0/bigdata/src/java/com/bigdata/btree/EvictionError.java) =================================================================== --- branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/EvictionError.java (rev 0) +++ branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/EvictionError.java 2014-09-11 19:56:32 UTC (rev 8649) @@ -0,0 +1,66 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2007. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* + * Created on Sep 2, 2014 + */ +package com.bigdata.btree; + +/** + * Error marks an mutable index as in an inconsistent state arising from an + * exception during eviction of a dirty node or leaf from a mutable index. The + * index MUST be reloaded from the current checkpoint record. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * + * @see <a href="http://trac.bigdata.com/ticket/1005"> Invalidate BTree objects + * if error occurs during eviction </a> + */ +public class EvictionError extends IndexInconsistentError { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public EvictionError() { + } + + public EvictionError(String message) { + super(message); + } + + public EvictionError(Throwable cause) { + super(cause); + } + + public EvictionError(String message, Throwable cause) { + super(message, cause); + } + + public EvictionError(String message, Throwable cause, + boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} Modified: branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/ICheckpointProtocol.java =================================================================== --- branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/ICheckpointProtocol.java 2014-09-11 19:26:33 UTC (rev 8648) +++ branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/ICheckpointProtocol.java 2014-09-11 19:56:32 UTC (rev 8649) @@ -48,7 +48,7 @@ * @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/585" > GIST </a> */ public interface ICheckpointProtocol extends ICommitter, ICounterSetAccess, - ISimpleIndexAccess { + ISimpleIndexAccess, IReadWriteLockManager { /** * The value of the record version number that will be assigned to the next Copied: branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/IReadWriteLockManager.java (from rev 8648, branches/BIGDATA_RELEASE_1_3_0/bigdata/src/java/com/bigdata/btree/IReadWriteLockManager.java) =================================================================== --- branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/IReadWriteLockManager.java (rev 0) +++ branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/IReadWriteLockManager.java 2014-09-11 19:56:32 UTC (rev 8649) @@ -0,0 +1,82 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2011. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +package com.bigdata.btree; + +import java.util.concurrent.locks.Lock; + +/** + * Interface for managing read/write locks on persistence capable data + * structures. + * + * @see <a href="http://trac.bigdata.com/ticket/855"> AssertionError: Child does + * not have persistent identity </a> + */ +public interface IReadWriteLockManager { + + /** + * Return a {@link Lock} that may be used to obtain a shared read lock which + * is used (in the absence of other concurrency control mechanisms) to + * permit concurrent readers on an unisolated index while serializing access + * to that index when a writer must run. This is exposed for processes which + * need to obtain the write lock to coordinate external operations. + * <p> + * Note: If the persistence capable data structure is read-only then the + * returned {@link Lock} is a singleton that ignores all lock requests. This + * is because our read-only persistence capable data structures are already + * thread-safe for concurrent readers. + * + * @return The lock. + */ + Lock readLock(); + + /** + * Return a {@link Lock} that may be used to obtain an exclusive write lock + * which is used (in the absence of other concurrency control mechanisms) to + * serialize all processes accessing an unisolated index when a writer must + * run. This is exposed for processes which need to obtain the write lock to + * coordinate external operations. + * + * @return The lock. + * + * @throws UnsupportedOperationException + * unless the view supports mutation. + */ + Lock writeLock(); + + /** + * Return the #of read-locks held by the current thread for a mutable index + * view. + * + * @return The #of reentrant read locks held by the current thread -or- ZERO + * if the index is read-only (read locks are not tracked for a + * read-only index view). + */ + int getReadLockCount(); + + /** + * Return <code>true</code> iff the data structure is read-only. + */ + boolean isReadOnly(); + +} Copied: branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/IndexInconsistentError.java (from rev 8648, branches/BIGDATA_RELEASE_1_3_0/bigdata/src/java/com/bigdata/btree/IndexInconsistentError.java) =================================================================== --- branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/IndexInconsistentError.java (rev 0) +++ branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/IndexInconsistentError.java 2014-09-11 19:56:32 UTC (rev 8649) @@ -0,0 +1,67 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2007. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* + * Created on Sep 2, 2014 + */ +package com.bigdata.btree; + +/** + * Error marks an mutable index as in an inconsistent state. The index MUST be + * reloaded from the current checkpoint record. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * + * @see <a href="http://trac.bigdata.com/ticket/1005"> Invalidate BTree objects + * if error occurs during eviction </a> + */ +public class IndexInconsistentError extends Error { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public IndexInconsistentError() { + } + + public IndexInconsistentError(String message) { + super(message); + } + + public IndexInconsistentError(Throwable cause) { + super(cause); + } + + public IndexInconsistentError(String message, Throwable cause) { + super(message, cause); + } + + public IndexInconsistentError(String message, Throwable cause, + boolean enableSuppression, boolean writableStackTrace) { + + super(message, cause, enableSuppression, writableStackTrace); + + } + +} Copied: branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/ReadWriteLockManager.java (from rev 8648, branches/BIGDATA_RELEASE_1_3_0/bigdata/src/java/com/bigdata/btree/ReadWriteLockManager.java) =================================================================== --- branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/ReadWriteLockManager.java (rev 0) +++ branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/ReadWriteLockManager.java 2014-09-11 19:56:32 UTC (rev 8649) @@ -0,0 +1,528 @@ +/* + +Copyright (C) SYSTAP, LLC 2006-2008. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* + * Created on Sep 2, 2014 + */ +package com.bigdata.btree; + +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import com.bigdata.journal.ICommitter; + +/** + * Base class for managing read/write locks for unisolated {@link ICommitter}s. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * + * @see <a href="http://trac.bigdata.com/ticket/855"> AssertionError: Child does + * not have persistent identity </a> + */ +public class ReadWriteLockManager implements IReadWriteLockManager { + +// private static final Logger log = Logger.getLogger(ReadWriteLockManager.class); + + /** + * The #of milliseconds that the class will wait for a read or write lock. A + * (wrapped) {@link InterruptedException} will be thrown if this timeout is + * exceeded. The default is {@value #LOCK_TIMEOUT_MILLIS} milliseconds. Use + * {@link Long#MAX_VALUE} for no timeout. + * + * TODO There may be no reason to have a timeout when waiting for a lock in + * which case we can get rid of this field. Also, there is no means + * available to configure the timeout (in a similar fashion you can not + * configure the fairness policy for the {@link ReentrantReadWriteLock}). + * <p> + * If we get rid of this field, then the {@link WrappedReadLock} and + * {@link WrappedWriteLock} classes can be simplified to have normal lock + * semantics rather than tryLock() based semantics. + */ + private static final long LOCK_TIMEOUT_MILLIS = Long.MAX_VALUE;// 10000; + + /* + * Note: This creates a hard reference that defeats the weak keys in the + * hash map. + */ +// /** +// * The unisolated persistence capable data structure. +// */ +// final private ICheckpointProtocol committer; + + /** + * True iff the caller's {@link ICheckpointProtocol} object was read-only. + */ + final private boolean readOnly; + + /** + * The {@link Lock} used to permit concurrent readers on an unisolated index + * while serializing access to that index when a writer must run. + */ + final private WrappedWriteLock writeLock; + + /** + * The {@link Lock} ensures that any code path that obtains the read lock + * also maintains the per-thread read-lock counter. + */ + final private Lock readLock; + + /** + * Canonicalizing mapping for the {@link ReadWriteLockManager} objects. + */ + static final private WeakHashMap<ICommitter, ReadWriteLockManager> locks = new WeakHashMap<ICommitter, ReadWriteLockManager>(); + + @Override + public int getReadLockCount() { + + if (readOnly) { + + // No locks are actually taken. + return 0; + + } + + // Return the locks actually held by this thread. + final Integer readLockCounter = ((WrappedReadLock) readLock).threadLockMap + .get(Thread.currentThread().getId()); + + if (readLockCounter == null) { + + // No read locks are held. + return 0; + + } + + return readLockCounter.intValue(); + + } + + @Override + public Lock readLock() { + + return readLock; + + } + + @Override + public Lock writeLock() { + + if (readOnly) + throw new UnsupportedOperationException( + AbstractBTree.ERROR_READ_ONLY); + + return writeLock; + + } + + @Override + public boolean isReadOnly() { + + /* + * Note: This method is grounded out without delegation to avoid + * recursion through the target persistence capable data structure. + */ + + return readOnly; + + } + + /** + * {@link WrappedReadLock} is used to intercept lock/unlock calls to the + * readLock to trigger calls to the logic that tracks the #of reentrant + * read-locks by read and which can be used to identify whether the readlock + * is held by the current thread. + * <p> + * This is tested in the touch() methods for the BTree and HTree classe to + * determine whether the touch should be ignored or trigger potential + * evictions. + * + * @see <a href="http://trac.bigdata.com/ticket/855"> AssertionError: Child + * does not have persistent identity </a> + */ + private class WrappedReadLock implements Lock { + + private final Lock delegate; + + /** + * Maintain count of readLocks on by Thread. This is used to avoid having + * read-only operations protected by an {@link ReadWriteLockManager} + * causing evictions of dirty nodes and leaves. + * + * @see <a href="http://trac.bigdata.com/ticket/855"> AssertionError: Child + * does not have persistent identity </a> + */ + private final ConcurrentHashMap<Long, Integer> threadLockMap; + + /** + * Track the #of read locks by thread IFF this is a read/write index + * view. + */ + private void readLockedThread() { + final long thisThreadId = Thread.currentThread().getId(); + final Integer entry = threadLockMap.get(thisThreadId); + final Integer newVal = entry == null ? 1 : 1 + entry.intValue(); + threadLockMap.put(thisThreadId, newVal); + } + + /** + * Track the #of read locks by thread IFF this is a read/write index + * view. + */ + private void readUnlockedThread() { + final long thisThreadId = Thread.currentThread().getId(); + final Integer entry = threadLockMap.get(thisThreadId); + assert entry != null; + if (entry.intValue() == 1) { + threadLockMap.remove(thisThreadId); + } else { + threadLockMap.put(thisThreadId, entry.intValue() - 1); + } + } + + WrappedReadLock(final Lock delegate) { + + if (delegate == null) + throw new IllegalArgumentException(); + + this.delegate = delegate; + + /* + * Configure parallelism default. + * + * Note: This CHM is ONLY used by mutable index views. So what + * matters here is the #of threads that contend for a mutable index + * view. I suspect that this is significantly fewer threads than we + * observe for concurrent read-only index views. Therefore I have + * set the parameters for the map based on the notion that only a + * few threads are contending for the mutable index object in order + * to reduce the heap burden associated with these CHM instances. If + * this map is observed to be hot spot, then we can simply use the + * defaults (initialCapacity = concurrencyLevel = 16). We only have + * this for the mutable index views and there are typically not that + * many instances of those open at the same time. + */ + final int initialCapacity = 4; + final int concurrencyLevel = initialCapacity; + final float loadFactor = .75f; + this.threadLockMap = new ConcurrentHashMap<Long, Integer>( + initialCapacity, loadFactor, concurrencyLevel); + + } + + @Override + public void lock() { + try { + /* + * Note: The original UnisolatedReadWriteLock semantics are + * always those of a tryLock with a default timeout. Make sure + * that we keep this in place! + */ + lockInterruptibly(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Override + public void lockInterruptibly() throws InterruptedException { + /* + * Note: The order in which we obtain the real read lock and + * increment (and decrement) the per-thread read lock counter on the + * AbstractBTree is not critical because AbstractBTree.touch() + * relies on the thread both owning the read lock and having the + * per-thread read lock counter incremented for that thread. + * + * Note: The original UnisolatedReadWriteLock semantics are always + * those of a tryLock with a default timeout. Make sure that we keep + * this in place! + */ +// delegate.lock(); + if (!delegate.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) { + throw new RuntimeException("Timeout"); + } + readLockedThread(); + } + + @Override + public boolean tryLock() { + final boolean ret = delegate.tryLock(); + if (ret) { + readLockedThread(); + } + return ret; + } + + @Override + public boolean tryLock(final long time, final TimeUnit unit) + throws InterruptedException { + final boolean ret = delegate.tryLock(time, unit); + if (ret) { + readLockedThread(); + } + return ret; + } + + @Override + public void unlock() { + /* + * Note: The unlock order does not really matter. See the + * comments on lock() and AbstractBTree.touch(). + */ + delegate.unlock(); + /* + * Do this after the unlock() in case the lock/unlock are not + * correctly paired. + */ + readUnlockedThread(); + } + + @Override + public Condition newCondition() { + return delegate.newCondition(); + } + + } // class WrappedReadLock + + /** + * Wraps the write lock to provide interruptable tryLock() with timeout + * semantics for all write lock acquisitions. + * + * @author <a href="mailto:tho...@us...">Bryan + * Thompson</a> + * + * @see <a href="http://trac.bigdata.com/ticket/855"> AssertionError: Child + * does not have persistent identity </a> + */ + private class WrappedWriteLock implements Lock { + + private final Lock delegate; + + WrappedWriteLock(final Lock delegate) { + + if (delegate == null) + throw new IllegalArgumentException(); + + this.delegate = delegate; + + } + + @Override + public void lock() { + try { + /* + * Note: The original UnisolatedReadWriteLock semantics are + * always those of a tryLock with a default timeout. Make sure + * that we keep this in place! + */ + lockInterruptibly(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Override + public void lockInterruptibly() throws InterruptedException { + /* + * Note: The original UnisolatedReadWriteLock semantics are always + * those of a tryLock with a default timeout. Make sure that we keep + * this in place! + */ +// delegate.lock(); + if (!delegate.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) { + throw new RuntimeException("Timeout"); + } + } + + @Override + public boolean tryLock() { + return delegate.tryLock(); + } + + @Override + public boolean tryLock(final long time, final TimeUnit unit) + throws InterruptedException { + return delegate.tryLock(time, unit); + } + + @Override + public void unlock() { + delegate.unlock(); + } + + @Override + public Condition newCondition() { + return delegate.newCondition(); + } + + } // class WrappedWriteLock + + /** + * Class used for read lock for read-only data structures. + * + * @author <a href="mailto:tho...@us...">Bryan + * Thompson</a> + */ + private static class ConcurrentReaderLock implements Lock { + + @Override + public void lock() { + // NOP + } + + @Override + public void lockInterruptibly() throws InterruptedException { + // NOP + } + + @Override + public boolean tryLock() { + return true; + } + + @Override + public boolean tryLock(long time, TimeUnit unit) + throws InterruptedException { + return true; + } + + @Override + public void unlock() { + // NOP + } + + @Override + public Condition newCondition() { + throw new UnsupportedOperationException(); + } + + } + private static final Lock READ_ONLY_LOCK = new ConcurrentReaderLock(); + + /** + * Canonicalizing factory for the {@link ReadWriteLock} for an + * {@link ICommitter}. + * <p> + * Note: This method CAN NOT be exposed since that breaks encapsulation for + * the {@link WrappedReadLock}. + * + * @param index + * The btree. + * @return The lock. + * + * @throws IllegalArgumentException + * if the argument is <code>null</code>. + */ + static public ReadWriteLockManager getLockManager( + final ICheckpointProtocol index) { + + if (index == null) + throw new IllegalArgumentException(); + + synchronized (locks) { + + ReadWriteLockManager lockManager = locks.get(index); + + if (lockManager == null) { + + lockManager = new ReadWriteLockManager(index); + + locks.put(index, lockManager); + + } + + return lockManager; + } + + } + + /** + * Note: ONLY accessed through the canonicalizing pattern! + */ + private ReadWriteLockManager(final ICheckpointProtocol index) { + +// this.committer = index; + + if (this.readOnly = index.isReadOnly()) { + + /* + * Since the index does not allow mutation, wrap with a NOP lock. + * + * Note: Concurrent readers are automatically supported by our + * persistent capable data structures so we return a NOP Lock + * implementation if the data structure is read-only. Also note that + * read-only data structures are (by definition) not mutable so we + * do not need to track the #of reentrant locks held for a read-only + * data structure (per above). + */ + this.readLock = READ_ONLY_LOCK; + + this.writeLock = null; + + } else { + + /* + * Note: fairness is NOT required for the locks. I believe that this + * is supposed to provide better throughput, but that has not been + * tested. Also, this has not been tested with a simple mutex lock + * vs a read-write lock. The use case for which this class was + * originally developed was computing the fix point of a set of + * rules. In that use case, we do a lot of concurrent reading and + * periodically flush the computed solutions onto the relations. It + * is likely that a read-write lock will do well for this situation. + */ + final ReadWriteLock readWriteLock = new ReentrantReadWriteLock( + false/* fair */); + + /** + * If the index allows mutation, then wrap with tryLock() and + * lock-counting semantics. This allows us to test for the #of + * reentrant locks held by the current thread in + * AbstractBTree.touch() and is the primary basis for the fix the + * ticket below. + * + * @see <a href="http://trac.bigdata.com/ticket/855"> + * AssertionError: Child does not have persistent identity </a> + */ + this.readLock = new WrappedReadLock(readWriteLock.readLock()); + + // Wrap with tryLock() semantics. + this.writeLock = new WrappedWriteLock(readWriteLock.writeLock()); + + } + + } + +// @Override +// final public String toString() { +// +// return getClass().getName() + "{committer=" + committer + ",readOnly=" +// + readOnly + "}"; +// +// } + +} Modified: branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/UnisolatedReadWriteIndex.java =================================================================== --- branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/UnisolatedReadWriteIndex.java 2014-09-11 19:26:33 UTC (rev 8648) +++ branches/SESAME_2_7/bigdata/src/java/com/bigdata/btree/UnisolatedReadWriteIndex.java 2014-09-11 19:56:32 UTC (rev 8649) @@ -23,20 +23,14 @@ */ /* * Created on Jan 10, 2008 - * */ package com.bigdata.btree; import java.util.Iterator; -import java.util.WeakHashMap; -import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import org.apache.log4j.Logger; - import com.bigdata.bop.cost.BTreeCostModel; import com.bigdata.bop.cost.DiskCostModel; import com.bigdata.bop.cost.ScanCostReport; @@ -48,10 +42,7 @@ import com.bigdata.btree.view.FusedView; import com.bigdata.counters.CounterSet; import com.bigdata.journal.ConcurrencyManager; -import com.bigdata.journal.ICommitter; import com.bigdata.journal.IConcurrencyManager; -import com.bigdata.journal.Journal; -import com.bigdata.journal.TemporaryStore; import com.bigdata.mdi.IResourceMetadata; import com.bigdata.service.Split; @@ -120,124 +111,52 @@ * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> */ -public class UnisolatedReadWriteIndex implements IIndex, ILinearList { +public class UnisolatedReadWriteIndex implements IIndex, ILinearList, + IReadWriteLockManager { - private static final Logger log = Logger.getLogger(UnisolatedReadWriteIndex.class); - /** - * The #of milliseconds that the class will wait for a read or write lock. A - * (wrapped) {@link InterruptedException} will be thrown if this timeout is - * exceeded. The default is {@value #LOCK_TIMEOUT_MILLIS} milliseconds. Use - * {@link Long#MAX_VALUE} for no timeout. - * - * @todo There may be no reason to have a timeout when waiting for a lock in - * which case we can get rid of this field. Also, there is no means - * available to configur... [truncated message content] |