|
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] |