protected void commitRelationshipMaps( ArrayMap<String, RelIdArray> cowRelationshipAddMap, ArrayMap<String, RelIdArray> cowRelationshipRemoveMap) { if (relationshipMap == null) { // we will load full in some other tx return; } if (cowRelationshipAddMap != null) { for (String type : cowRelationshipAddMap.keySet()) { RelIdArray add = cowRelationshipAddMap.get(type); RelIdArray remove = null; if (cowRelationshipRemoveMap != null) { remove = cowRelationshipRemoveMap.get(type); } RelIdArray src = relationshipMap.get(type); relationshipMap.put(type, RelIdArray.from(src, add, remove)); } } if (cowRelationshipRemoveMap != null) { for (String type : cowRelationshipRemoveMap.keySet()) { if (cowRelationshipAddMap != null && cowRelationshipAddMap.get(type) != null) { continue; } RelIdArray src = relationshipMap.get(type); RelIdArray remove = cowRelationshipRemoveMap.get(type); relationshipMap.put(type, RelIdArray.from(src, null, remove)); } } }
@Override public void attemptWaitForTxCompletionAndBlockFutureTransactions(long maxWaitTimeMillis) { msgLog.logMessage("TxManager is blocking new transactions and waiting for active to fail..."); blocked = true; List<Transaction> failedTransactions = new ArrayList<Transaction>(); synchronized (txThreadMap) { for (Transaction tx : txThreadMap.values()) { try { int status = tx.getStatus(); if (status != Status.STATUS_COMMITTING && status != Status .STATUS_ROLLING_BACK) { // Set it to rollback only if it's not committing or // rolling back tx.setRollbackOnly(); } } catch (IllegalStateException e) { // OK failedTransactions.add(tx); } catch (SystemException e) { // OK failedTransactions.add(tx); } } } msgLog.logMessage( "TxManager blocked transactions" + ((failedTransactions.isEmpty() ? "" : ", but failed for: " + failedTransactions.toString()))); long endTime = System.currentTimeMillis() + maxWaitTimeMillis; while (txThreadMap.size() > 0 && System.currentTimeMillis() < endTime) Thread.yield(); }
ArrayMap<String, IntArray> getMoreRelationships(NodeImpl node) { int nodeId = (int) node.getId(); RelationshipChainPosition position = node.getRelChainPosition(); Iterable<RelationshipData> rels = persistenceManager.getMoreRelationships(nodeId, position); ArrayMap<String, IntArray> newRelationshipMap = new ArrayMap<String, IntArray>(); for (RelationshipData rel : rels) { int relId = rel.getId(); RelationshipImpl relImpl = relCache.get(relId); RelationshipType type = null; if (relImpl == null) { type = getRelationshipTypeById(rel.relationshipType()); assert type != null; relImpl = new RelationshipImpl(relId, rel.firstNode(), rel.secondNode(), type, false, this); relCache.put(relId, relImpl); } else { type = relImpl.getType(); } IntArray relationshipSet = newRelationshipMap.get(type.name()); if (relationshipSet == null) { relationshipSet = new IntArray(); newRelationshipMap.put(type.name(), relationshipSet); } relationshipSet.add(relId); } return newRelationshipMap; }
private void receiveRelationships( Iterable<RelationshipRecord> rels, ArrayMap<Integer, RelIdArray> newRelationshipMap, List<RelationshipImpl> relsList, DirectionWrapper dir, boolean hasLoops) { for (RelationshipRecord rel : rels) { long relId = rel.getId(); RelationshipImpl relImpl = relCache.get(relId); RelationshipType type = null; int typeId; if (relImpl == null) { typeId = rel.getType(); type = getRelationshipTypeById(typeId); assert type != null; relImpl = newRelationshipImpl( relId, rel.getFirstNode(), rel.getSecondNode(), type, typeId, false); relsList.add(relImpl); } else { typeId = relImpl.getTypeId(); type = getRelationshipTypeById(typeId); } RelIdArray relationshipSet = newRelationshipMap.get(typeId); if (relationshipSet == null) { relationshipSet = hasLoops ? new RelIdArrayWithLoops(typeId) : new RelIdArray(typeId); newRelationshipMap.put(typeId, relationshipSet); } relationshipSet.add(relId, dir); } }
public T acquireResourceConnection() { T con = null; Transaction tx = this.getCurrentTransaction(); if (tx == null) { throw new NotInTransactionException(); } con = txConnectionMap.get(tx); if (con == null) { try { con = (T) newConnection(); if (!tx.enlistResource(con.getXaResource())) { throw new RuntimeException("Unable to enlist '" + con.getXaResource() + "' in " + tx); } tx.registerSynchronization(new TxCommitHook(tx)); txConnectionMap.put(tx, con); } catch (javax.transaction.RollbackException re) { String msg = "The transaction is marked for rollback only."; throw new RuntimeException(msg, re); } catch (javax.transaction.SystemException se) { String msg = "TM encountered an unexpected error condition."; throw new RuntimeException(msg, se); } } return con; }
public CowRelElement relationshipElement(long id, boolean create) { CowRelElement result = relationships.get(id); if (result == null && create) { result = new CowRelElement(id); relationships.put(id, result); } return result; }
public CowNodeElement nodeElement(long id, boolean create) { CowNodeElement result = nodes.get(id); if (result == null && create) { result = new CowNodeElement(id); nodes.put(id, result); } return result; }
private TxLockElement getOrCreateLockElement(Object tx) { assertTransaction(tx); TxLockElement tle = txLockElementMap.get(tx); if (tle == null) { txLockElementMap.put(tx, tle = new TxLockElement(tx)); } return tle; }
/** Closes this index service and frees all resources. */ public void close() { for (IndexSearcher searcher : indexSearchers.values()) { try { searcher.close(); } catch (IOException e) { e.printStackTrace(); } } indexSearchers.clear(); }
@Override public ArrayMap<Integer, Collection<Long>> getCowRelationshipRemoveMap(NodeImpl node) { if (primitiveElement != null) { ArrayMap<Long, CowNodeElement> cowElements = primitiveElement.nodes; CowNodeElement element = cowElements.get(node.getId()); if (element != null) { return element.relationshipRemoveMap; } } return null; }
public RelIdArray getRelationshipAddMap(int type, boolean create) { ArrayMap<Integer, RelIdArray> map = getRelationshipAddMap(create); if (map == null) { return null; } RelIdArray result = map.get(type); if (result == null && create) { result = new RelIdArrayWithLoops(type); map.put(type, result); } return result; }
public SetAndDirectionCounter getRelationshipRemoveMap(int type, boolean create) { ArrayMap<Integer, SetAndDirectionCounter> map = getRelationshipRemoveMap(create); if (map == null) { return null; } SetAndDirectionCounter result = map.get(type); if (result == null && create) { result = new SetAndDirectionCounter(); map.put(type, result); } return result; }
private void releaseCows(int param) { if (primitiveElement == null) { return; } ArrayMap<Long, CowNodeElement> cowNodeElements = primitiveElement.nodes; Set<Entry<Long, CowNodeElement>> nodeEntrySet = cowNodeElements.entrySet(); for (Entry<Long, CowNodeElement> entry : nodeEntrySet) { NodeImpl node = nodeManager.getNodeIfCached(entry.getKey()); if (node != null) { CowNodeElement nodeElement = entry.getValue(); if (param == Status.STATUS_COMMITTED) { node.commitRelationshipMaps( nodeElement.relationshipAddMap, nodeElement.relationshipRemoveMap); node.commitPropertyMaps( nodeElement.propertyAddMap, nodeElement.propertyRemoveMap, nodeElement.firstProp); } else if (param != Status.STATUS_ROLLEDBACK) { throw new TransactionFailureException("Unknown transaction status: " + param); } int sizeAfter = node.sizeOfObjectInBytesIncludingOverhead(); nodeManager.updateCacheSize(node, sizeAfter); } } ArrayMap<Long, CowRelElement> cowRelElements = primitiveElement.relationships; Set<Entry<Long, CowRelElement>> relEntrySet = cowRelElements.entrySet(); for (Entry<Long, CowRelElement> entry : relEntrySet) { RelationshipImpl rel = nodeManager.getRelIfCached(entry.getKey()); if (rel != null) { CowRelElement relElement = entry.getValue(); if (param == Status.STATUS_COMMITTED) { rel.commitPropertyMaps( relElement.propertyAddMap, relElement.propertyRemoveMap, Record.NO_NEXT_PROPERTY.intValue()); } else if (param != Status.STATUS_ROLLEDBACK) { throw new TransactionFailureException("Unknown transaction status: " + param); } int sizeAfter = rel.sizeOfObjectInBytesIncludingOverhead(); nodeManager.updateCacheSize(rel, sizeAfter); } } if (primitiveElement.graph != null && param == Status.STATUS_COMMITTED) { nodeManager .getGraphProperties() .commitPropertyMaps( primitiveElement.graph.getPropertyAddMap(false), primitiveElement.graph.getPropertyRemoveMap(false), Record.NO_NEXT_PROPERTY.intValue()); } }
public void shutdown() { try { for (IndexSearcher searcher : indexSearchers.values()) { searcher.close(); } indexSearchers.clear(); optimize(); for (IndexWriterContext writer : indexWriters.values()) { writer.writer.close(); } indexWriters.clear(); } catch (IOException e) { throw new RuntimeException(e); } }
String getStringKey(int keyId) { String stringKey = idToIndex.get(keyId); if (stringKey == null) { throw new NotFoundException("No such property index[" + keyId + "]"); } return stringKey; }
private TxLockElement getLockElement(Object tx) { TxLockElement tle = txLockElementMap.get(tx); if (tle == null) { throw new LockNotFoundException("No transaction lock element found for " + tx); } return tle; }
/** * Releases the write lock held by the provided tx. If it is null then an attempt to acquire the * current transaction from the transaction manager will be made. This is to make safe calling * this method as an <code>afterCompletion()</code> hook where the transaction context is not * necessarily available. If write count is zero and there are waiting transactions in the queue * they will be interrupted if they can acquire the lock. */ synchronized void releaseWriteLock(Object tx) throws LockNotFoundException { TxLockElement tle = getLockElement(tx); if (tle.writeCount == 0) { throw new LockNotFoundException("" + tx + " don't have writeLock"); } totalWriteCount--; tle.writeCount--; if (tle.isFree()) { txLockElementMap.remove(tx); ragManager.lockReleased(this, tx); } // the threads in the waitingList cannot be currentThread // so we only have to wake other elements if writeCount is down to zero // (that is: If writeCount > 0 a waiting thread in the queue cannot be // the thread that holds the write locks because then it would never // have been put into wait mode) if (totalWriteCount == 0 && waitingThreadList.size() > 0) { // wake elements in queue until a write lock is found or queue is // empty do { WaitElement we = waitingThreadList.removeLast(); if (!we.element.movedOn) { we.waitingThread.interrupt(); if (we.lockType == LockType.WRITE) { break; } } } while (waitingThreadList.size() > 0); } }
int getKeyId(String stringKey) { Integer keyId = propertyIndexes.get(stringKey); if (keyId != null) { return keyId; } return -1; }
// after invoke the transaction must wait on the resource synchronized void checkWaitOn(Object resource, Transaction tx) throws DeadlockDetectedException { List<Transaction> lockingTxList = resourceMap.get(resource); if (lockingTxList == null) { throw new LockException("Illegal resource[" + resource + "], not found in map"); } if (waitingTxMap.get(tx) != null) { throw new LockException(tx + " already waiting for resource"); } Iterator<Transaction> itr = lockingTxList.iterator(); List<Transaction> checkedTransactions = new LinkedList<Transaction>(); Stack<Object> graphStack = new Stack<Object>(); // has resource,transaction interleaved graphStack.push(resource); while (itr.hasNext()) { Transaction lockingTx = itr.next(); // the if statement bellow is valid because: // t1 -> r1 -> t1 (can happened with RW locks) is ok but, // t1 -> r1 -> t1&t2 where t2 -> r1 is a deadlock // think like this, we have two transactions and one resource // o t1 takes read lock on r1 // o t2 takes read lock on r1 // o t1 wanna take write lock on r1 but has to wait for t2 // to release the read lock ( t1->r1->(t1&t2), ok not deadlock yet // o t2 wanna take write lock on r1 but has to wait for t1 // to release read lock.... // DEADLOCK t1->r1->(t1&t2) and t2->r1->(t1&t2) ===> // t1->r1->t2->r1->t1, t2->r1->t1->r1->t2 etc... // to allow the first three steps above we check if lockingTx == // waitingTx on first level. // because of this special case we have to keep track on the // already "checked" tx since it is (now) legal for one type of // circular reference to exist (t1->r1->t1) otherwise we may // traverse t1->r1->t2->r1->t2->r1->t2... until SOE // ... KISS to you too if (lockingTx.equals(tx)) { continue; } graphStack.push(tx); checkWaitOnRecursive(lockingTx, tx, checkedTransactions, graphStack); graphStack.pop(); } // ok no deadlock, we can wait on resource waitingTxMap.put(tx, resource); }
public int getStatus() { Thread thread = Thread.currentThread(); TransactionImpl tx = txThreadMap.get(thread); if (tx != null) { return tx.getStatus(); } return Status.STATUS_NO_TRANSACTION; }
List<RelTypeElementIterator> getAllRelationships(NodeManager nodeManager) { ensureRelationshipMapNotNull(nodeManager); List<RelTypeElementIterator> relTypeList = new LinkedList<RelTypeElementIterator>(); boolean hasModifications = nodeManager.getLockReleaser().hasRelationshipModifications(this); ArrayMap<String, RelIdArray> addMap = null; if (hasModifications) { addMap = nodeManager.getCowRelationshipAddMap(this); } for (String type : relationshipMap.keySet()) { RelIdArray src = relationshipMap.get(type); RelIdArray remove = null; RelIdArray add = null; if (hasModifications) { remove = nodeManager.getCowRelationshipRemoveMap(this, type); if (addMap != null) { add = addMap.get(type); } } // if ( src != null || add != null ) // { relTypeList.add(RelTypeElement.create(type, this, src, add, remove)); // } } if (addMap != null) { for (String type : addMap.keySet()) { if (relationshipMap.get(type) == null) { RelIdArray remove = nodeManager.getCowRelationshipRemoveMap(this, type); RelIdArray add = addMap.get(type); relTypeList.add(RelTypeElement.create(type, this, null, add, remove)); } } } return relTypeList; }
List<RelTypeElementIterator> getAllRelationships(NodeManager nodeManager) { ensureRelationshipMapNotNull(nodeManager); List<RelTypeElementIterator> relTypeList = new LinkedList<RelTypeElementIterator>(); ArrayMap<String, IntArray> addMap = nodeManager.getCowRelationshipAddMap(this); for (String type : relationshipMap.keySet()) { IntArray src = relationshipMap.get(type); IntArray remove = nodeManager.getCowRelationshipRemoveMap(this, type); IntArray add = null; if (addMap != null) { add = addMap.get(type); } if (src != null || add != null) { relTypeList.add(RelTypeElement.create(type, this, src, add, remove)); } } if (addMap != null) { for (String type : addMap.keySet()) { if (relationshipMap.get(type) == null) { IntArray remove = nodeManager.getCowRelationshipRemoveMap(this, type); IntArray add = addMap.get(type); relTypeList.add(RelTypeElement.create(type, this, null, add, remove)); } } } return relTypeList; }
// need synch here so we don't create multiple lists private synchronized void addPropertyIndex(PropertyIndex index) { List<PropertyIndex> list = indexMap.get(index.getKey()); if (list == null) { list = new CopyOnWriteArrayList<PropertyIndex>(); indexMap.put(index.getKey(), list); } list.add(index); idToIndexMap.put(index.getKeyId(), index); }
public void setRollbackOnly() throws IllegalStateException, SystemException { assertTmOk("tx set rollback only"); Thread thread = Thread.currentThread(); TransactionImpl tx = txThreadMap.get(thread); if (tx == null) { throw new IllegalStateException("Not in transaction"); } tx.setRollbackOnly(); }
public void resume(Transaction tx) throws IllegalStateException, SystemException { assertTmOk("tx resume"); Thread thread = Thread.currentThread(); if (txThreadMap.get(thread) != null) { throw new IllegalStateException("Transaction already associated"); } if (tx != null) { TransactionImpl txImpl = (TransactionImpl) tx; if (txImpl.getStatus() != Status.STATUS_NO_TRANSACTION) { if (txImpl.isActive()) { throw new IllegalStateException(txImpl + " already active"); } txImpl.markAsActive(); txThreadMap.put(thread, txImpl); } // generate pro-active event resume } }
void commit(Transaction tx) { if (tx != null) { TxCommitHook hook = txCommitHooks.remove(tx); if (hook != null) { for (PropertyIndex index : hook.getAddedPropertyIndexes()) { addPropertyIndex(index); } } } }
public void optimize() { try { for (IndexWriterContext writer : indexWriters.values()) { writer.writer.optimize(true); writer.modifiedFlag = true; } } catch (IOException e) { throw new RuntimeException(e); } }
private IndexWriterContext getWriter(String key, boolean allowCreate) throws IOException { IndexWriterContext writer = indexWriters.get(key); Directory dir = instantiateDirectory(key); if (writer == null && (allowCreate || IndexReader.indexExists(dir))) { try { IndexWriter indexWriter = new IndexWriter(dir, fieldAnalyzer, MaxFieldLength.UNLIMITED); // TODO We should tamper with this value and see how it affects // the general performance. Lucene docs says rather >10 for // batch inserts // indexWriter.setMergeFactor( 15 ); writer = new IndexWriterContext(indexWriter); } catch (IOException e) { throw new RuntimeException(e); } indexWriters.put(key, writer); } return writer; }
public Transaction suspend() throws SystemException { assertTmOk("tx suspend"); // check for ACTIVE/MARKED_ROLLBACK? TransactionImpl tx = txThreadMap.remove(Thread.currentThread()); if (tx != null) { // generate pro-active event suspend tx.markAsSuspended(); } return tx; }
// concurent transactions may create duplicate keys, oh well PropertyIndex createPropertyIndex(String key) { Transaction tx = getTransaction(); if (tx == null) { throw new NotInTransactionException("Unable to create property index for " + key); } TxCommitHook hook = txCommitHooks.get(tx); if (hook == null) { hook = new TxCommitHook(); txCommitHooks.put(tx, hook); } PropertyIndex index = hook.getIndex(key); if (index != null) { return index; } int id = (int) idGenerator.nextId(PropertyIndex.class); index = new PropertyIndex(key, id); hook.addIndex(index); persistenceManager.createPropertyIndex(key, id); return index; }