From c6dfeb1c9de04cadb6819ecd4dcf93b5506c94e6 Mon Sep 17 00:00:00 2001 From: Britt Park Date: Mon, 26 Jun 2006 16:43:35 +0000 Subject: [PATCH] Added pessimistic locking in several places to shut down deadlocks. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3252 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../org/alfresco/repo/avm/AVMStressTest.java | 21 +++++++++++++++++-- .../java/org/alfresco/repo/avm/AVMTester.java | 12 +++++++++++ .../org/alfresco/repo/avm/DirectoryNode.java | 4 ++-- .../alfresco/repo/avm/DirectoryNodeImpl.java | 8 +++++-- .../repo/avm/LayeredDirectoryNodeImpl.java | 13 ++++++------ .../repo/avm/PlainDirectoryNodeImpl.java | 9 ++++---- .../org/alfresco/repo/avm/RepositoryImpl.java | 14 ++++++------- .../repo/avm/SimultaneousLoadTest.java | 6 +++--- .../alfresco/repo/avm/SuperRepository.java | 14 +++++++++---- .../repo/avm/hibernate/HibernateTxn.java | 2 +- 10 files changed, 72 insertions(+), 31 deletions(-) diff --git a/source/java/org/alfresco/repo/avm/AVMStressTest.java b/source/java/org/alfresco/repo/avm/AVMStressTest.java index 92a459f1c5..3f58b7d738 100644 --- a/source/java/org/alfresco/repo/avm/AVMStressTest.java +++ b/source/java/org/alfresco/repo/avm/AVMStressTest.java @@ -35,7 +35,7 @@ public class AVMStressTest extends AVMServiceTestBase { try { - int nCopies = 1; + int nCopies = 4; int nThreads = 8; BulkLoader loader = new BulkLoader(fService); long start = System.currentTimeMillis(); @@ -60,7 +60,7 @@ public class AVMStressTest extends AVMServiceTestBase 20, // modify file. 3200, // read file 10, // snapshot - 10000, // # ops + 1000, // # ops fService, "" + i); tester.refresh(); @@ -73,6 +73,7 @@ public class AVMStressTest extends AVMServiceTestBase thread.start(); } int exited = 0; + long sampStart = System.currentTimeMillis(); while (exited != nThreads) { try @@ -99,6 +100,22 @@ public class AVMStressTest extends AVMServiceTestBase exited++; } } + /* + long now = System.currentTimeMillis(); + if (now - sampStart > 30000) + { + System.err.println("RATE: " + (((long)AVMTester.GetCount()) * 1000 / (now - sampStart))); + for (AVMTester tester : testers) + { + tester.setExit(); + } + for (Thread thread : threads) + { + thread.join(); + } + fail(); + } + */ } catch (InterruptedException e) { diff --git a/source/java/org/alfresco/repo/avm/AVMTester.java b/source/java/org/alfresco/repo/avm/AVMTester.java index 5e544b87e7..755625bb4b 100644 --- a/source/java/org/alfresco/repo/avm/AVMTester.java +++ b/source/java/org/alfresco/repo/avm/AVMTester.java @@ -51,6 +51,7 @@ class AVMTester implements Runnable private List fAllFiles; private static boolean fgFrozen = false; + private static int fgOpCount = 0; /** * The operation table. @@ -239,6 +240,7 @@ class AVMTester implements Runnable snapshot(); break; } + IncCount(); } System.out.println(fAllPaths.size() + " fses in " + (System.currentTimeMillis() - startTime) + "ms"); @@ -615,4 +617,14 @@ class AVMTester implements Runnable { return fAllPaths.get(fgRandom.nextInt(fAllPaths.size())); } + + private static synchronized void IncCount() + { + ++fgOpCount; + } + + public static synchronized int GetCount() + { + return fgOpCount; + } } diff --git a/source/java/org/alfresco/repo/avm/DirectoryNode.java b/source/java/org/alfresco/repo/avm/DirectoryNode.java index e68e7f7535..a8cc07c454 100644 --- a/source/java/org/alfresco/repo/avm/DirectoryNode.java +++ b/source/java/org/alfresco/repo/avm/DirectoryNode.java @@ -44,9 +44,9 @@ interface DirectoryNode extends AVMNode * @param lPath The Lookup so far. * @param name The name of the child to lookup. * @param version The version to look under. - * @param visited A Set of full paths visited. Used for cycle checking. + * @param write Whether this is occuring in a write context. */ - public AVMNode lookupChild(Lookup lPath, String name, int version); + public AVMNode lookupChild(Lookup lPath, String name, int version, boolean write); /** * Lookup a child node using an AVMNodeDescriptor as context. diff --git a/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java index 33ffbe0a28..d9f4c33ce3 100644 --- a/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java @@ -19,6 +19,7 @@ package org.alfresco.repo.avm; import java.util.List; +import org.hibernate.LockMode; import org.hibernate.Query; import org.hibernate.Session; @@ -49,13 +50,16 @@ abstract class DirectoryNodeImpl extends AVMNodeImpl implements DirectoryNode /** * Retrieves the ChildEntry in this directory with the given name. * @param name The name to look for. + * @param write Whether the child should be looked up for writing. * @return The ChildEntry or null if not found. */ @SuppressWarnings("unchecked") - protected ChildEntry getChild(String name) + protected ChildEntry getChild(String name, boolean write) { Session sess = SuperRepository.GetInstance().getSession(); - return (ChildEntry)sess.get(ChildEntryImpl.class, new ChildEntryImpl(name, this, null)); + ChildEntry entry = (ChildEntry)sess.get(ChildEntryImpl.class, new ChildEntryImpl(name, this, null), + (write && getIsNew()) ? LockMode.UPGRADE : LockMode.READ); + return entry; } /** diff --git a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java index f12c23980a..818dea9c57 100644 --- a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java @@ -381,17 +381,18 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec * @param lPath The Lookup. * @param name The name we are looking. * @param version The version in which we are looking. + * @param write Whether this lookup is occurring in a write context. * @return The child or null if not found. */ @SuppressWarnings("unchecked") - public AVMNode lookupChild(Lookup lPath, String name, int version) + public AVMNode lookupChild(Lookup lPath, String name, int version, boolean write) { // If the name has been deleted quickly return. if (getDeleted(name) != null) { return null; } - ChildEntry entry = getChild(name); + ChildEntry entry = getChild(name, write); if (entry != null) { return AVMNodeUnwrapper.Unwrap(entry.getChild()); @@ -401,7 +402,7 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec { Lookup lookup = SuperRepository.GetInstance().lookupDirectory(-1, getUnderlying(lPath)); DirectoryNode dir = (DirectoryNode)lookup.getCurrentNode(); - return dir.lookupChild(lookup, name, -1); + return dir.lookupChild(lookup, name, -1, false); } catch (AVMException re) { @@ -429,7 +430,7 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec { return null; } - ChildEntry entry = getChild(name); + ChildEntry entry = getChild(name, false); if (entry != null) { return entry.getChild().getDescriptor(mine.getPath(), @@ -440,7 +441,7 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec { Lookup lookup = SuperRepository.GetInstance().lookupDirectory(-1, mine.getIndirection()); DirectoryNode dir = (DirectoryNode)lookup.getCurrentNode(); - AVMNode child = dir.lookupChild(lookup, name, -1); + AVMNode child = dir.lookupChild(lookup, name, -1, false); if (child == null) { return null; @@ -464,7 +465,7 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec @SuppressWarnings("unchecked") public void removeChild(String name) { - ChildEntry entry = getChild(name); + ChildEntry entry = getChild(name, true); if (entry != null) { SuperRepository.GetInstance().getSession().delete(entry); diff --git a/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java index 762ca933cd..7dbb573a62 100644 --- a/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java @@ -126,14 +126,15 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory * @param lPath The lookup path so far. * @param name The name to lookup. * @param version The version to look under. + * @param write Whether this is in a write context. * @return The child or null. */ @SuppressWarnings("unchecked") - public AVMNode lookupChild(Lookup lPath, String name, int version) + public AVMNode lookupChild(Lookup lPath, String name, int version, boolean write) { // We're doing the hand unrolling of the proxy because // Hibernate/CGLIB proxies are broken. - ChildEntry entry = getChild(name); + ChildEntry entry = getChild(name, write); if (entry == null) { return null; @@ -153,7 +154,7 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory { throw new AVMBadArgumentException("Path is null."); } - ChildEntry entry = getChild(name); + ChildEntry entry = getChild(name, false); if (entry == null) { return null; @@ -168,7 +169,7 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory @SuppressWarnings("unchecked") public void removeChild(String name) { - ChildEntry entry = getChild(name); + ChildEntry entry = getChild(name, true); if (entry != null) { SuperRepository.GetInstance().getSession().delete(entry); diff --git a/source/java/org/alfresco/repo/avm/RepositoryImpl.java b/source/java/org/alfresco/repo/avm/RepositoryImpl.java index 8da14759c5..b00176affe 100644 --- a/source/java/org/alfresco/repo/avm/RepositoryImpl.java +++ b/source/java/org/alfresco/repo/avm/RepositoryImpl.java @@ -162,7 +162,7 @@ class RepositoryImpl implements Repository, Serializable Lookup lPath = lookupDirectory(-1, path, true); // lPath.acquireLocks(); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (dir.lookupChild(lPath, name, -1) != null) + if (dir.lookupChild(lPath, name, -1, true) != null) { throw new AVMExistsException("Child exists: " + name); } @@ -195,7 +195,7 @@ class RepositoryImpl implements Repository, Serializable Lookup lPath = lookupDirectory(-1, dstPath, true); // lPath.acquireLocks(); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (dir.lookupChild(lPath, name, -1) != null) + if (dir.lookupChild(lPath, name, -1, true) != null) { throw new AVMExistsException("Child exists: " + name); } @@ -230,7 +230,7 @@ class RepositoryImpl implements Repository, Serializable Lookup lPath = lookupDirectory(-1, path, true); // lPath.acquireLocks(); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (dir.lookupChild(lPath, name, -1) != null) + if (dir.lookupChild(lPath, name, -1, true) != null) { throw new AVMExistsException("Child exists: " + name); } @@ -251,7 +251,7 @@ class RepositoryImpl implements Repository, Serializable Lookup lPath = lookupDirectory(-1, dstPath, true); // lPath.acquireLocks(); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (dir.lookupChild(lPath, name, -1) != null) + if (dir.lookupChild(lPath, name, -1, true) != null) { throw new AVMExistsException("Child exists: " + name); } @@ -372,7 +372,7 @@ class RepositoryImpl implements Repository, Serializable Lookup lPath = lookupDirectory(-1, path, true); // lPath.acquireLocks(); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (dir.lookupChild(lPath, name, -1) == null) + if (dir.lookupChild(lPath, name, -1, true) == null) { throw new AVMNotFoundException("Does not exist: " + name); } @@ -528,7 +528,7 @@ class RepositoryImpl implements Repository, Serializable // before the end. for (int i = 0; i < pathElements.length - 1; i++) { - AVMNode child = dir.lookupChild(result, pathElements[i], version); + AVMNode child = dir.lookupChild(result, pathElements[i], version, write); if (child == null) { throw new AVMNotFoundException("Not found: " + pathElements[i]); @@ -544,7 +544,7 @@ class RepositoryImpl implements Repository, Serializable dir = (DirectoryNode)result.getCurrentNode(); } // Now look up the last element. - AVMNode child = dir.lookupChild(result, pathElements[pathElements.length - 1], version); + AVMNode child = dir.lookupChild(result, pathElements[pathElements.length - 1], version, write); if (child == null) { throw new AVMNotFoundException("Not found: " + pathElements[pathElements.length - 1]); diff --git a/source/java/org/alfresco/repo/avm/SimultaneousLoadTest.java b/source/java/org/alfresco/repo/avm/SimultaneousLoadTest.java index 0866edc3dd..daf52e9c77 100644 --- a/source/java/org/alfresco/repo/avm/SimultaneousLoadTest.java +++ b/source/java/org/alfresco/repo/avm/SimultaneousLoadTest.java @@ -32,8 +32,8 @@ public class SimultaneousLoadTest extends AVMServiceTestBase { try { - int n = 8; - int m = 1; + int n = 1; + int m = 8; for (int i = 0; i < n; i++) { fService.createDirectory("main:/", "d" + i); @@ -42,7 +42,7 @@ public class SimultaneousLoadTest extends AVMServiceTestBase Thread [] threads = new Thread[n]; for (int i = 0; i < n; i++) { - Loader loader = new Loader("/Users/britt/stuff/" + i, "main:/d" + i, m); + Loader loader = new Loader("source", "main:/d" + i, m); threads[i] = new Thread(loader); threads[i].start(); } diff --git a/source/java/org/alfresco/repo/avm/SuperRepository.java b/source/java/org/alfresco/repo/avm/SuperRepository.java index 750b138e5e..478c033ac5 100644 --- a/source/java/org/alfresco/repo/avm/SuperRepository.java +++ b/source/java/org/alfresco/repo/avm/SuperRepository.java @@ -298,7 +298,7 @@ class SuperRepository Lookup sPath = srcRepo.lookupDirectory(-1, pathParts[1], true); // sPath.acquireLocks(); DirectoryNode srcDir = (DirectoryNode)sPath.getCurrentNode(); - AVMNode srcNode = srcDir.lookupChild(sPath, srcName, -1); + AVMNode srcNode = srcDir.lookupChild(sPath, srcName, -1, true); if (srcNode == null) { throw new AVMNotFoundException("Not found: " + srcName); @@ -310,7 +310,7 @@ class SuperRepository Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true); // dPath.acquireLocks(); DirectoryNode dstDir = (DirectoryNode)dPath.getCurrentNode(); - AVMNode dstNode = dstDir.lookupChild(dPath, dstName, -1); + AVMNode dstNode = dstDir.lookupChild(dPath, dstName, -1, true); if (dstNode != null) { throw new AVMExistsException("Node exists: " + dstName); @@ -422,6 +422,7 @@ class SuperRepository for (String repName : repositories) { Repository repo = getRepositoryByName(repName, true); + fSession.get().lock(repo, LockMode.UPGRADE); // fSession.get().lock(repo, LockMode.UPGRADE); repo.createSnapshot(); } @@ -434,6 +435,7 @@ class SuperRepository public void createSnapshot(String repository) { Repository repo = getRepositoryByName(repository, true); + fSession.get().lock(repo, LockMode.UPGRADE); // fSession.get().lock(repo, LockMode.UPGRADE); repo.createSnapshot(); } @@ -694,12 +696,16 @@ class SuperRepository private Repository getRepositoryByName(String name, boolean write) { Repository rep = (Repository)fSession.get().get(RepositoryImpl.class, - name /* , - write ? LockMode.UPGRADE : LockMode.READ */); + name, LockMode.READ /*, + write ? LockMode.UPGRADE : LockMode.READ*/); if (rep == null) { throw new AVMNotFoundException("Repository not found: " + name); } + if (write && !rep.getRoot().getIsNew()) + { + fSession.get().lock(rep, LockMode.UPGRADE); + } return rep; } diff --git a/source/java/org/alfresco/repo/avm/hibernate/HibernateTxn.java b/source/java/org/alfresco/repo/avm/hibernate/HibernateTxn.java index 2742565755..608e3af20a 100644 --- a/source/java/org/alfresco/repo/avm/hibernate/HibernateTxn.java +++ b/source/java/org/alfresco/repo/avm/hibernate/HibernateTxn.java @@ -88,7 +88,7 @@ public class HibernateTxn } */ sess = fSessionFactory.openSession(); - sess.setFlushMode(FlushMode.ALWAYS); +// sess.setFlushMode(FlushMode.ALWAYS); txn = sess.beginTransaction(); callback.perform(sess); txn.commit();