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;
}
}