diff --git a/config/alfresco/avm-services-context.xml b/config/alfresco/avm-services-context.xml index 6551e39286..f95862fbc3 100644 --- a/config/alfresco/avm-services-context.xml +++ b/config/alfresco/avm-services-context.xml @@ -127,8 +127,11 @@ + + + - 200 + 50 @@ -169,6 +172,9 @@ + + + diff --git a/source/java/org/alfresco/filesys/avm/AVMSearchContext.java b/source/java/org/alfresco/filesys/avm/AVMSearchContext.java index 5aaf27f6e7..5af6e6c81c 100644 --- a/source/java/org/alfresco/filesys/avm/AVMSearchContext.java +++ b/source/java/org/alfresco/filesys/avm/AVMSearchContext.java @@ -252,7 +252,12 @@ public class AVMSearchContext extends SearchContext { // Search backwards from the current file int curFileIdx = m_fileIdx; - + + if (m_fileIdx >= m_fileList.length) + { + m_fileIdx = m_fileList.length - 1; + } + while ( m_fileIdx > 0) { // Check if the current file is the required search restart point diff --git a/source/java/org/alfresco/repo/avm/AVMCrawlTestP.java b/source/java/org/alfresco/repo/avm/AVMCrawlTestP.java index 2a64e7fc8c..f91fec6d1e 100644 --- a/source/java/org/alfresco/repo/avm/AVMCrawlTestP.java +++ b/source/java/org/alfresco/repo/avm/AVMCrawlTestP.java @@ -37,7 +37,7 @@ public class AVMCrawlTestP extends AVMServiceTestBase { int n = 2; // Number of Threads. int m = 4; // How many multiples of content to start with. - long runTime = 300000; // 5 minutes + long runTime = 600000; // 5 minutes fService.purgeAVMStore("main"); BulkLoader loader = new BulkLoader(); loader.setAvmService(fService); diff --git a/source/java/org/alfresco/repo/avm/AVMRepository.java b/source/java/org/alfresco/repo/avm/AVMRepository.java index 0cf12cd32f..b9a508d570 100644 --- a/source/java/org/alfresco/repo/avm/AVMRepository.java +++ b/source/java/org/alfresco/repo/avm/AVMRepository.java @@ -75,6 +75,11 @@ public class AVMRepository */ private Issuer fLayerIssuer; + /** + * The Lookup Cache instance. + */ + private LookupCache fLookupCache; + /** * Create a new one. */ @@ -101,6 +106,15 @@ public class AVMRepository { fLayerIssuer = layerIssuer; } + + /** + * Set the Lookup Cache instance. + * @param cache The instance to set. + */ + public void setLookupCache(LookupCache cache) + { + fLookupCache = cache; + } /** * Create a file. @@ -117,7 +131,9 @@ public class AVMRepository if (store == null) { throw new AVMNotFoundException("Store not found."); } - return store.createFile(pathParts[1], name); + fLookupCache.onWrite(pathParts[0]); + OutputStream out = store.createFile(pathParts[1], name); + return out; } finally { @@ -142,6 +158,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.createFile(pathParts[1], name, data); } finally @@ -166,6 +183,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.createDirectory(pathParts[1], name); } finally @@ -212,6 +230,7 @@ public class AVMRepository child = new PlainDirectoryNodeImpl(store); } dir.putChild(name, child); + fLookupCache.onWrite(pathParts[0]); return child.getDescriptor(parent.getPath(), name, parent.getIndirection()); } @@ -237,6 +256,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.createLayeredDirectory(srcPath, pathParts[1], name); } finally @@ -262,6 +282,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.createLayeredFile(srcPath, pathParts[1], name); } finally @@ -314,6 +335,7 @@ public class AVMRepository } if (version < 0) { + fLookupCache.onSnapshot(pathParts[0]); version = srcRepo.createSnapshot("Branch Snapshot", null); } sPath = srcRepo.lookup(version, pathParts[1], false, false); @@ -336,6 +358,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true); if (dPath == null) { @@ -392,7 +415,9 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } - return store.getOutputStream(pathParts[1]); + fLookupCache.onWrite(pathParts[0]); + OutputStream out = store.getOutputStream(pathParts[1]); + return out; } finally { @@ -441,7 +466,9 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found: " + pathParts[0]); } - return store.createContentWriter(pathParts[1]); + fLookupCache.onWrite(pathParts[0]); + ContentWriter writer = store.createContentWriter(pathParts[1]); + return writer; } finally { @@ -477,6 +504,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onDelete(pathParts[0]); sPath = srcRepo.lookupDirectory(-1, pathParts[1], true); if (sPath == null) { @@ -502,6 +530,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true); if (dPath == null) { @@ -620,6 +649,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.uncover(pathParts[1], name); } finally @@ -643,6 +673,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onSnapshot(repName); result.add(store.createSnapshot(null, null)); } return result; @@ -662,7 +693,9 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } - return store.createSnapshot(tag, description); + fLookupCache.onSnapshot(storeName); + int result = store.createSnapshot(tag, description); + return result; } /** @@ -681,6 +714,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onDelete(pathParts[0]); store.removeNode(pathParts[1], name); } finally @@ -702,6 +736,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onDelete(name); AVMNode root = store.getRoot(); root.setIsRoot(false); VersionRootDAO vrDAO = AVMDAOs.Instance().fVersionRootDAO; @@ -733,6 +768,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onDelete(name); store.purgeVersion(version); } @@ -1385,6 +1421,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.makePrimary(pathParts[1]); } finally @@ -1409,6 +1446,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.retargetLayeredDirectory(pathParts[1], target); } finally @@ -1464,6 +1502,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.setOpacity(pathParts[1], opacity); } finally @@ -1489,6 +1528,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.setNodeProperty(pathParts[1], name, value); } finally @@ -1513,6 +1553,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.setNodeProperties(pathParts[1], properties); } finally @@ -1588,6 +1629,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.deleteNodeProperty(pathParts[1], name); } finally @@ -1611,6 +1653,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.deleteNodeProperties(pathParts[1]); } finally @@ -1856,7 +1899,9 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } - return store.getContentDataForWrite(pathParts[1]); + fLookupCache.onWrite(pathParts[0]); + ContentData result = store.getContentDataForWrite(pathParts[1]); + return result; } finally { @@ -1880,6 +1925,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.setContentData(pathParts[1], data); } finally @@ -1913,6 +1959,7 @@ public class AVMRepository { throw new AVMNotFoundException("Node not found: " + from.getPath()); } + fLookupCache.onWrite(pathParts[0]); store.setMetaDataFrom(pathParts[1], fromNode); } finally @@ -1937,6 +1984,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.addAspect(pathParts[1], aspectName); } finally @@ -1986,6 +2034,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.removeAspect(pathParts[1], aspectName); } finally @@ -2036,6 +2085,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); store.setACL(pathParts[1], acl); } finally @@ -2087,6 +2137,7 @@ public class AVMRepository throw new AVMNotFoundException("Store not found."); } store.link(pathParts[1], name, toLink); + fLookupCache.onWrite(pathParts[0]); } finally { @@ -2134,6 +2185,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); Lookup lPath = store.lookup(-1, pathParts[1], true, false); AVMNode node = lPath.getCurrentNode(); if (node == null) @@ -2169,6 +2221,7 @@ public class AVMRepository { throw new AVMNotFoundException("Store not found."); } + fLookupCache.onWrite(pathParts[0]); // Just force a copy if needed by looking up in write mode. Lookup lPath = store.lookup(-1, pathParts[1], true, false); if (lPath == null) diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTest.java b/source/java/org/alfresco/repo/avm/AVMServiceTest.java index 91f2445f2f..a24f3e629c 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTest.java @@ -1052,6 +1052,8 @@ public class AVMServiceTest extends AVMServiceTestBase assertEquals("main", info.getNativeAVMStore().getName()); fService.createLayeredDirectory("layer:/alayer/b", "layer:/", "blayer"); fService.createSnapshot("layer", null, null); + System.err.println(recursiveList("main", -1, true)); + System.err.println(recursiveList("layer", -1, true)); info = fService.getLayeringInfo(-1, "layer:/blayer/c"); assertEquals("main", info.getNativeAVMStore().getName()); info = fService.getLayeringInfo(-1, "layer:/blayer/figs"); diff --git a/source/java/org/alfresco/repo/avm/Lookup.java b/source/java/org/alfresco/repo/avm/Lookup.java index 14156d3161..34b889c461 100644 --- a/source/java/org/alfresco/repo/avm/Lookup.java +++ b/source/java/org/alfresco/repo/avm/Lookup.java @@ -28,6 +28,11 @@ import java.util.List; */ class Lookup { + /** + * Is this lookup valid? + */ + private boolean fValid; + /** * The AVMStore. */ @@ -86,13 +91,24 @@ class Lookup public Lookup(Lookup other, AVMNodeDAO nodeDAO, AVMStoreDAO storeDAO) { + fValid = true; fAVMStore = storeDAO.getByName(other.fAVMStore.getName()); + if (fAVMStore == null) + { + fValid = false; + return; + } fStoreName = fAVMStore.getName(); fComponents = new ArrayList(); fLayeredYet = other.fLayeredYet; if (other.fTopLayer != null) { fTopLayer = (LayeredDirectoryNode)nodeDAO.getByID(other.fTopLayer.getId()); + if (fTopLayer == null) + { + fValid = false; + return; + } } fPosition = other.fPosition; fTopLayerIndex = other.fTopLayerIndex; @@ -105,8 +121,18 @@ class Lookup newComp.setName(comp.getName()); newComp.setIndirection(comp.getIndirection()); newComp.setNode(nodeDAO.getByID(comp.getNode().getId())); + if (newComp.getNode() == null) + { + fValid = false; + return; + } fComponents.add(newComp); } + fFinalStore = storeDAO.getByName(other.fFinalStore.getName()); + if (fFinalStore == null) + { + fValid = false; + } } /** @@ -116,6 +142,7 @@ class Lookup */ public Lookup(AVMStore store, String storeName) { + fValid = true; fAVMStore = store; fStoreName = storeName; fComponents = new ArrayList(); @@ -129,6 +156,14 @@ class Lookup fFinalStore = store; } + /** + * Is this a valid lookup? + */ + public boolean isValid() + { + return fValid; + } + // TODO This is badly in need of cleanup. /** * Add a new node to the lookup. diff --git a/source/java/org/alfresco/repo/avm/LookupCache.java b/source/java/org/alfresco/repo/avm/LookupCache.java index 538eee1180..6358d1c112 100644 --- a/source/java/org/alfresco/repo/avm/LookupCache.java +++ b/source/java/org/alfresco/repo/avm/LookupCache.java @@ -51,6 +51,11 @@ public class LookupCache */ private AVMNodeDAO fAVMNodeDAO; + /** + * Reference to the Store DAO. + */ + private AVMStoreDAO fAVMStoreDAO; + /** * Make one up. */ @@ -72,6 +77,15 @@ public class LookupCache fAVMNodeDAO = dao; } + /** + * Set the store dao. + * @param dao The dao to set. + */ + public void setAvmStoreDAO(AVMStoreDAO dao) + { + fAVMStoreDAO = dao; + } + /** * Set the maximum cache size. * @param maxSize @@ -165,6 +179,38 @@ public class LookupCache */ private synchronized Lookup findInCache(LookupKey key) { + Lookup found = fCache.get(key); + if (found != null) + { + Lookup result = new Lookup(found, fAVMNodeDAO, fAVMStoreDAO); + if (!result.isValid()) + { + fgLogger.error("Invalid entry in cache: " + key); + onRollback(); + return null; + } + updateCache(key, found); + return result; + } + // Alternatively for a read lookup a write can match. + if (!key.isWrite()) + { + LookupKey newKey = new LookupKey(key); + newKey.setWrite(true); + found = fCache.get(newKey); + if (found != null) + { + Lookup result = new Lookup(found, fAVMNodeDAO, fAVMStoreDAO); + if (!result.isValid()) + { + fgLogger.error("Invalid entry in cache: " + newKey); + onRollback(); + return null; + } + updateCache(newKey, found); + return result; + } + } return null; } diff --git a/source/java/org/alfresco/repo/avm/LookupKey.java b/source/java/org/alfresco/repo/avm/LookupKey.java index 0819e052cf..6e06c55db2 100644 --- a/source/java/org/alfresco/repo/avm/LookupKey.java +++ b/source/java/org/alfresco/repo/avm/LookupKey.java @@ -57,6 +57,15 @@ public class LookupKey fIncludeDeleted = includeDeleted; } + public LookupKey(LookupKey other) + { + fVersion = other.fVersion; + fPath = other.fPath; + fStoreName = other.fStoreName; + fWrite = other.fWrite; + fIncludeDeleted = other.fIncludeDeleted; + } + /** * Set the writeness of this key. */ @@ -125,6 +134,6 @@ public class LookupKey @Override public String toString() { - return fStoreName + ":" + fPath; + return fStoreName + ":" + fPath + "-" + fVersion + "-" + fWrite + "-" + fIncludeDeleted; } }