From 56e9002855ce58f0136a780d4150a5f67167355f Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Wed, 3 May 2006 23:06:59 +0000 Subject: [PATCH] More robust concurrency handling of cached references git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2750 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../repo/domain/hibernate/ChildAssocImpl.java | 121 +++++++++++++++--- .../repo/domain/hibernate/NodeAssocImpl.java | 79 ++++++++++-- 2 files changed, 175 insertions(+), 25 deletions(-) diff --git a/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java b/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java index 9b3c31bfa0..fa356b5093 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java @@ -16,6 +16,10 @@ */ package org.alfresco.repo.domain.hibernate; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; + import org.alfresco.repo.domain.ChildAssoc; import org.alfresco.repo.domain.Node; import org.alfresco.service.cmr.repository.ChildAssociationRef; @@ -34,10 +38,17 @@ public class ChildAssocImpl implements ChildAssoc private QName qName; private boolean isPrimary; private int index; + + private transient ReadLock refReadLock; + private transient WriteLock refWriteLock; private transient ChildAssociationRef childAssocRef; public ChildAssocImpl() { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + refReadLock = lock.readLock(); + refWriteLock = lock.writeLock(); + setIndex(Integer.MAX_VALUE); // comes last } @@ -64,19 +75,42 @@ public class ChildAssocImpl implements ChildAssoc this.getChild().getParentAssocs().remove(this); } - public synchronized ChildAssociationRef getChildAssocRef() + public ChildAssociationRef getChildAssocRef() { - if (childAssocRef == null) + // first check if it is available + refReadLock.lock(); + try { - childAssocRef = new ChildAssociationRef( - this.typeQName, - getParent().getNodeRef(), - this.qName, - getChild().getNodeRef(), - this.isPrimary, - -1); + if (childAssocRef != null) + { + return childAssocRef; + } + } + finally + { + refReadLock.unlock(); + } + // get write lock + refWriteLock.lock(); + try + { + // double check + if (childAssocRef == null ) + { + childAssocRef = new ChildAssociationRef( + this.typeQName, + getParent().getNodeRef(), + this.qName, + getChild().getNodeRef(), + this.isPrimary, + -1); + } + return childAssocRef; + } + finally + { + refWriteLock.unlock(); } - return childAssocRef; } public String toString() @@ -161,6 +195,7 @@ public class ChildAssocImpl implements ChildAssoc /** * For Hibernate use */ + @SuppressWarnings("unused") private void setId(Long id) { this.id = id; @@ -176,7 +211,16 @@ public class ChildAssocImpl implements ChildAssoc */ private void setParent(Node parentNode) { - this.parent = parentNode; + refWriteLock.lock(); + try + { + this.parent = parentNode; + this.childAssocRef = null; + } + finally + { + refWriteLock.unlock(); + } } public Node getChild() @@ -189,7 +233,16 @@ public class ChildAssocImpl implements ChildAssoc */ private void setChild(Node node) { - child = node; + refWriteLock.lock(); + try + { + child = node; + this.childAssocRef = null; + } + finally + { + refWriteLock.unlock(); + } } public QName getTypeQName() @@ -199,7 +252,16 @@ public class ChildAssocImpl implements ChildAssoc public void setTypeQName(QName typeQName) { - this.typeQName = typeQName; + refWriteLock.lock(); + try + { + this.typeQName = typeQName; + this.childAssocRef = null; + } + finally + { + refWriteLock.unlock(); + } } public QName getQname() @@ -209,7 +271,16 @@ public class ChildAssocImpl implements ChildAssoc public void setQname(QName qname) { - this.qName = qname; + refWriteLock.lock(); + try + { + this.qName = qname; + this.childAssocRef = null; + } + finally + { + refWriteLock.unlock(); + } } public boolean getIsPrimary() @@ -219,7 +290,16 @@ public class ChildAssocImpl implements ChildAssoc public void setIsPrimary(boolean isPrimary) { - this.isPrimary = isPrimary; + refWriteLock.lock(); + try + { + this.isPrimary = isPrimary; + this.childAssocRef = null; + } + finally + { + refWriteLock.unlock(); + } } public int getIndex() @@ -229,6 +309,15 @@ public class ChildAssocImpl implements ChildAssoc public void setIndex(int index) { - this.index = index; + refWriteLock.lock(); + try + { + this.index = index; + this.childAssocRef = null; + } + finally + { + refWriteLock.unlock(); + } } } diff --git a/source/java/org/alfresco/repo/domain/hibernate/NodeAssocImpl.java b/source/java/org/alfresco/repo/domain/hibernate/NodeAssocImpl.java index b69f1a5376..be3897e152 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/NodeAssocImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/NodeAssocImpl.java @@ -16,6 +16,10 @@ */ package org.alfresco.repo.domain.hibernate; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; + import org.alfresco.repo.domain.Node; import org.alfresco.repo.domain.NodeAssoc; import org.alfresco.service.cmr.repository.AssociationRef; @@ -33,10 +37,16 @@ public class NodeAssocImpl implements NodeAssoc private Node source; private Node target; private QName typeQName; + + private transient ReadLock refReadLock; + private transient WriteLock refWriteLock; private transient AssociationRef nodeAssocRef; public NodeAssocImpl() { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + refReadLock = lock.readLock(); + refWriteLock = lock.writeLock(); } public void buildAssociation(Node sourceNode, Node targetNode) @@ -62,15 +72,39 @@ public class NodeAssocImpl implements NodeAssoc this.getTarget().getSourceNodeAssocs().remove(this); } - public synchronized AssociationRef getNodeAssocRef() + public AssociationRef getNodeAssocRef() { - if (nodeAssocRef == null) + // first check if it is available + refReadLock.lock(); + try { - nodeAssocRef = new AssociationRef(getSource().getNodeRef(), - this.typeQName, - getTarget().getNodeRef()); + if (nodeAssocRef != null) + { + return nodeAssocRef; + } + } + finally + { + refReadLock.unlock(); + } + // get write lock + refWriteLock.lock(); + try + { + // double check + if (nodeAssocRef == null ) + { + nodeAssocRef = new AssociationRef( + getSource().getNodeRef(), + this.typeQName, + getTarget().getNodeRef()); + } + return nodeAssocRef; + } + finally + { + refWriteLock.unlock(); } - return nodeAssocRef; } public String toString() @@ -133,7 +167,16 @@ public class NodeAssocImpl implements NodeAssoc */ private void setSource(Node source) { - this.source = source; + refWriteLock.lock(); + try + { + this.source = source; + this.nodeAssocRef = null; + } + finally + { + refWriteLock.unlock(); + } } public Node getTarget() @@ -146,7 +189,16 @@ public class NodeAssocImpl implements NodeAssoc */ private void setTarget(Node target) { - this.target = target; + refWriteLock.lock(); + try + { + this.target = target; + this.nodeAssocRef = null; + } + finally + { + refWriteLock.unlock(); + } } public QName getTypeQName() @@ -156,6 +208,15 @@ public class NodeAssocImpl implements NodeAssoc public void setTypeQName(QName typeQName) { - this.typeQName = typeQName; + refWriteLock.lock(); + try + { + this.typeQName = typeQName; + this.nodeAssocRef = null; + } + finally + { + refWriteLock.unlock(); + } } }