Factored the ancestor-descendent and merged from-to relationships

out of AVMNode.  Easier to get hibernate to do what I want and appears
to be a little more efficient as it removes several FK constraints
from a frequently updated table.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3137 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Britt Park
2006-06-18 21:35:17 +00:00
parent 606096011c
commit d3f6048fbc
8 changed files with 338 additions and 40 deletions

View File

@@ -19,6 +19,9 @@ package org.alfresco.repo.avm;
import java.io.Serializable;
import org.hibernate.Query;
import org.hibernate.Session;
/**
* Base class for all repository file system like objects.
* @author britt
@@ -35,16 +38,6 @@ abstract class AVMNodeImpl implements AVMNode, Serializable
*/
private int fVersionID;
/**
* The ancestor of this.
*/
private AVMNode fAncestor;
/**
* The node that was merged into this.
*/
private AVMNode fMergedFrom;
/**
* The Repository that owns this.
*/
@@ -87,8 +80,6 @@ abstract class AVMNodeImpl implements AVMNode, Serializable
{
fID = id;
fVersionID = -1;
fAncestor = null;
fMergedFrom = null;
fRepository = repo;
fIsRoot = false;
long time = System.currentTimeMillis();
@@ -107,7 +98,14 @@ abstract class AVMNodeImpl implements AVMNode, Serializable
*/
public void setAncestor(AVMNode ancestor)
{
fAncestor = ancestor;
if (ancestor == null)
{
return;
}
HistoryLinkImpl link = new HistoryLinkImpl();
link.setAncestor(ancestor);
link.setDescendent(this);
SuperRepository.GetInstance().getSession().save(link);
}
/**
@@ -116,7 +114,10 @@ abstract class AVMNodeImpl implements AVMNode, Serializable
*/
public AVMNode getAncestor()
{
return fAncestor;
Session sess = SuperRepository.GetInstance().getSession();
Query query = sess.createQuery("select hl.ancestor from HistoryLinkImpl hl where hl.descendent = :desc");
query.setEntity("desc", this);
return (AVMNode)query.uniqueResult();
}
/**
@@ -125,7 +126,14 @@ abstract class AVMNodeImpl implements AVMNode, Serializable
*/
public void setMergedFrom(AVMNode mergedFrom)
{
fMergedFrom = mergedFrom;
if (mergedFrom == null)
{
return;
}
MergeLinkImpl link = new MergeLinkImpl();
link.setMfrom(mergedFrom);
link.setMto(this);
SuperRepository.GetInstance().getSession().save(link);
}
/**
@@ -134,7 +142,10 @@ abstract class AVMNodeImpl implements AVMNode, Serializable
*/
public AVMNode getMergedFrom()
{
return fMergedFrom;
Session sess = SuperRepository.GetInstance().getSession();
Query query = sess.createQuery("select ml.mfrom from MergeLinkImpl ml where ml.mto = :to");
query.setEntity("to", this);
return (AVMNode)query.uniqueResult();
}
/**

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.avm;
/**
* Interface for the ancestor-descendent relationship.
* @author britt
*/
interface HistoryLink
{
/**
* Set the ancestor part of this.
* @param ancestor
*/
public void setAncestor(AVMNode ancestor);
/**
* Get the ancestor part of this.
* @return The ancestor.
*/
public AVMNode getAncestor();
/**
* Set the descendent part of this.
* @param descendent
*/
public void setDescendent(AVMNode descendent);
/**
* Get the descendent part of this.
* @return
*/
public AVMNode getDescendent();
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.avm;
import java.io.Serializable;
/**
* Holds a ancestor-descendent relationship.
* @author britt
*/
class HistoryLinkImpl implements HistoryLink, Serializable
{
private static final long serialVersionUID = -430859344980137718L;
/**
* The ancestor.
*/
private AVMNode fAncestor;
/**
* The descendent.
*/
private AVMNode fDescendent;
/**
* Set the ancestor part of this.
* @param ancestor
*/
public void setAncestor(AVMNode ancestor)
{
fAncestor = ancestor;
}
/**
* Get the ancestor part of this.
* @return The ancestor.
*/
public AVMNode getAncestor()
{
return fAncestor;
}
/**
* Set the descendent part of this.
* @param descendent
*/
public void setDescendent(AVMNode descendent)
{
fDescendent = descendent;
}
/**
* Get the descendent part of this.
* @return The descendent.
*/
public AVMNode getDescendent()
{
return fDescendent;
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.avm;
/**
* This is the interface for the merged from - to relationship.
* @author britt
*/
interface MergeLink
{
/**
* Set the from part.
* @param from
*/
public void setMfrom(AVMNode from);
/**
* Get the from part.
* @return The from part.
*/
public AVMNode getMfrom();
/**
* Set the to part.
* @param to
*/
public void setMto(AVMNode to);
/**
* Get the to part.
* @return The to part.
*/
public AVMNode getMto();
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.avm;
import java.io.Serializable;
/**
* This contains a single merged from-to relationship.
* @author britt
*/
class MergeLinkImpl implements MergeLink, Serializable
{
private static final long serialVersionUID = 6672271083042424944L;
/**
* The node that was merged from.
*/
private AVMNode fFrom;
/**
* The node that was merged to.
*/
private AVMNode fTo;
/**
* Set the from part.
* @param from
*/
public void setMfrom(AVMNode from)
{
fFrom = from;
}
/**
* Get the from part.
* @return The from part.
*/
public AVMNode getMfrom()
{
return fFrom;
}
/**
* Set the to part.
* @param to
*/
public void setMto(AVMNode to)
{
fTo = to;
}
/**
* Get the to part.
* @return The to part.
*/
public AVMNode getMto()
{
return fTo;
}
}

View File

@@ -184,6 +184,7 @@ class OrphanReaper implements Runnable
{
public void perform(Session session)
{
SuperRepository.GetInstance().setSession(session);
Query query = session.getNamedQuery("FindOrphans");
query.setMaxResults(fBatchSize);
List<AVMNode> nodes = (List<AVMNode>)query.list();
@@ -196,28 +197,48 @@ class OrphanReaper implements Runnable
for (AVMNode node : nodes)
{
// Save away the ancestor and merged from fields from this node.
AVMNode ancestor = node.getAncestor();
AVMNode mergedFrom = node.getMergedFrom();
// Get all the nodes that have this node as ancestor.
query = session.getNamedQuery("AVMNode.GetDescendents");
query.setEntity("node", node);
List<AVMNode> descendents = (List<AVMNode>)query.list();
for (AVMNode desc : descendents)
query = session.createQuery("from HistoryLinkImpl hl where hl.descendent = :desc");
query.setEntity("desc", node);
HistoryLink hlink = (HistoryLink)query.uniqueResult();
AVMNode ancestor = null;
if (hlink != null)
{
ancestor = hlink.getAncestor();
session.delete(hlink);
}
query = session.createQuery("from MergeLinkImpl ml where ml.mto = :to");
query.setEntity("to", node);
MergeLink mlink = (MergeLink)query.uniqueResult();
AVMNode mergedFrom = null;
if (mlink != null)
{
mergedFrom = mlink.getMfrom();
session.delete(mlink);
}
// Get all the nodes that have this node as ancestor.
query = session.getNamedQuery("HistoryLink.ByAncestor");
query.setEntity("node", node);
List<HistoryLink> links = (List<HistoryLink>)query.list();
for (HistoryLink link : links)
{
AVMNode desc = link.getDescendent();
desc.setAncestor(ancestor);
if (desc.getMergedFrom() == null)
{
desc.setMergedFrom(mergedFrom);
}
session.delete(link);
}
// Get all the nodes that have this node as mergedFrom
query = session.getNamedQuery("AVMNode.GetMergedTo");
query = session.getNamedQuery("MergeLink.ByFrom");
query.setEntity("merged", node);
List<AVMNode> merged = (List<AVMNode>)query.list();
for (AVMNode merge : merged)
List<MergeLink> mlinks = (List<MergeLink>)query.list();
for (MergeLink link : mlinks)
{
merge.setMergedFrom(ancestor);
link.getMto().setMergedFrom(ancestor);
session.delete(link);
}
session.flush();
node = AVMNodeUnwrapper.Unwrap(node);
// Extra work for directories.
if (node instanceof DirectoryNode)

View File

@@ -37,7 +37,7 @@ public class PurgeTest extends AVMServiceTestBase
setupBasicTree();
BulkLoader loader = new BulkLoader(fService);
long start = System.currentTimeMillis();
loader.recursiveLoad("source", "main:/");
loader.recursiveLoad("source/web", "main:/");
System.err.println("Load time: " + (System.currentTimeMillis() - start) + "ms");
fService.createSnapshot("main");
System.err.println("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");

View File

@@ -24,14 +24,6 @@
<version column="vers"
name="vers"
type="long"/>
<!-- BasicAttributes are attributes that pretty much all AVMNodes will
have. -->
<many-to-one name="ancestor" column="ancestor_id"
class="AVMNodeImpl"/>
<!-- Nothing does anything with this yet. We'll need it for
complete versioning semantics. -->
<many-to-one name="mergedFrom" column="merged_from"
class="AVMNodeImpl"/>
<!-- This should really be not null, but I haven't figured out
the right way to build the relation so that nullability constraints
won't cause violations in the db during saves. -->
@@ -174,6 +166,18 @@
column="parent_id"/>
</composite-id>
</class>
<class name="HistoryLinkImpl" proxy="HistoryLink" table="history_links">
<composite-id>
<key-many-to-one name="ancestor" class="AVMNodeImpl" column="ancestor"/>
<key-many-to-one name="descendent" class="AVMNodeImpl" column="descendent"/>
</composite-id>
</class>
<class name="MergeLinkImpl" proxy="MergeLink" table="merge_links">
<composite-id>
<key-many-to-one name="mfrom" class="AVMNodeImpl" column="mfrom"/>
<key-many-to-one name="mto" class="AVMNodeImpl" column="mto"/>
</composite-id>
</class>
<query name="ChildEntry.ByNameParent">
<![CDATA[
from ChildEntryImpl ce
@@ -210,14 +214,28 @@
</query>
<query name="AVMNode.GetDescendents">
<![CDATA[
from AVMNodeImpl an
where an.ancestor = :node
select hl.descendent
from HistoryLinkImpl hl
where hl.ancestor = :node
]]>
</query>
<query name="HistoryLink.ByAncestor">
<![CDATA[
from HistoryLinkImpl hl
where hl.ancestor = :node
]]>
</query>
<query name="AVMNode.GetMergedTo">
<![CDATA[
from AVMNodeImpl an
where an.mergedFrom = :merged
select ml.mto
from MergeLinkImpl ml
where ml.mfrom = :merged
]]>
</query>
<query name="MergeLink.ByFrom">
<![CDATA[
from MergeLinkImpl ml
where ml.mfrom = :merged
]]>
</query>
<query name="VersionRoot.GetVersionRoot">