From 1318a5204b5e7419bf393a6a03d8b450365348af Mon Sep 17 00:00:00 2001 From: Britt Park Date: Wed, 21 Jun 2006 13:07:42 +0000 Subject: [PATCH] Changed copy on write to occur during lookup, rather than after lookup. Much carnage, but it's way faster. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3172 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../java/org/alfresco/repo/avm/AVMNode.java | 7 -- .../org/alfresco/repo/avm/AVMNodeImpl.java | 41 --------- .../org/alfresco/repo/avm/AVMServiceTest.java | 2 + .../alfresco/repo/avm/AVMServiceTestBase.java | 8 +- .../org/alfresco/repo/avm/AVMStressTest.java | 6 +- .../org/alfresco/repo/avm/DirectoryNode.java | 19 +--- .../repo/avm/LayeredDirectoryNodeImpl.java | 91 +------------------ source/java/org/alfresco/repo/avm/Lookup.java | 69 +++++++++++--- .../repo/avm/PlainDirectoryNodeImpl.java | 48 +--------- .../org/alfresco/repo/avm/Repository.java | 6 +- .../org/alfresco/repo/avm/RepositoryImpl.java | 57 ++++++------ .../repo/avm/SimultaneousLoadTest.java | 2 +- .../alfresco/repo/avm/SuperRepository.java | 29 +++--- .../repo/avm/hibernate/HibernateTxn.java | 29 +++--- 14 files changed, 134 insertions(+), 280 deletions(-) diff --git a/source/java/org/alfresco/repo/avm/AVMNode.java b/source/java/org/alfresco/repo/avm/AVMNode.java index f9aab57580..a3953dfa97 100644 --- a/source/java/org/alfresco/repo/avm/AVMNode.java +++ b/source/java/org/alfresco/repo/avm/AVMNode.java @@ -58,13 +58,6 @@ interface AVMNode */ public void setVersionID(int version); - /** - * Perform a COW if required. - * @param lPath The lookup path. - * @return A 'copied' version of this node. - */ - public AVMNode copyOnWrite(Lookup lPath); - /** * Possibly copy ourselves. * @param lPath The Lookup for this node. diff --git a/source/java/org/alfresco/repo/avm/AVMNodeImpl.java b/source/java/org/alfresco/repo/avm/AVMNodeImpl.java index 3bdba7723a..70628c9493 100644 --- a/source/java/org/alfresco/repo/avm/AVMNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMNodeImpl.java @@ -148,47 +148,6 @@ abstract class AVMNodeImpl implements AVMNode, Serializable return (AVMNode)query.uniqueResult(); } - /** - * Perform a copy on write on this node and recursively - * up to the repository root. This is a template method - * which farms out work to possiblyCopy(). - * @param lPath The Lookup. - */ - public AVMNode copyOnWrite(Lookup lPath) - { - // Call the subclass's copy on write logic. - AVMNode newMe = possiblyCopy(lPath); - // No copying needed, so short circuit. - if (newMe == null) - { - return this; - } - String myName = lPath.getName(); - lPath.upCurrentNode(); - Repository repos = lPath.getRepository(); - newMe.setVersionID(repos.getNextVersionID()); - // Get our parent directory if we have one. - DirectoryNode parent = null; - if (!getIsRoot()) - { - parent = (DirectoryNode)lPath.getCurrentNode(); - } - if (parent != null) - { - // Recursive invocation. - DirectoryNode newParent = - (DirectoryNode)parent.copyOnWrite(lPath); - newParent.putChild(myName, newMe); - } - else // Null parent means root of repository. - { - repos.setNewRoot((DirectoryNode)newMe); - } - newMe.setRepository(repos); - newMe.setIsNew(true); - return newMe; - } - /** * Set the owning repository for this. * @param repo The owning repository. diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTest.java b/source/java/org/alfresco/repo/avm/AVMServiceTest.java index 751e4cccbe..a2e4ba85cb 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTest.java @@ -92,6 +92,7 @@ public class AVMServiceTest extends AVMServiceTestBase // assertEquals("foo", listing.get(1).getName()); // /layer/b should contain foo, bar, and baz. listing = fService.getDirectoryListing(-1, "main:/layer/b"); + System.out.println(recursiveList("main", -1, true)); assertEquals(3, listing.size()); // assertEquals("bar", listing.get(0).getName()); // assertEquals("baz", listing.get(1).getName()); @@ -1114,6 +1115,7 @@ public class AVMServiceTest extends AVMServiceTestBase catch (Exception e) { e.printStackTrace(System.err); + fail(); } } diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java b/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java index 293e91b090..8def33a099 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java @@ -50,7 +50,7 @@ public class AVMServiceTestBase extends TestCase @Override protected void setUp() throws Exception { - HibernateHelper.GetSessionFactory().getStatistics().setStatisticsEnabled(true); +// HibernateHelper.GetSessionFactory().getStatistics().setStatisticsEnabled(true); AVMServiceImpl service = new AVMServiceImpl(); service.setStorage("build/test-results/storage"); service.init(true); @@ -66,9 +66,9 @@ public class AVMServiceTestBase extends TestCase { long now = System.currentTimeMillis(); System.out.println("Timing: " + (now - fStartTime) + "ms"); - Statistics stats = HibernateHelper.GetSessionFactory().getStatistics(); - stats.logSummary(); - stats.clear(); +// Statistics stats = HibernateHelper.GetSessionFactory().getStatistics(); +// stats.logSummary(); +// stats.clear(); HibernateHelper.Reset(); } diff --git a/source/java/org/alfresco/repo/avm/AVMStressTest.java b/source/java/org/alfresco/repo/avm/AVMStressTest.java index bf85d0f514..1e2948681d 100644 --- a/source/java/org/alfresco/repo/avm/AVMStressTest.java +++ b/source/java/org/alfresco/repo/avm/AVMStressTest.java @@ -46,7 +46,7 @@ public class AVMStressTest extends AVMServiceTestBase System.out.println("Load time: " + (System.currentTimeMillis() - start)); List testers = new ArrayList(); List threads = new ArrayList(); - for (int i = 0; i < 1; i++) + for (int i = 0; i < 8; i++) { AVMTester tester = new AVMTester(400, // create file. @@ -74,12 +74,12 @@ public class AVMStressTest extends AVMServiceTestBase thread.start(); } int exited = 0; - while (exited != 1) + while (exited != 8) { try { Thread.sleep(2000); - for (int i = 0; i < 1; i++) + for (int i = 0; i < 8; i++) { if (threads.get(i) == null) { diff --git a/source/java/org/alfresco/repo/avm/DirectoryNode.java b/source/java/org/alfresco/repo/avm/DirectoryNode.java index 817830e787..e68e7f7535 100644 --- a/source/java/org/alfresco/repo/avm/DirectoryNode.java +++ b/source/java/org/alfresco/repo/avm/DirectoryNode.java @@ -56,28 +56,11 @@ interface DirectoryNode extends AVMNode */ public AVMNodeDescriptor lookupChild(AVMNodeDescriptor mine, String name); - /** - * Add a child node. Fails if child already exists. - * Copy is possible. - * @param name The name to give the child. - * @param child The child to add. - * @param The lookup path. - */ - public boolean addChild(String name, AVMNode child, Lookup lPath); - - /** - * Remove a child node. Fails if child does not exist. - * Copy is possible. - * @param name The name of the child to remove. - * @param lPath The lookup path. - */ - public boolean removeChild(String name, Lookup lPath); - /** * Remove a child directly. No copy is possible. * @param name The name of the child to remove. */ - public void rawRemoveChild(String name); + public void removeChild(String name); /** * Get a directory listing. diff --git a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java index ab1e638ef2..41336e0280 100644 --- a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java @@ -282,44 +282,6 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec } } - /** - * Add a child to this directory and possibly COW. - * @param name The name of the child to add. - * @param child The child to add. - * @param lPath The Lookup. - * @return Whether the child was successfully added. - */ - public boolean addChild(String name, AVMNode child, Lookup lPath) - { - if (getChild(name) != null) - { - return false; - } - if (getDeleted(name) == null) - { - try - { - Lookup lookup = SuperRepository.GetInstance().lookupDirectory(-1, getUnderlying(lPath)); - DirectoryNode dir = (DirectoryNode)lookup.getCurrentNode(); - if (dir.lookupChild(lookup, name, -1) != null) - { - return false; - } - } - catch (AVMException re) - { - if (re instanceof AVMCycleException) - { - throw re; - } - // Do nothing. - } - } - DirectoryNode toModify = (DirectoryNode)copyOnWrite(lPath); - toModify.putChild(name, child); - child.setRepository(lPath.getRepository()); - return true; - } /** * Does this node directly contain the indicated node. @@ -506,7 +468,7 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec * @param name The name of the child to remove. */ @SuppressWarnings("unchecked") - public void rawRemoveChild(String name) + public void removeChild(String name) { ChildEntry entry = getChild(name); if (entry != null) @@ -518,48 +480,6 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec SuperRepository.GetInstance().getSession().save(dc); } - /** - * Remove a child by name. Possibly COW. - * @param name The name of the child to remove. - * @param lPath The Lookup. - * @return Whether the child was successfully removed. - */ - @SuppressWarnings("unchecked") - public boolean removeChild(String name, Lookup lPath) - { - // Can't delete something that is already deleted. - if (getDeleted(name) != null) - { - return false; - } - ChildEntry entry = getChild(name); - if (entry == null) - { - // See if the name is seen via indirection. - try - { - Lookup lookup = SuperRepository.GetInstance().lookupDirectory(-1, getUnderlying(lPath)); - DirectoryNode dir = (DirectoryNode)lookup.getCurrentNode(); - if (dir.lookupChild(lookup, name, -1) == null) - { - return false; - } - } - catch (AVMException re) - { - if (re instanceof AVMCycleException) - { - throw re; - } - return false; - } - } - LayeredDirectoryNode toModify = - (LayeredDirectoryNode)copyOnWrite(lPath); - toModify.rawRemoveChild(name); - return true; - } - /** * Get the type of this node. * @return The type of this node. @@ -596,8 +516,7 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec public void turnPrimary(Lookup lPath) { String path = lPath.getCurrentIndirection(); - LayeredDirectoryNode toModify = (LayeredDirectoryNode)copyOnWrite(lPath); - toModify.rawSetPrimary(path); + rawSetPrimary(path); } /** @@ -606,8 +525,7 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec */ public void retarget(Lookup lPath, String target) { - LayeredDirectoryNode toModify = (LayeredDirectoryNode)copyOnWrite(lPath); - toModify.rawSetPrimary(target); + rawSetPrimary(target); } /** @@ -617,8 +535,7 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec */ public void uncover(Lookup lPath, String name) { - LayeredDirectoryNodeImpl toModify = (LayeredDirectoryNodeImpl)copyOnWrite(lPath); - DeletedChild dc = toModify.getDeleted(name); + DeletedChild dc = getDeleted(name); if (dc != null) { SuperRepository.GetInstance().getSession().delete(dc); diff --git a/source/java/org/alfresco/repo/avm/Lookup.java b/source/java/org/alfresco/repo/avm/Lookup.java index 5e2a75ed69..a1013d17cb 100644 --- a/source/java/org/alfresco/repo/avm/Lookup.java +++ b/source/java/org/alfresco/repo/avm/Lookup.java @@ -96,8 +96,10 @@ class Lookup * Add a new node to the lookup. * @param node The node to add. * @param name The name of the node in the path. + * @param write Whether this is in the context of + * a write operation. */ - public void add(AVMNode node, String name) + public void add(AVMNode node, String name, boolean write) { LookupComponent comp = new LookupComponent(); comp.setName(name); @@ -109,6 +111,8 @@ class Lookup } else { + // TODO The isDirectlyContained should be eliminated in favor of + // a cumulative state. if (fPosition >= 0 && (!((DirectoryNode)fComponents.get(fPosition).getNode()).directlyContains(node) || !isDirectlyContained())) { @@ -127,20 +131,7 @@ class Lookup } else { - String parentIndirection = fComponents.get(fPosition).getIndirection(); - if (parentIndirection == null) - { - System.out.println("Oink!"); - } - if (parentIndirection.endsWith("/")) // This currently is impossible because - // root dirs are always plain. - { - comp.setIndirection(parentIndirection + name); - } - else - { - comp.setIndirection(parentIndirection + "/" + name); - } + comp.setIndirection(computeIndirection(name)); } fLayeredYet = true; // Record the first layer seen. @@ -151,10 +142,58 @@ class Lookup } fLowestLayerIndex = fPosition + 1; } + // In a write context a plain directory contained in a layer will + // be copied so we will need to compute an indirection path. + else if (fLayeredYet && write) + { + comp.setIndirection(computeIndirection(name)); + } comp.setLowestLayerIndex(fLowestLayerIndex); comp.setLayered(fLayeredYet); fComponents.add(comp); fPosition++; + // If we are in a write context do copy on write. + if (write) + { + // Possibly copy. + node = node.possiblyCopy(this); + if (node == null) + { + return; + } + // Node was copied. + fComponents.get(fPosition).setNode(node); + if (fPosition == 0) + { + // Inform the repository of a new root. + fRepository.setNewRoot((DirectoryNode)node); + return; + } + // Not the root. Check if we are the top layer and insert this into it's parent. + if (fPosition == fTopLayerIndex) + { + fTopLayer = (LayeredDirectoryNode)node; + } + ((DirectoryNode)fComponents.get(fPosition - 1).getNode()).putChild(name, node); + } + } + + /** + * A helper for keeping track of indirection. + * @param name The name of the being added node. + * @return The indirection for the being added node. + */ + private String computeIndirection(String name) + { + String parentIndirection = fComponents.get(fPosition).getIndirection(); + if (parentIndirection.endsWith("/")) + { + return parentIndirection + name; + } + else + { + return parentIndirection + "/" + name; + } } /** diff --git a/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java index fbf3654949..7b36c1d8e9 100644 --- a/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java @@ -72,27 +72,6 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory } } - /** - * Add a child to this directory, possibly doing a copy. - * @param name The name of the child. - * @param child The child node. - * @param lPath The lookup path to this directory. - * @return Success or failure. - */ - public boolean addChild(String name, AVMNode child, Lookup lPath) - { - // No, if a child with the given name exists. Note that uniqueness - // of names is built into the AVM, as opposed to being configurable. - if (getChild(name) != null) - { - return false; - } - DirectoryNode toModify = (DirectoryNode)copyOnWrite(lPath); - toModify.putChild(name, child); - child.setRepository(lPath.getRepository()); - return true; - } - /** * Does this directory directly contain the given node. * @param node The node to check. @@ -187,7 +166,7 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory * @param name The name of the child to remove. */ @SuppressWarnings("unchecked") - public void rawRemoveChild(String name) + public void removeChild(String name) { ChildEntry entry = getChild(name); if (entry != null) @@ -196,24 +175,6 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory } } - /** - * Remove a child. Possibly copy. - * @param name The name of the child to remove. - * @param lPath The lookup path. - * @return Success or failure. - */ - public boolean removeChild(String name, Lookup lPath) - { - // Can't remove it if it's not there. - if (getChild(name) == null) - { - return false; - } - DirectoryNode toModify = (DirectoryNode)copyOnWrite(lPath); - toModify.rawRemoveChild(name); - return true; - } - /** * Put a new child node into this directory. No copy. * @param name The name of the child. @@ -294,9 +255,7 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory */ public void turnPrimary(Lookup lPath) { - LayeredDirectoryNode toModify = (LayeredDirectoryNode)copyOnWrite(lPath); - Lookup lookup = SuperRepository.GetInstance().lookup(-1, lPath.getRepresentedPath()); - toModify.rawSetPrimary(lookup.getCurrentIndirection()); + assert false : "Should never happen."; } /** @@ -306,8 +265,7 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory */ public void retarget(Lookup lPath, String target) { - LayeredDirectoryNode toModify = (LayeredDirectoryNode)copyOnWrite(lPath); - toModify.rawSetPrimary(target); + assert false : "Should never happen."; } /** diff --git a/source/java/org/alfresco/repo/avm/Repository.java b/source/java/org/alfresco/repo/avm/Repository.java index 19e8f80d52..649d1f8398 100644 --- a/source/java/org/alfresco/repo/avm/Repository.java +++ b/source/java/org/alfresco/repo/avm/Repository.java @@ -156,17 +156,19 @@ interface Repository * Lookup a node. * @param version The version to look under. * @param path The path to the node. + * @param write Whether this is in a write context. * @return A Lookup object. */ - public Lookup lookup(int version, String path); + public Lookup lookup(int version, String path, boolean write); /** * Lookup a directory. * @param version The version to look under. * @param path The path to the directory. + * @param write Whether this is in a write context. * @return A Lookup object. */ - public Lookup lookupDirectory(int version, String path); + public Lookup lookupDirectory(int version, String path, boolean write); /** * For a layered node, get its indirection. diff --git a/source/java/org/alfresco/repo/avm/RepositoryImpl.java b/source/java/org/alfresco/repo/avm/RepositoryImpl.java index 8b0fee98ac..6b31b3f002 100644 --- a/source/java/org/alfresco/repo/avm/RepositoryImpl.java +++ b/source/java/org/alfresco/repo/avm/RepositoryImpl.java @@ -147,7 +147,7 @@ class RepositoryImpl implements Repository, Serializable */ public void createDirectory(String path, String name) { - Lookup lPath = lookupDirectory(-1, path); + Lookup lPath = lookupDirectory(-1, path, true); // lPath.acquireLocks(); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); if (dir.lookupChild(lPath, name, -1) != null) @@ -168,7 +168,7 @@ class RepositoryImpl implements Repository, Serializable newDir = new PlainDirectoryNodeImpl(this); } newDir.setVersionID(getNextVersionID()); - dir.addChild(name, newDir, lPath); + dir.putChild(name, newDir); } /** @@ -180,7 +180,7 @@ class RepositoryImpl implements Repository, Serializable public void createLayeredDirectory(String srcPath, String dstPath, String name) { - Lookup lPath = lookupDirectory(-1, dstPath); + Lookup lPath = lookupDirectory(-1, dstPath, true); // lPath.acquireLocks(); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); if (dir.lookupChild(lPath, name, -1) != null) @@ -202,7 +202,7 @@ class RepositoryImpl implements Repository, Serializable // Otherwise we issue a brand new layer id. newDir.setLayerID(fSuper.issueLayerID()); } - dir.addChild(name, newDir, lPath); + dir.putChild(name, newDir); newDir.setVersionID(getNextVersionID()); } @@ -215,7 +215,7 @@ class RepositoryImpl implements Repository, Serializable */ public OutputStream createFile(String path, String name) { - Lookup lPath = lookupDirectory(-1, path); + Lookup lPath = lookupDirectory(-1, path, true); // lPath.acquireLocks(); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); if (dir.lookupChild(lPath, name, -1) != null) @@ -224,7 +224,7 @@ class RepositoryImpl implements Repository, Serializable } PlainFileNodeImpl file = new PlainFileNodeImpl(this); file.setVersionID(getNextVersionID()); - dir.addChild(name, file, lPath); + dir.putChild(name, file); return file.getContentForWrite().getOutputStream(); } @@ -236,7 +236,7 @@ class RepositoryImpl implements Repository, Serializable */ public void createLayeredFile(String srcPath, String dstPath, String name) { - Lookup lPath = lookupDirectory(-1, dstPath); + Lookup lPath = lookupDirectory(-1, dstPath, true); // lPath.acquireLocks(); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); if (dir.lookupChild(lPath, name, -1) != null) @@ -246,7 +246,7 @@ class RepositoryImpl implements Repository, Serializable // TODO Reexamine decision to not check validity of srcPath. LayeredFileNodeImpl newFile = new LayeredFileNodeImpl(srcPath, this); - dir.addChild(name, newFile, lPath); + dir.putChild(name, newFile); newFile.setVersionID(getNextVersionID()); } @@ -258,7 +258,7 @@ class RepositoryImpl implements Repository, Serializable */ public InputStream getInputStream(int version, String path) { - Lookup lPath = lookup(version, path); + Lookup lPath = lookup(version, path, false); AVMNode node = lPath.getCurrentNode(); if (node.getType() != AVMNodeType.PLAIN_FILE && node.getType() != AVMNodeType.LAYERED_FILE) @@ -278,7 +278,7 @@ class RepositoryImpl implements Repository, Serializable */ public Map getListing(int version, String path) { - Lookup lPath = lookupDirectory(version, path); + Lookup lPath = lookupDirectory(version, path, false); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); Map listing = dir.getListing(lPath); Map results = new TreeMap(); @@ -298,7 +298,7 @@ class RepositoryImpl implements Repository, Serializable */ public OutputStream getOutputStream(String path) { - Lookup lPath = lookup(-1, path); + Lookup lPath = lookup(-1, path, true); // lPath.acquireLocks(); AVMNode node = lPath.getCurrentNode(); if (node.getType() != AVMNodeType.PLAIN_FILE && @@ -307,9 +307,8 @@ class RepositoryImpl implements Repository, Serializable throw new AVMWrongTypeException("Not a file: " + path); } FileNode file = (FileNode)node; - file = (FileNode)file.copyOnWrite(lPath); FileContent content = file.getContentForWrite(); - return content.getOutputStream(); // TODO Do we really need fSuper? + return content.getOutputStream(); } /** @@ -326,7 +325,7 @@ class RepositoryImpl implements Repository, Serializable { throw new AVMException("Access denied: " + path); } - Lookup lPath = lookup(version, path); + Lookup lPath = lookup(version, path, write); // if (write) // { // lPath.acquireLocks(); @@ -341,7 +340,6 @@ class RepositoryImpl implements Repository, Serializable FileContent content = null; if (write) { - file = (FileNode)file.copyOnWrite(lPath); content = file.getContentForWrite(); } else @@ -359,14 +357,14 @@ class RepositoryImpl implements Repository, Serializable public void removeNode(String path, String name) { // TODO Are we double checking for existence? - Lookup lPath = lookupDirectory(-1, path); + Lookup lPath = lookupDirectory(-1, path, true); // lPath.acquireLocks(); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); if (dir.lookupChild(lPath, name, -1) == null) { throw new AVMNotFoundException("Does not exist: " + name); } - dir.removeChild(name, lPath); + dir.removeChild(name); } /** @@ -376,7 +374,7 @@ class RepositoryImpl implements Repository, Serializable */ public void uncover(String dirPath, String name) { - Lookup lPath = lookup(-1, dirPath); + Lookup lPath = lookup(-1, dirPath, true); // lPath.acquireLocks(); AVMNode node = lPath.getCurrentNode(); if (node.getType() != AVMNodeType.LAYERED_DIRECTORY) @@ -475,9 +473,10 @@ class RepositoryImpl implements Repository, Serializable * Lookup up a path. * @param version The version to look in. * @param path The path to look up. + * @param write Whether this is in the context of a write. * @return A Lookup object. */ - public Lookup lookup(int version, String path) + public Lookup lookup(int version, String path, boolean write) { // Make up a Lookup to hold the results. Lookup result = new Lookup(this, fName); @@ -507,7 +506,8 @@ class RepositoryImpl implements Repository, Serializable } // fSuper.getSession().lock(dir, LockMode.READ); // Add an entry for the root. - result.add(dir, ""); + result.add(dir, "", write); + dir = (DirectoryNode)result.getCurrentNode(); if (pathElements.length == 0) { return result; @@ -527,9 +527,9 @@ class RepositoryImpl implements Repository, Serializable { throw new AVMWrongTypeException("Not a directory: " + pathElements[i]); } - dir = (DirectoryNode)child; // fSuper.getSession().lock(dir, LockMode.READ); - result.add(dir, pathElements[i]); + result.add(child, pathElements[i], write); + dir = (DirectoryNode)result.getCurrentNode(); } // Now look up the last element. AVMNode child = dir.lookupChild(result, pathElements[pathElements.length - 1], version); @@ -538,7 +538,7 @@ class RepositoryImpl implements Repository, Serializable throw new AVMNotFoundException("Not found: " + pathElements[pathElements.length - 1]); } // fSuper.getSession().lock(child, LockMode.READ); - result.add(child, pathElements[pathElements.length - 1]); + result.add(child, pathElements[pathElements.length - 1], write); return result; } @@ -573,13 +573,14 @@ class RepositoryImpl implements Repository, Serializable * Lookup a node and insist that it is a directory. * @param version The version to look under. * @param path The path to the directory. + * @param write Whether this is in a write context. * @return A Lookup object. */ - public Lookup lookupDirectory(int version, String path) + public Lookup lookupDirectory(int version, String path, boolean write) { // Just do a regular lookup and assert that the last element // is a directory. - Lookup lPath = lookup(version, path); + Lookup lPath = lookup(version, path, write); if (lPath.getCurrentNode().getType() != AVMNodeType.PLAIN_DIRECTORY && lPath.getCurrentNode().getType() != AVMNodeType.LAYERED_DIRECTORY) { @@ -596,7 +597,7 @@ class RepositoryImpl implements Repository, Serializable */ public String getIndirectionPath(int version, String path) { - Lookup lPath = lookup(version, path); + Lookup lPath = lookup(version, path, false); AVMNode node = lPath.getCurrentNode(); if (node.getType() == AVMNodeType.LAYERED_DIRECTORY) { @@ -615,7 +616,7 @@ class RepositoryImpl implements Repository, Serializable */ public void makePrimary(String path) { - Lookup lPath = lookupDirectory(-1, path); + Lookup lPath = lookupDirectory(-1, path, true); // lPath.acquireLocks(); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); if (!lPath.isLayered()) @@ -632,7 +633,7 @@ class RepositoryImpl implements Repository, Serializable */ public void retargetLayeredDirectory(String path, String target) { - Lookup lPath = lookupDirectory(-1, path); + Lookup lPath = lookupDirectory(-1, path, true); // lPath.acquireLocks(); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); if (!lPath.isLayered()) diff --git a/source/java/org/alfresco/repo/avm/SimultaneousLoadTest.java b/source/java/org/alfresco/repo/avm/SimultaneousLoadTest.java index add30cc31d..803b2ac699 100644 --- a/source/java/org/alfresco/repo/avm/SimultaneousLoadTest.java +++ b/source/java/org/alfresco/repo/avm/SimultaneousLoadTest.java @@ -32,7 +32,7 @@ public class SimultaneousLoadTest extends AVMServiceTestBase { try { - int n = 16; + int n = 4; for (int i = 0; i < n; i++) { fService.createDirectory("main:/", "d" + i); diff --git a/source/java/org/alfresco/repo/avm/SuperRepository.java b/source/java/org/alfresco/repo/avm/SuperRepository.java index b9ce56279e..f774e7f1bc 100644 --- a/source/java/org/alfresco/repo/avm/SuperRepository.java +++ b/source/java/org/alfresco/repo/avm/SuperRepository.java @@ -201,13 +201,13 @@ class SuperRepository String [] pathParts = SplitPath(srcPath); Repository srcRepo = getRepositoryByName(pathParts[0], false); // fSession.get().lock(srcRepo, LockMode.READ); - Lookup sPath = srcRepo.lookup(version, pathParts[1]); + Lookup sPath = srcRepo.lookup(version, pathParts[1], false); // Lookup the destination directory. fLookupCount.set(1); pathParts = SplitPath(dstPath); Repository dstRepo = getRepositoryByName(pathParts[0], true); // fSession.get().lock(dstRepo, LockMode.UPGRADE); - Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1]); + Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true); // dPath.acquireLocks(); DirectoryNode dirNode = (DirectoryNode)dPath.getCurrentNode(); AVMNode srcNode = sPath.getCurrentNode(); @@ -235,7 +235,7 @@ class SuperRepository } dstNode.setVersionID(dstRepo.getNextVersionID()); dstNode.setAncestor(srcNode); - dirNode.addChild(name, dstNode, dPath); + dirNode.putChild(name, dstNode); } /** @@ -287,7 +287,7 @@ class SuperRepository String [] pathParts = SplitPath(srcPath); Repository srcRepo = getRepositoryByName(pathParts[0], true); // fSession.get().lock(srcRepo, LockMode.UPGRADE); - Lookup sPath = srcRepo.lookupDirectory(-1, pathParts[1]); + Lookup sPath = srcRepo.lookupDirectory(-1, pathParts[1], true); // sPath.acquireLocks(); DirectoryNode srcDir = (DirectoryNode)sPath.getCurrentNode(); AVMNode srcNode = srcDir.lookupChild(sPath, srcName, -1); @@ -299,7 +299,7 @@ class SuperRepository pathParts = SplitPath(dstPath); Repository dstRepo = getRepositoryByName(pathParts[0], true); // fSession.get().lock(dstRepo, LockMode.UPGRADE); - Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1]); + Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true); // dPath.acquireLocks(); DirectoryNode dstDir = (DirectoryNode)dPath.getCurrentNode(); AVMNode dstNode = dstDir.lookupChild(dPath, dstName, -1); @@ -385,14 +385,9 @@ class SuperRepository { dstNode = new PlainFileNodeImpl((PlainFileNode)srcNode, dstRepo); } - srcDir.removeChild(srcName, sPath); - fLookupCount.set(1); - pathParts = SplitPath(dstPath); - dPath = dstRepo.lookup(-1, pathParts[1]); -// dPath.acquireLocks(); - dstDir = (DirectoryNode)dPath.getCurrentNode(); + srcDir.removeChild(srcName); dstNode.setVersionID(dstRepo.getNextVersionID()); - dstDir.addChild(dstName, dstNode, dPath); + dstDir.putChild(dstName, dstNode); dstNode.setAncestor(srcNode); } @@ -674,8 +669,8 @@ class SuperRepository private Repository getRepositoryByName(String name, boolean write) { return (Repository)fSession.get().get(RepositoryImpl.class, - name, - write ? LockMode.UPGRADE : LockMode.READ); + name /* , + write ? LockMode.UPGRADE : LockMode.READ */); } /** @@ -711,7 +706,7 @@ class SuperRepository String [] pathParts = SplitPath(path); Repository rep = getRepositoryByName(pathParts[0], false); // fSession.get().lock(rep, LockMode.READ); - return rep.lookup(version, pathParts[1]); + return rep.lookup(version, pathParts[1], false); } /** @@ -746,14 +741,14 @@ class SuperRepository public Lookup lookupDirectory(int version, String path) { fLookupCount.set(fLookupCount.get() + 1); - if (fLookupCount.get() > 10) + if (fLookupCount.get() > 50) { throw new AVMCycleException("Cycle in lookup."); } String [] pathParts = SplitPath(path); Repository rep = getRepositoryByName(pathParts[0], false); // fSession.get().lock(rep, LockMode.READ); - return rep.lookupDirectory(version, pathParts[1]); + return rep.lookupDirectory(version, pathParts[1], false); } /** diff --git a/source/java/org/alfresco/repo/avm/hibernate/HibernateTxn.java b/source/java/org/alfresco/repo/avm/hibernate/HibernateTxn.java index 02ec92e0bc..412e8b5939 100644 --- a/source/java/org/alfresco/repo/avm/hibernate/HibernateTxn.java +++ b/source/java/org/alfresco/repo/avm/hibernate/HibernateTxn.java @@ -27,6 +27,7 @@ import org.hibernate.SessionFactory; import org.hibernate.StaleStateException; import org.hibernate.Transaction; import org.hibernate.exception.GenericJDBCException; +import org.hibernate.exception.LockAcquisitionException; /** * Helper for DAOs. @@ -106,26 +107,30 @@ public class HibernateTxn } // If we've lost a race or we've deadlocked, retry. if (t instanceof StaleStateException || - t instanceof GenericJDBCException) + t instanceof GenericJDBCException || + t instanceof LockAcquisitionException) { if (t instanceof StaleStateException) { System.err.println("Lost Race"); - continue; } - System.err.println("Deadlock"); - try + else { - long interval; - synchronized (fRandom) + System.err.println("Deadlock"); + try { - interval = fRandom.nextInt(1000); + long interval; + synchronized (fRandom) + { + interval = fRandom.nextInt(1000); + } + Thread.sleep(interval); + continue; + } + catch (InterruptedException ie) + { + // Do nothing. } - Thread.sleep(interval); - } - catch (InterruptedException ie) - { - // Do nothing. } continue; }