Moved key column from access_control_list onto node

This eliminates several select statements issued while walking up the parent hierarchy
The V1.2.1 - V1.3 script has been updated and tested, but if you want to keep an existing 1.3, then:
  SET FOREIGN_KEY_CHECKS = 0;
  ALTER TABLE node ADD `acl_id` bigint(20) default NULL;
  UPDATE node node SET node.acl_id = (SELECT acl.id FROM access_control_list acl WHERE acl.node_id = node.id);
  SET FOREIGN_KEY_CHECKS = 1;


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2910 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley 2006-05-17 15:24:31 +00:00
parent 272aad23f6
commit 516fc15cf4
6 changed files with 172 additions and 60 deletions

View File

@ -30,10 +30,6 @@ public interface DbAccessControlList
{
public long getId();
public Node getNode();
public void setNode(Node node);
/**
*
* @return Returns the access control entries for this access control list

View File

@ -26,8 +26,6 @@ import org.alfresco.repo.domain.DbAccessControlList;
import org.alfresco.repo.domain.DbAuthority;
import org.alfresco.repo.domain.DbPermission;
import org.alfresco.repo.domain.DbPermissionKey;
import org.alfresco.repo.domain.Node;
import org.alfresco.util.EqualsHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
@ -42,7 +40,6 @@ public class DbAccessControlListImpl extends LifecycleAdapter implements DbAcces
private static Log logger = LogFactory.getLog(DbAccessControlListImpl.class);
private long id;
private Node node;
private Set<DbAccessControlEntry> entries;
private boolean inherits;
@ -57,7 +54,6 @@ public class DbAccessControlListImpl extends LifecycleAdapter implements DbAcces
StringBuilder sb = new StringBuilder(128);
sb.append("DbAccessControlListImpl")
.append("[ id=").append(id)
.append(", node=").append(node)
.append(", entries=").append(entries.size())
.append(", inherits=").append(inherits)
.append("]");
@ -77,14 +73,13 @@ public class DbAccessControlListImpl extends LifecycleAdapter implements DbAcces
}
DbAccessControlList other = (DbAccessControlList) o;
return (this.inherits == other.getInherits())
&& (EqualsHelper.nullSafeEquals(this.node, other.getNode()));
return (this.inherits == other.getInherits());
}
@Override
public int hashCode()
{
return (node == null ? 0 : node.hashCode());
return (inherits == false ? 0 : 17);
}
public long getId()
@ -101,16 +96,6 @@ public class DbAccessControlListImpl extends LifecycleAdapter implements DbAcces
this.id = id;
}
public Node getNode()
{
return node;
}
public void setNode(Node node)
{
this.node = node;
}
public Set<DbAccessControlEntry> getEntries()
{
return entries;

View File

@ -28,6 +28,7 @@ import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.ChildAssoc;
import org.alfresco.repo.domain.DbAccessControlList;
import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.NodeAssoc;
import org.alfresco.repo.domain.NodeKey;
@ -35,12 +36,14 @@ import org.alfresco.repo.domain.NodeStatus;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.domain.Store;
import org.alfresco.repo.domain.StoreKey;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.BaseSpringTest;
import org.alfresco.util.GUID;
import org.hibernate.CacheMode;
import org.hibernate.exception.ConstraintViolationException;
/**
@ -385,6 +388,133 @@ public class HibernateNodeTest extends BaseSpringTest
{
txn.rollback();
}
}
/**
* Create some simple parent-child relationships and flush them. Then read them back in without
* using the L2 cache.
*/
public void testQueryJoins() throws Exception
{
getSession().setCacheMode(CacheMode.IGNORE);
// make a container node
Node containerNode = new NodeImpl();
containerNode.setStore(store);
containerNode.setUuid(GUID.generate());
containerNode.setTypeQName(ContentModel.TYPE_CONTAINER);
containerNode.getProperties().put(ContentModel.PROP_AUTHOR, new PropertyValue(DataTypeDefinition.TEXT, "ABC"));
containerNode.getProperties().put(ContentModel.PROP_ARCHIVED_BY, new PropertyValue(DataTypeDefinition.TEXT, "ABC"));
containerNode.getAspects().add(ContentModel.ASPECT_AUDITABLE);
Serializable containerNodeId = getSession().save(containerNode);
NodeKey containerNodeKey = new NodeKey(containerNode.getNodeRef());
NodeStatus containerNodeStatus = new NodeStatusImpl();
containerNodeStatus.setKey(containerNodeKey);
containerNodeStatus.setNode(containerNode);
containerNodeStatus.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
getSession().save(containerNodeStatus);
// make content node 1
Node contentNode1 = new NodeImpl();
contentNode1.setStore(store);
contentNode1.setUuid(GUID.generate());
contentNode1.setTypeQName(ContentModel.TYPE_CONTENT);
contentNode1.getProperties().put(ContentModel.PROP_AUTHOR, new PropertyValue(DataTypeDefinition.TEXT, "ABC"));
contentNode1.getProperties().put(ContentModel.PROP_ARCHIVED_BY, new PropertyValue(DataTypeDefinition.TEXT, "ABC"));
contentNode1.getAspects().add(ContentModel.ASPECT_AUDITABLE);
Serializable contentNode1Id = getSession().save(contentNode1);
NodeKey contentNodeKey1 = new NodeKey(contentNode1.getNodeRef());
NodeStatus contentNodeStatus1 = new NodeStatusImpl();
contentNodeStatus1.setKey(contentNodeKey1);
contentNodeStatus1.setNode(contentNode1);
contentNodeStatus1.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
getSession().save(contentNodeStatus1);
// make content node 2
Node contentNode2 = new NodeImpl();
contentNode2.setStore(store);
contentNode2.setUuid(GUID.generate());
contentNode2.setTypeQName(ContentModel.TYPE_CONTENT);
Serializable contentNode2Id = getSession().save(contentNode2);
contentNode2.getProperties().put(ContentModel.PROP_AUTHOR, new PropertyValue(DataTypeDefinition.TEXT, "ABC"));
contentNode2.getProperties().put(ContentModel.PROP_ARCHIVED_BY, new PropertyValue(DataTypeDefinition.TEXT, "ABC"));
contentNode2.getAspects().add(ContentModel.ASPECT_AUDITABLE);
NodeKey contentNodeKey2 = new NodeKey(contentNode2.getNodeRef());
NodeStatus contentNodeStatus2 = new NodeStatusImpl();
contentNodeStatus2.setKey(contentNodeKey2);
contentNodeStatus2.setNode(contentNode2);
contentNodeStatus2.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
getSession().save(contentNodeStatus2);
// create an association to content 1
ChildAssoc assoc1 = new ChildAssocImpl();
assoc1.setIsPrimary(true);
assoc1.setTypeQName(QName.createQName(null, "type1"));
assoc1.setQname(QName.createQName(null, "number1"));
assoc1.buildAssociation(containerNode, contentNode1);
getSession().save(assoc1);
// create an association to content 2
ChildAssoc assoc2 = new ChildAssocImpl();
assoc2.setIsPrimary(true);
assoc2.setTypeQName(QName.createQName(null, "type2"));
assoc2.setQname(QName.createQName(null, "number2"));
assoc2.buildAssociation(containerNode, contentNode2);
getSession().save(assoc2);
// make sure that there are no entities cached in either L1 or L2
getSession().flush();
getSession().clear();
// now read the structure back in from the container down
containerNodeStatus = (NodeStatus) getSession().get(NodeStatusImpl.class, containerNodeKey);
containerNode = containerNodeStatus.getNode();
Collection<ChildAssoc> assocs = containerNode.getChildAssocs();
for (ChildAssoc assoc : assocs)
{
Node childNode = assoc.getChild();
Store store = childNode.getStore();
childNode.getAspects().size();
childNode.getProperties().size();
childNode.getParentAssocs().size();
childNode.getChildAssocs().size();
childNode.getSourceNodeAssocs().size();
childNode.getTargetNodeAssocs().size();
DbAccessControlList acl = childNode.getAccessControlList();
if (acl != null)
{
acl.getEntries().size();
}
}
// clear out again
getSession().clear();
// now remove a property from each child
containerNodeStatus = (NodeStatus) getSession().get(NodeStatusImpl.class, containerNodeKey);
containerNode = containerNodeStatus.getNode();
assocs = containerNode.getChildAssocs();
for (ChildAssoc assoc : assocs)
{
Node childNode = assoc.getChild();
PropertyValue removed = childNode.getProperties().remove(ContentModel.PROP_ARCHIVED_BY);
assertNotNull("Property was not present", removed);
}
// expect that just the specific property gets removed in the delete statement
getSession().flush();
getSession().clear();
// Create a second association to content 2
// create an association to content 2
containerNodeStatus = (NodeStatus) getSession().get(NodeStatusImpl.class, containerNodeKey);
containerNode = containerNodeStatus.getNode();
contentNodeStatus2 = (NodeStatus) getSession().get(NodeStatusImpl.class, contentNodeKey2);
contentNode2 = contentNodeStatus2.getNode();
ChildAssoc assoc3 = new ChildAssocImpl();
assoc3.setIsPrimary(false);
assoc3.setTypeQName(QName.createQName(null, "type3"));
assoc3.setQname(QName.createQName(null, "number3"));
assoc3.buildAssociation(containerNode, contentNode2); // check whether the children are pulled in for this
getSession().save(assoc3);
// flush it
getSession().flush();
getSession().clear();
}
}

View File

@ -38,14 +38,16 @@
<property name="uuid" column="uuid" type="string" length="36" />
</natural-id>
<property name="typeQName" column="type_qname" type="QName" length="255" not-null="true" />
<!-- inverse assoc to access control list -->
<one-to-one
<!-- forward assoc to access control list (optional) -->
<many-to-one
name="accessControlList"
class="org.alfresco.repo.domain.hibernate.DbAccessControlListImpl"
property-ref="node"
column="acl_id"
lazy="false"
fetch="join"
cascade="delete" />
unique="false"
not-null="false"
cascade="delete" />
<!-- forward assoc to properties -->
<map
name="properties"
@ -87,8 +89,8 @@
<set
name="parentAssocs"
inverse="true"
lazy="true"
fetch="select"
lazy="false"
fetch="join"
cascade="none"
optimistic-lock="true" >
<key column="child_node_id" />
@ -98,8 +100,8 @@
<set
name="childAssocs"
inverse="true"
lazy="true"
fetch="select"
lazy="false"
fetch="join"
cascade="none"
optimistic-lock="true" >
<key column="parent_node_id" />
@ -173,8 +175,8 @@
<many-to-one
name="parent"
class="org.alfresco.repo.domain.hibernate.NodeImpl"
lazy="false"
fetch="join"
lazy="proxy"
fetch="select"
optimistic-lock="true"
not-null="true" >
<column name="parent_node_id" />
@ -182,8 +184,8 @@
<!-- forward assoc to child node -->
<many-to-one
name="child"
lazy="false"
fetch="join"
lazy="proxy"
fetch="select"
class="org.alfresco.repo.domain.hibernate.NodeImpl"
optimistic-lock="true"
not-null="true" >

View File

@ -19,14 +19,6 @@
<generator class="native" />
</id>
<many-to-one
name="node"
class="org.alfresco.repo.domain.hibernate.NodeImpl"
unique="true"
not-null="true">
<column name="node_id" />
</many-to-one>
<set name="entries"
inverse="true"
lazy="false"

View File

@ -39,7 +39,6 @@ import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ParameterCheck;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
@ -98,7 +97,7 @@ public class PermissionsDaoComponentImpl extends HibernateDaoSupport implements
}
else
{
npe = createSimpleNodePermissionEntry(acl);
npe = createSimpleNodePermissionEntry(node);
}
// done
if (logger.isDebugEnabled())
@ -139,7 +138,6 @@ public class PermissionsDaoComponentImpl extends HibernateDaoSupport implements
private DbAccessControlList createAccessControlList(Node node)
{
DbAccessControlList acl = new DbAccessControlListImpl();
acl.setNode(node);
acl.setInherits(INHERIT_PERMISSIONS_DEFAULT);
getHibernateTemplate().save(acl);
@ -184,10 +182,10 @@ public class PermissionsDaoComponentImpl extends HibernateDaoSupport implements
DbAccessControlList acl = getAccessControlList(node, false);
if (acl != null)
{
// maintain referencial integrity
node.setAccessControlList(null);
// delete the access control list - it will cascade to the entries
getHibernateTemplate().delete(acl);
// maintain inverse
node.setAccessControlList(null);
}
}
@ -383,10 +381,10 @@ public class PermissionsDaoComponentImpl extends HibernateDaoSupport implements
DbAccessControlList acl = getAccessControlList(node, false);
if (acl != null)
{
// maintain referencial integrity
node.setAccessControlList(null);
// drop the list
getHibernateTemplate().delete(acl);
// update node
node.setAccessControlList(null);
}
// create the access control list
acl = createAccessControlList(node);
@ -452,25 +450,34 @@ public class PermissionsDaoComponentImpl extends HibernateDaoSupport implements
// Utility methods to create simple detached objects for the outside world
// We do not pass out the hibernate objects
private SimpleNodePermissionEntry createSimpleNodePermissionEntry(DbAccessControlList acl)
private SimpleNodePermissionEntry createSimpleNodePermissionEntry(Node node)
{
DbAccessControlList acl = node.getAccessControlList();
if (acl == null)
{
ParameterCheck.mandatory("acl", acl);
// there isn't an access control list for the node - spoof a null one
SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry(
node.getNodeRef(),
true,
Collections.<SimplePermissionEntry> emptySet());
return snpe;
}
else
{
Set<DbAccessControlEntry> entries = acl.getEntries();
SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry(
node.getNodeRef(),
acl.getInherits(),
createSimplePermissionEntries(node, entries));
return snpe;
}
Set<DbAccessControlEntry> entries = acl.getEntries();
SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry(
acl.getNode().getNodeRef(),
acl.getInherits(),
createSimplePermissionEntries(entries));
return snpe;
}
/**
* @param entries access control entries
* @return Returns a unique set of entries that can be given back to the outside world
*/
private Set<SimplePermissionEntry> createSimplePermissionEntries(Collection<DbAccessControlEntry> entries)
private Set<SimplePermissionEntry> createSimplePermissionEntries(Node node, Collection<DbAccessControlEntry> entries)
{
if (entries == null)
{
@ -481,20 +488,20 @@ public class PermissionsDaoComponentImpl extends HibernateDaoSupport implements
{
for (DbAccessControlEntry entry : entries)
{
spes.add(createSimplePermissionEntry(entry));
spes.add(createSimplePermissionEntry(node, entry));
}
}
return spes;
}
private static SimplePermissionEntry createSimplePermissionEntry(DbAccessControlEntry ace)
private static SimplePermissionEntry createSimplePermissionEntry(Node node, DbAccessControlEntry ace)
{
if (ace == null)
{
return null;
}
return new SimplePermissionEntry(
ace.getAccessControlList().getNode().getNodeRef(),
node.getNodeRef(),
createSimplePermissionReference(ace.getPermission()),
ace.getAuthority().getRecipient(),
ace.isAllowed() ? AccessStatus.ALLOWED : AccessStatus.DENIED);