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)); } } }
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; }
boolean getMoreRelationships(NodeManager nodeManager) { // ArrayMap<String, IntArray> tmpRelMap = relationshipMap; Pair<ArrayMap<String, RelIdArray>, Map<Long, RelationshipImpl>> pair; synchronized (this) { if (!relChainPosition.hasMore()) { return false; } pair = nodeManager.getMoreRelationships(this); ArrayMap<String, RelIdArray> addMap = pair.first(); if (addMap.size() == 0) { return false; } for (String type : addMap.keySet()) { RelIdArray addRels = addMap.get(type); // IntArray srcRels = tmpRelMap.get( type ); RelIdArray srcRels = relationshipMap.get(type); if (srcRels == null) { relationshipMap.put(type, addRels); } else { srcRels.addAll(addRels); } } } nodeManager.putAllInRelCache(pair.other()); return true; }
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 TxLockElement getOrCreateLockElement(Object tx) { assertTransaction(tx); TxLockElement tle = txLockElementMap.get(tx); if (tle == null) { txLockElementMap.put(tx, tle = new TxLockElement(tx)); } return tle; }
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; }
// 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); }
@Test public void testArrayMap() { ArrayMap<String, Integer> map = new ArrayMap<String, Integer>(); assertTrue(map.get("key1") == null); map.put("key1", 0); assertEquals(new Integer(0), map.get("key1")); assertEquals(new Integer(0), map.get("key1")); map.put("key1", 1); assertEquals(new Integer(1), map.get("key1")); map.put("key2", 0); assertEquals(new Integer(0), map.get("key2")); map.put("key2", 2); assertEquals(new Integer(2), map.get("key2")); assertEquals(new Integer(2), map.remove("key2")); assertTrue(map.get("key2") == null); assertEquals(new Integer(1), map.get("key1")); assertEquals(new Integer(1), map.remove("key1")); assertTrue(map.get("key1") == null); map.put("key1", 1); map.put("key2", 2); map.put("key3", 3); map.put("key4", 4); map.put("key5", 5); assertEquals(new Integer(5), map.get("key5")); assertEquals(new Integer(4), map.get("key4")); assertEquals(new Integer(3), map.get("key3")); assertEquals(new Integer(2), map.get("key2")); assertEquals(new Integer(1), map.get("key1")); assertEquals(new Integer(5), map.remove("key5")); assertEquals(new Integer(1), map.get("key1")); assertEquals(new Integer(4), map.get("key4")); assertEquals(new Integer(3), map.get("key3")); assertEquals(new Integer(2), map.get("key2")); assertEquals(new Integer(3), map.remove("key3")); assertEquals(new Integer(1), map.remove("key1")); assertEquals(new Integer(2), map.remove("key2")); for (int i = 0; i < 100; i++) { map.put("key" + i, i); } for (int i = 0; i < 100; i++) { assertEquals(new Integer(i), map.get("key" + i)); } for (int i = 0; i < 100; i++) { assertEquals(new Integer(i), map.remove("key" + i)); } for (int i = 0; i < 100; i++) { assertTrue(map.get("key" + i) == 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; }
// 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 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 } }
public void delete(NodeManager nodeManager) { nodeManager.acquireLock(this, LockType.WRITE); boolean success = false; try { ArrayMap<Integer, PropertyData> skipMap = nodeManager.getCowPropertyRemoveMap(this, true); ArrayMap<Integer, PropertyData> removedProps = nodeManager.deleteNode(this); if (removedProps.size() > 0) { for (int index : removedProps.keySet()) { skipMap.put(index, removedProps.get(index)); } } success = true; } finally { nodeManager.releaseLock(this, LockType.WRITE); if (!success) { nodeManager.setRollbackOnly(); } } }
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; }
// 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; }
IndexSearcher getIndexSearcher(String key) { IndexSearcher searcher = indexSearchers.get(key); if (searcher == null) { try { File fsDirectory = new File(storeDir, key); if (!fsDirectory.exists()) { return null; } Directory dir = FSDirectory.open(fsDirectory); if (dir.listAll().length == 0) { return null; } searcher = new IndexSearcher(dir, true); } catch (IOException e) { throw new RuntimeException(e); } indexSearchers.put(key, searcher); } return searcher; }
public void begin(ForceMode forceMode) throws NotSupportedException, SystemException { if (blocked) { throw new SystemException( "TxManager is preventing new transactions from starting " + "due a shutdown is imminent"); } assertTmOk("tx begin"); Thread thread = Thread.currentThread(); TransactionImpl tx = txThreadMap.get(thread); if (tx != null) { throw logAndReturn( "TM error tx begin", new NotSupportedException("Nested transactions not supported")); } tx = new TransactionImpl(this, forceMode); txThreadMap.put(thread, tx); int concurrentTxCount = txThreadMap.size(); if (concurrentTxCount > peakConcurrentTransactions) { peakConcurrentTransactions = concurrentTxCount; } startedTxCount.incrementAndGet(); // start record written on resource enlistment }
private Map<Long, RelationshipImpl> getMoreRelationships( NodeManager nodeManager, ArrayMap<String, RelIdArray> tmpRelMap) { if (!relChainPosition.hasMore()) { return null; } Pair<ArrayMap<String, RelIdArray>, Map<Long, RelationshipImpl>> pair = nodeManager.getMoreRelationships(this); ArrayMap<String, RelIdArray> addMap = pair.first(); if (addMap.size() == 0) { return null; } for (String type : addMap.keySet()) { RelIdArray addRels = addMap.get(type); RelIdArray srcRels = tmpRelMap.get(type); if (srcRels == null) { tmpRelMap.put(type, addRels); } else { srcRels.addAll(addRels); } } return pair.other(); // nodeManager.putAllInRelCache( pair.other() ); }
private IndexSearcher getSearcher(String key) { try { IndexWriterContext writer = getWriter(key, false); if (writer == null) { return null; } IndexSearcher oldSearcher = indexSearchers.get(key); IndexSearcher result = oldSearcher; if (oldSearcher == null || writer.modifiedFlag) { if (oldSearcher != null) { oldSearcher.getIndexReader().close(); oldSearcher.close(); } IndexReader newReader = writer.writer.getReader(); result = new IndexSearcher(newReader); indexSearchers.put(key, result); writer.modifiedFlag = false; } return result; } catch (IOException e) { throw new RuntimeException(e); } }
void addPropertyIndex(String stringKey, int keyId) { propertyIndexes.put(stringKey, keyId); idToIndex.put(keyId, stringKey); }
public void delete() { NodeImpl startNode = null; NodeImpl endNode = null; boolean startNodeLocked = false; boolean endNodeLocked = false; nodeManager.acquireLock(this, LockType.WRITE); boolean success = false; try { startNode = nodeManager.getLightNode(startNodeId); if (startNode != null) { nodeManager.acquireLock(startNode, LockType.WRITE); startNodeLocked = true; } endNode = nodeManager.getLightNode(endNodeId); if (endNode != null) { nodeManager.acquireLock(endNode, LockType.WRITE); endNodeLocked = true; } // no need to load full relationship, all properties will be // deleted when relationship is deleted ArrayMap<Integer, PropertyData> skipMap = nodeManager.getCowPropertyRemoveMap(this, true); ArrayMap<Integer, PropertyData> removedProps = nodeManager.deleteRelationship(this); if (removedProps.size() > 0) { for (int index : removedProps.keySet()) { skipMap.put(index, removedProps.get(index)); } } success = true; if (startNode != null) { startNode.removeRelationship(type, id); } if (endNode != null) { endNode.removeRelationship(type, id); } success = true; } finally { boolean releaseFailed = false; try { if (startNodeLocked) { nodeManager.releaseLock(startNode, LockType.WRITE); } } catch (Exception e) { releaseFailed = true; e.printStackTrace(); } try { if (endNodeLocked) { nodeManager.releaseLock(endNode, LockType.WRITE); } } catch (Exception e) { releaseFailed = true; e.printStackTrace(); } nodeManager.releaseLock(this, LockType.WRITE); if (!success) { setRollbackOnly(); } if (releaseFailed) { throw new LockException( "Unable to release locks [" + startNode + "," + endNode + "] in relationship delete->" + this); } } }
PropertyIndexHolder(PropertyIndexData[] indexes) { for (PropertyIndexData index : indexes) { propertyIndexes.put(index.getValue(), index.getKeyId()); idToIndex.put(index.getKeyId(), index.getValue()); } }