Merged V2.1 to HEAD

6486: Fix for AWC-1134 (Made minimum length for username and password configurable)
   6487: Added "copy.verbose" property to build script to list all files being copied in the 'deploy-tomcat-exploded' and 'deploy-webclient-changes' targets
   6488: Changed default CIFS server to remove underscore as it can cause problems with OpenOffice.
   6489: Fix for WCM-498 (Expired items that are deleted are not represented as such in the change request dialog or submit dialog)
   6490: Fix for WCM-446 and WCM-624. Multi-select and All operations in Modified Files list respect items in workflow and ignore them.
   6491: Fixes profoundly brain dead behavior in AVMLockingService.init().
   6492: Refactoring of LookupCache to be clustering compatible
   6493: Staging and locking changes
   6494: WCM Revert action moved to end of all action lists to avoid accidently clicking it (as it has no confirmation screen!)
   6496: Fixes for WCM-746 and WCM-747 - Edit File Properties and Edit Folder Properties working correctly again for AVM objects.
   6497: Enable virtualization server to be (re)started at any point prior or during the startup of the alfresco webapp (fixes WCM-750).
   6498: WCM-742 - moving locks from the preview sandbox to the main user sandbox.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@6739 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2007-09-10 23:15:37 +00:00
parent 7a522e4b88
commit 1b272d6766
17 changed files with 1011 additions and 1224 deletions

View File

@@ -146,14 +146,8 @@
<property name="avmStoreDAO"> <property name="avmStoreDAO">
<ref bean="avmStoreDAO"/> <ref bean="avmStoreDAO"/>
</property> </property>
<property name="maxSize"> <property name="transactionalCache">
<value>50</value> <ref bean="lookupTransactionalCache"/>
</property>
</bean>
<bean id="lookupCacheListener" class="org.alfresco.repo.avm.AVMLookupCacheListener">
<property name="lookupCache">
<ref bean="lookupCache"/>
</property> </property>
</bean> </bean>
@@ -290,6 +284,9 @@
<property name="avmSyncService"> <property name="avmSyncService">
<ref bean="AVMSyncService" /> <ref bean="AVMSyncService" />
</property> </property>
<property name="avmLockingAwareService">
<ref bean="AVMLockingAwareService" />
</property>
<property name="nodeService"> <property name="nodeService">
<ref bean="NodeService" /> <ref bean="NodeService" />
</property> </property>

View File

@@ -244,7 +244,36 @@
<value>10</value> <value>10</value>
</property> </property>
</bean> </bean>
<!-- Transactional caches setup for LookupCache -->
<bean name="lookupSharedCache" class="org.alfresco.repo.cache.EhCacheAdapter">
<property name="cache">
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref bean="internalEHCacheManager"/>
</property>
<property name="cacheName">
<value>org.alfresco.repo.avm.lookupSharedCache</value>
</property>
</bean>
</property>
</bean>
<bean name="lookupTransactionalCache" class="org.alfresco.repo.cache.TransactionalCache">
<property name="sharedCache">
<ref bean="lookupSharedCache"/>
</property>
<property name="cacheManager">
<ref bean="transactionalEHCacheManager"/>
</property>
<property name="name">
<value>org.alfresco.repo.avm.lookupTransactionalCache</value>
</property>
<property name="maxCacheSize">
<value>50</value>
</property>
</bean>
<!-- ===================================== --> <!-- ===================================== -->
<!-- Messages Caches --> <!-- Messages Caches -->
<!-- ===================================== --> <!-- ===================================== -->

View File

@@ -2,7 +2,7 @@
<config evaluator="string-compare" condition="CIFS Server"> <config evaluator="string-compare" condition="CIFS Server">
<serverEnable enabled="true"/> <serverEnable enabled="true"/>
<host name="${localname}_A"/> <host name="${localname}A"/>
<comment>Alfresco CIFS Server</comment> <comment>Alfresco CIFS Server</comment>
<!-- Set to the broadcast mask for the subnet --> <!-- Set to the broadcast mask for the subnet -->

View File

@@ -795,9 +795,6 @@
<property name="avmRepository"> <property name="avmRepository">
<ref bean="avmRepository"/> <ref bean="avmRepository"/>
</property> </property>
<property name="transactionListener">
<ref bean="lookupCacheListener"/>
</property>
</bean> </bean>
<bean id="avmServiceReadTxnAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <bean id="avmServiceReadTxnAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">

View File

@@ -48,6 +48,7 @@ import org.alfresco.sandbox.SandboxConstants;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.alfresco.service.cmr.avm.locking.AVMLockingService;
import org.alfresco.service.cmr.avmsync.AVMSyncService; import org.alfresco.service.cmr.avmsync.AVMSyncService;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -86,6 +87,7 @@ public class AVMExpiredContentProcessor
protected Map<String, Map<String, List<String>>> expiredContent; protected Map<String, Map<String, List<String>>> expiredContent;
protected AVMService avmService; protected AVMService avmService;
protected AVMSyncService avmSyncService; protected AVMSyncService avmSyncService;
protected AVMService avmLockingAwareService;
protected NodeService nodeService; protected NodeService nodeService;
protected WorkflowService workflowService; protected WorkflowService workflowService;
protected PersonService personService; protected PersonService personService;
@@ -157,6 +159,11 @@ public class AVMExpiredContentProcessor
{ {
this.searchService = searchService; this.searchService = searchService;
} }
public void setAvmLockingAwareService(AVMService avmLockingAwareService)
{
this.avmLockingAwareService = avmLockingAwareService;
}
/** /**
* Executes the expired content processor. * Executes the expired content processor.
@@ -305,7 +312,7 @@ public class AVMExpiredContentProcessor
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("Examining expiration date for '" + nodePath + "': " + logger.debug("Examining expiration date for '" + nodePath + "': " +
expirationDateProp.getStringValue()); expirationDateProp);
if (expirationDateProp != null) if (expirationDateProp != null)
{ {
@@ -465,10 +472,10 @@ public class AVMExpiredContentProcessor
String path = workflowStoreName + ":/" + JNDIConstants.DIR_DEFAULT_WWW + String path = workflowStoreName + ":/" + JNDIConstants.DIR_DEFAULT_WWW +
"/" + JNDIConstants.DIR_DEFAULT_APPBASE; "/" + JNDIConstants.DIR_DEFAULT_APPBASE;
// DNS name mangle the property name - can only contain value DNS characters! // DNS name mangle the property name - can only contain value DNS characters!
String dnsProp = SandboxConstants.PROP_DNS + DNSNameMangler.MakeDNSName(userStore, packageName); String dnsProp = SandboxConstants.PROP_DNS + DNSNameMangler.MakeDNSName(stagingStore, packageName);
this.avmService.setStoreProperty(workflowStoreName, QName.createQName(null, dnsProp), this.avmService.setStoreProperty(workflowStoreName, QName.createQName(null, dnsProp),
new PropertyValue(DataTypeDefinition.TEXT, path)); new PropertyValue(DataTypeDefinition.TEXT, path));
// the main workflow store depends on the main user store (dist=1) // the main workflow store depends on the main user store (dist=1)
String prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + userStore; String prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + userStore;
this.avmService.setStoreProperty(workflowStoreName, QName.createQName(null, prop_key), this.avmService.setStoreProperty(workflowStoreName, QName.createQName(null, prop_key),
@@ -560,11 +567,10 @@ public class AVMExpiredContentProcessor
String pathInWorkflowStore = workflowStoreName + ":" + relPath; String pathInWorkflowStore = workflowStoreName + ":" + relPath;
// call forceCopy to make sure the path appears modified in the workflow // call forceCopy to make sure the path appears modified in the workflow
// sandbox, if the item is already modified or deleted this call has no // sandbox, if the item is already modified or deleted this call has no effect.
// effect. this.avmLockingAwareService.forceCopy(pathInWorkflowStore);
this.avmService.forceCopy(pathInWorkflowStore);
} }
// convert package to workflow package // convert package to workflow package
AVMNodeDescriptor packageDesc = avmService.lookup(-1, packagesPath); AVMNodeDescriptor packageDesc = avmService.lookup(-1, packagesPath);
NodeRef packageNodeRef = workflowService.createPackage( NodeRef packageNodeRef = workflowService.createPackage(

View File

@@ -1,53 +0,0 @@
/**
*
*/
package org.alfresco.repo.avm;
import org.alfresco.repo.transaction.TransactionListenerAdapter;
/**
* This is the listener that cleans up the lookup cache on transaction
* rollback.
* @author britt
*/
public class AVMLookupCacheListener extends TransactionListenerAdapter
{
/**
* The lookup cache.
*/
private LookupCache fLookupCache;
/**
* A default constructor.
*/
public AVMLookupCacheListener()
{
}
/**
* Set the Lookup Cache.
* @param lookupCache
*/
public void setLookupCache(LookupCache lookupCache)
{
fLookupCache = lookupCache;
}
/* (non-Javadoc)
* @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterRollback()
*/
@Override
public void afterRollback()
{
fLookupCache.onRollback();
}
/* (non-Javadoc)
* @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterCommit()
*/
@Override
public void afterCommit()
{
fLookupCache.onCommit();
}
}

View File

@@ -633,7 +633,6 @@ public class AVMRepository
{ {
throw new AVMNotFoundException("Store not found."); throw new AVMNotFoundException("Store not found.");
} }
fLookupCache.onDelete(pathParts[0]);
sPath = srcRepo.lookupDirectory(-1, pathParts[1], true); sPath = srcRepo.lookupDirectory(-1, pathParts[1], true);
if (sPath == null) if (sPath == null)
{ {
@@ -645,6 +644,7 @@ public class AVMRepository
{ {
throw new AVMNotFoundException("Not found: " + srcName); throw new AVMNotFoundException("Not found: " + srcName);
} }
fLookupCache.onDelete(pathParts[0]);
} }
finally finally
{ {
@@ -659,7 +659,6 @@ public class AVMRepository
{ {
throw new AVMNotFoundException("Store not found."); throw new AVMNotFoundException("Store not found.");
} }
fLookupCache.onWrite(pathParts[0]);
Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true); Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true);
if (dPath == null) if (dPath == null)
{ {
@@ -761,6 +760,7 @@ public class AVMRepository
{ {
dstNode.setAncestor(srcNode); dstNode.setAncestor(srcNode);
} }
fLookupCache.onWrite(pathParts[0]);
} }
finally finally
{ {
@@ -808,10 +808,10 @@ public class AVMRepository
{ {
throw new AVMNotFoundException("Store not found."); throw new AVMNotFoundException("Store not found.");
} }
fLookupCache.onSnapshot(storeName);
Map<String, Integer> result = store.createSnapshot(tag, description, new HashMap<String, Integer>()); Map<String, Integer> result = store.createSnapshot(tag, description, new HashMap<String, Integer>());
for (Map.Entry<String, Integer> entry : result.entrySet()) for (Map.Entry<String, Integer> entry : result.entrySet())
{ {
fLookupCache.onSnapshot(entry.getKey());
fCreateVersionTxnListener.versionCreated(entry.getKey(), entry.getValue()); fCreateVersionTxnListener.versionCreated(entry.getKey(), entry.getValue());
} }
return result; return result;
@@ -1639,18 +1639,33 @@ public class AVMRepository
*/ */
public Lookup lookupDirectory(int version, String path) public Lookup lookupDirectory(int version, String path)
{ {
fLookupCount.set(fLookupCount.get() + 1); Integer count = fLookupCount.get();
if (fLookupCount.get() > 50) try
{ {
throw new AVMCycleException("Cycle in lookup."); if (count == null)
{
fLookupCount.set(1);
}
fLookupCount.set(fLookupCount.get() + 1);
if (fLookupCount.get() > 50)
{
throw new AVMCycleException("Cycle in lookup.");
}
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
if (store == null)
{
return null;
}
return store.lookupDirectory(version, pathParts[1], false);
} }
String [] pathParts = SplitPath(path); finally
AVMStore store = getAVMStoreByName(pathParts[0]);
if (store == null)
{ {
return null; if (count == null)
{
fLookupCount.set(null);
}
} }
return store.lookupDirectory(version, pathParts[1], false);
} }
/** /**

View File

@@ -36,12 +36,12 @@ public class AVMScaleTestP extends AVMServiceTestBase
{ {
public void testScaling() public void testScaling()
{ {
int n = 4; // The number of BulkLoads to do. int n = 250; // The number of BulkLoads to do.
int futzCount = 10; // The number of post snapshot modifications to make after each load. int futzCount = 10; // The number of post snapshot modifications to make after each load.
String load = "/Users/britt/hibernate-3.1"; // The tree of stuff to load. String load = "/Users/britt/hibernate-3.1"; // The tree of stuff to load.
BulkLoader loader = new BulkLoader(); BulkLoader loader = new BulkLoader();
loader.setAvmService(fService); loader.setAvmService(fService);
loader.setPropertyCount(5); loader.setPropertyCount(50);
BulkReader reader = new BulkReader(); BulkReader reader = new BulkReader();
reader.setAvmService(fService); reader.setAvmService(fService);
long lastTime = System.currentTimeMillis(); long lastTime = System.currentTimeMillis();

View File

@@ -36,8 +36,6 @@ import java.util.SortedMap;
import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.domain.DbAccessControlList;
import org.alfresco.repo.domain.PropertyValue; import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionListener;
import org.alfresco.service.cmr.avm.AVMBadArgumentException; import org.alfresco.service.cmr.avm.AVMBadArgumentException;
import org.alfresco.service.cmr.avm.AVMException; import org.alfresco.service.cmr.avm.AVMException;
import org.alfresco.service.cmr.avm.AVMExistsException; import org.alfresco.service.cmr.avm.AVMExistsException;
@@ -72,8 +70,6 @@ public class AVMServiceImpl implements AVMService
*/ */
private AVMRepository fAVMRepository; private AVMRepository fAVMRepository;
private TransactionListener fTransactionListener;
/** /**
* Basic constructor for the service. * Basic constructor for the service.
*/ */
@@ -90,15 +86,6 @@ public class AVMServiceImpl implements AVMService
fAVMRepository = avmRepository; fAVMRepository = avmRepository;
} }
/**
* Set the transaction listener.
* @param transactionListener
*/
public void setTransactionListener(TransactionListener transactionListener)
{
fTransactionListener = transactionListener;
}
/** /**
* Get an InputStream from a file. * Get an InputStream from a file.
* @param version The version to look under. * @param version The version to look under.
@@ -139,7 +126,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Null path."); throw new AVMBadArgumentException("Null path.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
return fAVMRepository.getOutputStream(path); return fAVMRepository.getOutputStream(path);
} }
@@ -169,7 +155,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Null path."); throw new AVMBadArgumentException("Null path.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
return fAVMRepository.createContentWriter(path); return fAVMRepository.createContentWriter(path);
} }
@@ -361,7 +346,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal argument."); throw new AVMBadArgumentException("Illegal argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
return fAVMRepository.createFile(path, name); return fAVMRepository.createFile(path, name);
} }
@@ -378,7 +362,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal argument."); throw new AVMBadArgumentException("Illegal argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
// Save the contents to temp space. // Save the contents to temp space.
File temp; File temp;
try try
@@ -419,7 +402,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal argument."); throw new AVMBadArgumentException("Illegal argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.createDirectory(path, name); fAVMRepository.createDirectory(path, name);
} }
@@ -436,7 +418,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal argument."); throw new AVMBadArgumentException("Illegal argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.createLayeredFile(srcPath, parent, name); fAVMRepository.createLayeredFile(srcPath, parent, name);
} }
@@ -453,7 +434,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal argument."); throw new AVMBadArgumentException("Illegal argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.createLayeredDirectory(srcPath, parent, name); fAVMRepository.createLayeredDirectory(srcPath, parent, name);
} }
@@ -485,7 +465,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal argument."); throw new AVMBadArgumentException("Illegal argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.createBranch(version, srcPath, dstPath, name); fAVMRepository.createBranch(version, srcPath, dstPath, name);
} }
@@ -501,7 +480,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal null argument."); throw new AVMBadArgumentException("Illegal null argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.remove(parent, name); fAVMRepository.remove(parent, name);
} }
@@ -520,7 +498,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Cannot remove root node: " + path); throw new AVMBadArgumentException("Cannot remove root node: " + path);
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.remove(basePath[0], basePath[1]); fAVMRepository.remove(basePath[0], basePath[1]);
} }
@@ -539,7 +516,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal argument."); throw new AVMBadArgumentException("Illegal argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.rename(srcParent, srcName, dstParent, dstName); fAVMRepository.rename(srcParent, srcName, dstParent, dstName);
} }
@@ -554,7 +530,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal null argument."); throw new AVMBadArgumentException("Illegal null argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.uncover(dirPath, name); fAVMRepository.uncover(dirPath, name);
} }
@@ -570,7 +545,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal null argument."); throw new AVMBadArgumentException("Illegal null argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.flatten(dirPath, name); fAVMRepository.flatten(dirPath, name);
} }
@@ -616,7 +590,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Store is null."); throw new AVMBadArgumentException("Store is null.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
return fAVMRepository.createSnapshot(store, tag, description); return fAVMRepository.createSnapshot(store, tag, description);
} }
@@ -861,7 +834,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal null argument."); throw new AVMBadArgumentException("Illegal null argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.retargetLayeredDirectory(path, target); fAVMRepository.retargetLayeredDirectory(path, target);
} }
@@ -875,7 +847,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Path is null."); throw new AVMBadArgumentException("Path is null.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.makePrimary(path); fAVMRepository.makePrimary(path);
} }
@@ -967,7 +938,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Null path."); throw new AVMBadArgumentException("Null path.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.setOpacity(path, opacity); fAVMRepository.setOpacity(path, opacity);
} }
@@ -1018,7 +988,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal null argument."); throw new AVMBadArgumentException("Illegal null argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.setNodeProperty(path, name, value); fAVMRepository.setNodeProperty(path, name, value);
} }
@@ -1033,7 +1002,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal null argument."); throw new AVMBadArgumentException("Illegal null argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.setNodeProperties(path, properties); fAVMRepository.setNodeProperties(path, properties);
} }
@@ -1091,7 +1059,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal null argument."); throw new AVMBadArgumentException("Illegal null argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.deleteNodeProperty(path, name); fAVMRepository.deleteNodeProperty(path, name);
} }
@@ -1105,7 +1072,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Null path."); throw new AVMBadArgumentException("Null path.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.deleteNodeProperties(path); fAVMRepository.deleteNodeProperties(path);
} }
@@ -1208,7 +1174,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Invalid null argument."); throw new AVMBadArgumentException("Invalid null argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.deleteStoreProperty(store, name); fAVMRepository.deleteStoreProperty(store, name);
} }
@@ -1250,7 +1215,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Null Path."); throw new AVMBadArgumentException("Null Path.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
return fAVMRepository.getContentDataForWrite(path); return fAVMRepository.getContentDataForWrite(path);
} }
@@ -1268,7 +1232,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Null Path."); throw new AVMBadArgumentException("Null Path.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.setContentData(path, data); fAVMRepository.setContentData(path, data);
} }
@@ -1283,7 +1246,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal null argument."); throw new AVMBadArgumentException("Illegal null argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.setMetaDataFrom(path, from); fAVMRepository.setMetaDataFrom(path, from);
} }
@@ -1300,7 +1262,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal Null Argument."); throw new AVMBadArgumentException("Illegal Null Argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.addAspect(path, aspectName); fAVMRepository.addAspect(path, aspectName);
} }
@@ -1342,7 +1303,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Null path."); throw new AVMBadArgumentException("Null path.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.removeAspect(path, aspectName); fAVMRepository.removeAspect(path, aspectName);
} }
@@ -1374,7 +1334,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal Null Argument."); throw new AVMBadArgumentException("Illegal Null Argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.link(parentPath, name, toLink); fAVMRepository.link(parentPath, name, toLink);
} }
@@ -1388,7 +1347,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Null Path."); throw new AVMBadArgumentException("Null Path.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
return fAVMRepository.forceCopy(path); return fAVMRepository.forceCopy(path);
} }
@@ -1427,7 +1385,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal name."); throw new AVMBadArgumentException("Illegal name.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
AVMNodeDescriptor srcDesc = lookup(srcVersion, srcPath); AVMNodeDescriptor srcDesc = lookup(srcVersion, srcPath);
recursiveCopy(srcVersion, srcDesc, dstPath, name); recursiveCopy(srcVersion, srcDesc, dstPath, name);
} }
@@ -1508,7 +1465,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Cannot revert store root: " + path); throw new AVMBadArgumentException("Cannot revert store root: " + path);
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.revert(baseName[0], baseName[1], toRevertTo); fAVMRepository.revert(baseName[0], baseName[1], toRevertTo);
} }
@@ -1521,7 +1477,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal Null Argument."); throw new AVMBadArgumentException("Illegal Null Argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.setGuid(path, guid); fAVMRepository.setGuid(path, guid);
} }
@@ -1534,7 +1489,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal Null Argument."); throw new AVMBadArgumentException("Illegal Null Argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.setEncoding(path, encoding); fAVMRepository.setEncoding(path, encoding);
} }
@@ -1547,7 +1501,6 @@ public class AVMServiceImpl implements AVMService
{ {
throw new AVMBadArgumentException("Illegal Null Argument."); throw new AVMBadArgumentException("Illegal Null Argument.");
} }
AlfrescoTransactionSupport.bindListener(fTransactionListener);
fAVMRepository.setMimeType(path, mimeType); fAVMRepository.setMimeType(path, mimeType);
} }
} }

View File

@@ -347,136 +347,6 @@ public class AVMServiceTest extends AVMServiceTestBase
} }
/**
* Test async indexing.
* @throws Exception
*/
public void testAsyncIndex() throws Exception
{
// Make sure the slate is clean ...
UserTransaction tx = fTransactionService.getUserTransaction();
tx.begin();
if(fService.getStore("avmAsynchronousTest") != null)
{
assertTrue(fIndexingInterceptor.hasIndexBeenCreated("avmAsynchronousTest"));
fService.purgeStore("avmAsynchronousTest");
assertTrue(fIndexingInterceptor.hasIndexBeenCreated("avmAsynchronousTest"));
assertFalse(fIndexingInterceptor.hasIndexBeenCreated("bananaStoreWoof"));
}
else
{
assertFalse(fIndexingInterceptor.hasIndexBeenCreated("avmAsynchronousTest"));
}
StoreRef storeRef = AVMNodeConverter.ToStoreRef("avmAsynchronousTest");
Indexer indexer = fIndexerAndSearcher.getIndexer(storeRef);
if(indexer instanceof AVMLuceneIndexer)
{
AVMLuceneIndexer avmIndexer = (AVMLuceneIndexer)indexer;
avmIndexer.deleteIndex("avmAsynchronousTest", IndexMode.SYNCHRONOUS);
}
tx.commit();
tx = fTransactionService.getUserTransaction();
tx.begin();
assertEquals(-1, fIndexingInterceptor.getLastIndexedSnapshot("bananaStoreWoof"));
assertEquals(-1, fIndexingInterceptor.getLastIndexedSnapshot("avmAsynchronousTest"));
tx.commit();
// TODO: Suspend and resume indexing in case we are really unlucky and hit an index before we expect it.
SearchService searchService = fIndexerAndSearcher.getSearcher(storeRef, true);
ResultSet results;
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(0, results.length());
results.close();
fService.createStore("avmAsynchronousTest");
tx = fTransactionService.getUserTransaction();
tx.begin();
assertEquals(0, fIndexingInterceptor.getLastIndexedSnapshot("avmAsynchronousTest"));
tx.commit();
fService.createSnapshot("avmAsynchronousTest", null, null);
tx = fTransactionService.getUserTransaction();
tx.begin();
assertEquals(0, fIndexingInterceptor.getLastIndexedSnapshot("avmAsynchronousTest"));
tx.commit();
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(1, results.length());
results.close();
fService.createDirectory("avmAsynchronousTest:/", "a");
fService.createDirectory("avmAsynchronousTest:/a", "b");
fService.createDirectory("avmAsynchronousTest:/a/b", "c");
tx = fTransactionService.getUserTransaction();
tx.begin();
assertEquals(0, fIndexingInterceptor.getLastIndexedSnapshot("avmAsynchronousTest"));
assertTrue(fIndexingInterceptor.isIndexUpToDate("avmAsynchronousTest"));
tx.commit();
fService.createSnapshot("avmAsynchronousTest", null, null);
tx = fTransactionService.getUserTransaction();
tx.begin();
assertEquals(1, fIndexingInterceptor.getLastIndexedSnapshot("avmAsynchronousTest"));
assertTrue(fIndexingInterceptor.isIndexUpToDate("avmAsynchronousTest"));
assertFalse(fIndexingInterceptor.isIndexUpToDateAndSearchable("avmAsynchronousTest"));
assertEquals(IndexMode.ASYNCHRONOUS, fIndexingInterceptor.getIndexMode("avmAsynchronousTest"));
assertEquals(IndexMode.SYNCHRONOUS, fIndexingInterceptor.getIndexMode("main"));
assertTrue(fIndexingInterceptor.isSnapshotIndexed("avmAsynchronousTest", 0));
assertTrue(fIndexingInterceptor.isSnapshotIndexed("avmAsynchronousTest", 1));
assertFalse(fIndexingInterceptor.isSnapshotIndexed("avmAsynchronousTest", 2));
tx.commit();
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(1, results.length());
results.close();
Thread.sleep(180000);
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(4, results.length());
results.close();
tx = fTransactionService.getUserTransaction();
tx.begin();
assertEquals(1, fIndexingInterceptor.getLastIndexedSnapshot("avmAsynchronousTest"));
assertTrue(fIndexingInterceptor.isIndexUpToDate("avmAsynchronousTest"));
assertTrue(fIndexingInterceptor.isIndexUpToDateAndSearchable("avmAsynchronousTest"));
tx.commit();
fService.purgeStore("avmAsynchronousTest");
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(0, results.length());
results.close();
fService.createStore("avmAsynchronousTest");
fService.createSnapshot("avmAsynchronousTest", null, null);
fService.createDirectory("avmAsynchronousTest:/", "a");
fService.createDirectory("avmAsynchronousTest:/a", "b");
fService.createDirectory("avmAsynchronousTest:/a/b", "c");
fService.createSnapshot("avmAsynchronousTest", null, null);
fService.purgeStore("avmAsynchronousTest");
fService.createStore("avmAsynchronousTest");
fService.createSnapshot("avmAsynchronousTest", null, null);
fService.createDirectory("avmAsynchronousTest:/", "a");
fService.createDirectory("avmAsynchronousTest:/a", "b");
fService.createDirectory("avmAsynchronousTest:/a/b", "c");
fService.createSnapshot("avmAsynchronousTest", null, null);
Thread.sleep(180000);
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(4, results.length());
results.close();
}
public void testForceCopyDeleted() public void testForceCopyDeleted()
{ {
@@ -537,8 +407,16 @@ public class AVMServiceTest extends AVMServiceTestBase
fService.createBranch(1, "layer:/root", "branch:/", "branch"); fService.createBranch(1, "layer:/root", "branch:/", "branch");
fService.createSnapshot("branch", null, null); fService.createSnapshot("branch", null, null);
fService.getFileOutputStream("main:/a/b/c/foo").close(); fService.getFileOutputStream("main:/a/b/c/foo").close();
System.out.println("main 1");
System.out.println(recursiveList("main", 1, true));
System.out.println("branch 1");
System.out.println(recursiveList("branch", 1, true));
assertEquals(fService.lookup(1, "main:/a/b/c/foo").getId(), fService.lookup(1, assertEquals(fService.lookup(1, "main:/a/b/c/foo").getId(), fService.lookup(1,
"branch:/branch/layer/b/c/foo").getId()); "branch:/branch/layer/b/c/foo").getId());
System.out.println("main -1");
System.out.println(recursiveList("main", -1, true));
System.out.println("branch -1");
System.out.println(recursiveList("branch", -1, true));
assertEquals(fService.lookup(-1, "main:/a/b/c/foo").getId(), fService.lookup(-1, assertEquals(fService.lookup(-1, "main:/a/b/c/foo").getId(), fService.lookup(-1,
"branch:/branch/layer/b/c/foo").getId()); "branch:/branch/layer/b/c/foo").getId());
} }
@@ -5641,4 +5519,135 @@ public class AVMServiceTest extends AVMServiceTestBase
fail(); fail();
} }
} }
/**
* Test async indexing.
* @throws Exception
*/
public void testAsyncIndex() throws Exception
{
// Make sure the slate is clean ...
UserTransaction tx = fTransactionService.getUserTransaction();
tx.begin();
if(fService.getStore("avmAsynchronousTest") != null)
{
assertTrue(fIndexingInterceptor.hasIndexBeenCreated("avmAsynchronousTest"));
fService.purgeStore("avmAsynchronousTest");
assertTrue(fIndexingInterceptor.hasIndexBeenCreated("avmAsynchronousTest"));
assertFalse(fIndexingInterceptor.hasIndexBeenCreated("bananaStoreWoof"));
}
else
{
assertFalse(fIndexingInterceptor.hasIndexBeenCreated("avmAsynchronousTest"));
}
StoreRef storeRef = AVMNodeConverter.ToStoreRef("avmAsynchronousTest");
Indexer indexer = fIndexerAndSearcher.getIndexer(storeRef);
if(indexer instanceof AVMLuceneIndexer)
{
AVMLuceneIndexer avmIndexer = (AVMLuceneIndexer)indexer;
avmIndexer.deleteIndex("avmAsynchronousTest", IndexMode.SYNCHRONOUS);
}
tx.commit();
tx = fTransactionService.getUserTransaction();
tx.begin();
assertEquals(-1, fIndexingInterceptor.getLastIndexedSnapshot("bananaStoreWoof"));
assertEquals(-1, fIndexingInterceptor.getLastIndexedSnapshot("avmAsynchronousTest"));
tx.commit();
// TODO: Suspend and resume indexing in case we are really unlucky and hit an index before we expect it.
SearchService searchService = fIndexerAndSearcher.getSearcher(storeRef, true);
ResultSet results;
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(0, results.length());
results.close();
fService.createStore("avmAsynchronousTest");
tx = fTransactionService.getUserTransaction();
tx.begin();
assertEquals(0, fIndexingInterceptor.getLastIndexedSnapshot("avmAsynchronousTest"));
tx.commit();
fService.createSnapshot("avmAsynchronousTest", null, null);
tx = fTransactionService.getUserTransaction();
tx.begin();
assertEquals(0, fIndexingInterceptor.getLastIndexedSnapshot("avmAsynchronousTest"));
tx.commit();
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(1, results.length());
results.close();
fService.createDirectory("avmAsynchronousTest:/", "a");
fService.createDirectory("avmAsynchronousTest:/a", "b");
fService.createDirectory("avmAsynchronousTest:/a/b", "c");
tx = fTransactionService.getUserTransaction();
tx.begin();
assertEquals(0, fIndexingInterceptor.getLastIndexedSnapshot("avmAsynchronousTest"));
assertTrue(fIndexingInterceptor.isIndexUpToDate("avmAsynchronousTest"));
tx.commit();
fService.createSnapshot("avmAsynchronousTest", null, null);
tx = fTransactionService.getUserTransaction();
tx.begin();
assertEquals(1, fIndexingInterceptor.getLastIndexedSnapshot("avmAsynchronousTest"));
assertTrue(fIndexingInterceptor.isIndexUpToDate("avmAsynchronousTest"));
assertFalse(fIndexingInterceptor.isIndexUpToDateAndSearchable("avmAsynchronousTest"));
assertEquals(IndexMode.ASYNCHRONOUS, fIndexingInterceptor.getIndexMode("avmAsynchronousTest"));
assertEquals(IndexMode.SYNCHRONOUS, fIndexingInterceptor.getIndexMode("main"));
assertTrue(fIndexingInterceptor.isSnapshotIndexed("avmAsynchronousTest", 0));
assertTrue(fIndexingInterceptor.isSnapshotIndexed("avmAsynchronousTest", 1));
assertFalse(fIndexingInterceptor.isSnapshotIndexed("avmAsynchronousTest", 2));
tx.commit();
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(1, results.length());
results.close();
Thread.sleep(180000);
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(4, results.length());
results.close();
tx = fTransactionService.getUserTransaction();
tx.begin();
assertEquals(1, fIndexingInterceptor.getLastIndexedSnapshot("avmAsynchronousTest"));
assertTrue(fIndexingInterceptor.isIndexUpToDate("avmAsynchronousTest"));
assertTrue(fIndexingInterceptor.isIndexUpToDateAndSearchable("avmAsynchronousTest"));
tx.commit();
fService.purgeStore("avmAsynchronousTest");
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(0, results.length());
results.close();
fService.createStore("avmAsynchronousTest");
fService.createSnapshot("avmAsynchronousTest", null, null);
fService.createDirectory("avmAsynchronousTest:/", "a");
fService.createDirectory("avmAsynchronousTest:/a", "b");
fService.createDirectory("avmAsynchronousTest:/a/b", "c");
fService.createSnapshot("avmAsynchronousTest", null, null);
fService.purgeStore("avmAsynchronousTest");
fService.createStore("avmAsynchronousTest");
fService.createSnapshot("avmAsynchronousTest", null, null);
fService.createDirectory("avmAsynchronousTest:/", "a");
fService.createDirectory("avmAsynchronousTest:/a", "b");
fService.createDirectory("avmAsynchronousTest:/a/b", "c");
fService.createSnapshot("avmAsynchronousTest", null, null);
Thread.sleep(180000);
results = searchService.query(storeRef, "lucene", "PATH:\"//.\"");
assertEquals(4, results.length());
results.close();
}
} }

View File

@@ -24,7 +24,6 @@
package org.alfresco.repo.avm; package org.alfresco.repo.avm;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
@@ -39,9 +38,7 @@ import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.alfresco.service.cmr.avm.locking.AVMLockingService; import org.alfresco.service.cmr.avm.locking.AVMLockingService;
import org.alfresco.service.cmr.avmsync.AVMSyncService; import org.alfresco.service.cmr.avmsync.AVMSyncService;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow; import org.alfresco.service.cmr.search.ResultSetRow;
@@ -225,6 +222,7 @@ public class AVMServiceTestBase extends TestCase
Map<String, AVMNodeDescriptor> listing = fService.getDirectoryListing(version, path, true); Map<String, AVMNodeDescriptor> listing = fService.getDirectoryListing(version, path, true);
for (String name : listing.keySet()) for (String name : listing.keySet())
{ {
System.err.println(name);
builder.append(recursiveList(basename + name, version, indent + 2, followLinks)); builder.append(recursiveList(basename + name, version, indent + 2, followLinks));
} }
} }

View File

@@ -214,11 +214,20 @@ public class AVMStoreImpl implements AVMStore, Serializable
{ {
continue; continue;
} }
fAVMRepository.forceCopy(entry.getPath());
// TODO This leaves the behavior of LayeredFiles not quite
// right.
/*
String parentName[] = AVMNodeConverter.SplitBase(entry.getPath()); String parentName[] = AVMNodeConverter.SplitBase(entry.getPath());
parentName[0] = parentName[0].substring(parentName[0].indexOf(':') + 1); parentName[0] = parentName[0].substring(parentName[0].indexOf(':') + 1);
lookup = lookupDirectory(-1, parentName[0], true); lookup = lookupDirectory(-1, parentName[0], true);
DirectoryNode parent = (DirectoryNode)lookup.getCurrentNode(); DirectoryNode parent = (DirectoryNode)lookup.getCurrentNode();
AVMNode child = parent.lookupChild(lookup, parentName[1], false); AVMNode child = parent.lookupChild(lookup, parentName[1], false);
// TODO For debugging.
if (child == null)
{
System.err.println("Yoiks!");
}
// TODO This is funky. Need to look carefully to see that this call // TODO This is funky. Need to look carefully to see that this call
// does exactly what's needed. // does exactly what's needed.
lookup.add(child, parentName[1], false); lookup.add(child, parentName[1], false);
@@ -232,6 +241,7 @@ public class AVMStoreImpl implements AVMStore, Serializable
newChild = ((LayeredFileNode)child).copyLiterally(lookup); newChild = ((LayeredFileNode)child).copyLiterally(lookup);
} }
parent.putChild(parentName[1], newChild); parent.putChild(parentName[1], newChild);
*/
} }
// Clear out the new nodes. // Clear out the new nodes.
List<AVMNode> newInRep = AVMDAOs.Instance().fAVMNodeDAO.getNewInStore(this); List<AVMNode> newInRep = AVMDAOs.Instance().fAVMNodeDAO.getNewInStore(this);

View File

@@ -23,6 +23,7 @@
package org.alfresco.repo.avm; package org.alfresco.repo.avm;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -34,8 +35,10 @@ import org.alfresco.util.Pair;
* from the root directory of a repository. * from the root directory of a repository.
* @author britt * @author britt
*/ */
class Lookup class Lookup implements Serializable
{ {
private static final long serialVersionUID = -2844833688622561L;
/** /**
* Is this lookup valid? * Is this lookup valid?
*/ */

View File

@@ -3,14 +3,11 @@
*/ */
package org.alfresco.repo.avm; package org.alfresco.repo.avm;
import java.util.HashMap; import java.util.ArrayList;
import java.util.HashSet; import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import org.alfresco.repo.avm.util.SimplePath; import org.alfresco.repo.avm.util.SimplePath;
import org.alfresco.repo.cache.SimpleCache;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
/** /**
@@ -21,42 +18,10 @@ public class LookupCache
{ {
private static Logger fgLogger = Logger.getLogger(LookupCache.class); private static Logger fgLogger = Logger.getLogger(LookupCache.class);
/**
* Per transaction lookup results to be added to the cache on successful
* commit.
*/
private ThreadLocal<Map<LookupKey, Lookup>> fToBeAdded;
/**
* Per transaction set of invalidated lookup keys.
*/
private ThreadLocal<Set<LookupKey>> fToBePurged;
/** /**
* The Map of of keys to lookups. * The Map of of keys to lookups.
*/ */
private Map<LookupKey, Lookup> fCache; private SimpleCache<LookupKey, Lookup> fCache;
/**
* The Map of time stamps to keys.
*/
private SortedMap<Long, LookupKey> fTimeStamps;
/**
* The inverse map of keys to timestamps.
*/
private Map<LookupKey, Long> fInverseTimeStamps;
/**
* The timestamp to next issue.
*/
private long fTimeStamp;
/**
* The maximum number of lines to have in the cache.
*/
private int fMaxSize;
/** /**
* Reference to the Node DAO. * Reference to the Node DAO.
@@ -73,13 +38,6 @@ public class LookupCache
*/ */
public LookupCache() public LookupCache()
{ {
fCache = new HashMap<LookupKey, Lookup>();
fTimeStamps = new TreeMap<Long, LookupKey>();
fInverseTimeStamps = new HashMap<LookupKey, Long>();
fToBeAdded = new ThreadLocal<Map<LookupKey, Lookup>>();
fToBePurged = new ThreadLocal<Set<LookupKey>>();
fTimeStamp = 0L;
fMaxSize = 100;
} }
/** /**
@@ -100,13 +58,9 @@ public class LookupCache
fAVMStoreDAO = dao; fAVMStoreDAO = dao;
} }
/** public void setTransactionalCache(SimpleCache<LookupKey, Lookup> cache)
* Set the maximum cache size.
* @param maxSize
*/
public void setMaxSize(int maxSize)
{ {
fMaxSize = maxSize; fCache = cache;
} }
/** /**
@@ -125,8 +79,14 @@ public class LookupCache
LookupKey key = new LookupKey(version, path, store.getName(), write, includeDeleted); LookupKey key = new LookupKey(version, path, store.getName(), write, includeDeleted);
// Is it in the cache? // Is it in the cache?
Lookup found = findInCache(key); Lookup found = findInCache(key);
// TODO Testing.
// found = null;
if (found != null) if (found != null)
{ {
if (fgLogger.isDebugEnabled())
{
fgLogger.debug("Cache Hit: " + key + ", " + found.getCurrentNode().getId());
}
return found; return found;
} }
// Make up a Lookup to hold the results. // Make up a Lookup to hold the results.
@@ -155,7 +115,7 @@ public class LookupCache
dir = (DirectoryNode)result.getCurrentNode(); dir = (DirectoryNode)result.getCurrentNode();
if (path.size() == 1 && path.get(0).equals("")) if (path.size() == 1 && path.get(0).equals(""))
{ {
updateCache(key, result); fCache.put(key, result);
return result; return result;
} }
// Now look up each path element in sequence up to one // Now look up each path element in sequence up to one
@@ -184,7 +144,7 @@ public class LookupCache
return null; return null;
} }
result.add(child, path.get(path.size() - 1), write); result.add(child, path.get(path.size() - 1), write);
updateCache(key, result); fCache.put(key, result);
return result; return result;
} }
@@ -195,24 +155,7 @@ public class LookupCache
*/ */
private synchronized Lookup findInCache(LookupKey key) private synchronized Lookup findInCache(LookupKey key)
{ {
// Get the current transaction's purged set. Lookup found = fCache.get(key);
Set<LookupKey> purged = fToBePurged.get();
// Get the current transaction's added map.
Map<LookupKey, Lookup> added = fToBeAdded.get();
// See if it's cached in the transaction.
Lookup found = (added != null) ? added.get(key) : null;
// It's not.
if (found == null)
{
// If it's been purged in the transaction it is
// a miss.
if (purged != null && purged.contains(key))
{
return null;
}
found = fCache.get(key);
}
// Despite the odds, we found a hit.
if (found != null) if (found != null)
{ {
// Get a freshened Lookup. // Get a freshened Lookup.
@@ -224,8 +167,6 @@ public class LookupCache
fgLogger.error("Invalid entry in cache: " + key); fgLogger.error("Invalid entry in cache: " + key);
return null; return null;
} }
// Prepare the cache for a timestamp update on commit.
updateCache(key, found);
return result; return result;
} }
// Alternatively for a read lookup a write can match. // Alternatively for a read lookup a write can match.
@@ -234,18 +175,7 @@ public class LookupCache
// Make a copy of the key and set it to 'write' // Make a copy of the key and set it to 'write'
LookupKey newKey = new LookupKey(key); LookupKey newKey = new LookupKey(key);
newKey.setWrite(true); newKey.setWrite(true);
// Is it in the transaction's cache? found = fCache.get(newKey);
found = (added != null) ? added.get(newKey) : null;
// If not.
if (found == null)
{
// If it's been purged it's a miss.
if (purged != null && purged.contains(newKey))
{
return null;
}
found = fCache.get(newKey);
}
if (found != null) if (found != null)
{ {
// We found it. Make a freshened copy of the Lookup. // We found it. Make a freshened copy of the Lookup.
@@ -257,103 +187,12 @@ public class LookupCache
fgLogger.error("Invalid entry in cache: " + newKey); fgLogger.error("Invalid entry in cache: " + newKey);
return null; return null;
} }
// Prepare the cache to update time stamp.
updateCache(newKey, found);
return result; return result;
} }
} }
return null; return null;
} }
/**
* Add or update an entry in the cache.
* @param key
* @param lookup
*/
private void updateCache(LookupKey key, Lookup lookup)
{
// First, put it in the transaction scoped cache.
Map<LookupKey, Lookup> map = fToBeAdded.get();
if (map == null)
{
map = new HashMap<LookupKey, Lookup>();
}
map.put(key, lookup);
// Remove any corresponding entry from the purge list.
Set<LookupKey> purged = fToBePurged.get();
if (purged == null)
{
return;
}
purged.remove(key);
}
/**
* Called when a transaction has successfully committed,
* to make lookups from the transaction available to other transactions.
*/
public synchronized void onCommit()
{
// First get rid of all entries purged by the transaction.
Set<LookupKey> purged = fToBePurged.get();
if (purged != null)
{
purgeEntries(purged);
}
// Null out the thread local.
fToBePurged.set(null);
// Get and go through the transaction's added list.
Map<LookupKey, Lookup> added = fToBeAdded.get();
if (added == null)
{
return;
}
for (Map.Entry<LookupKey, Lookup> entry : added.entrySet())
{
LookupKey key = entry.getKey();
Lookup lookup = entry.getValue();
// If the cache already has the key, remove it.
if (fCache.containsKey(key))
{
fCache.remove(key);
Long oldTime = fInverseTimeStamps.get(key);
fInverseTimeStamps.remove(key);
fTimeStamps.remove(oldTime);
}
// Add the entry.
long timeStamp = fTimeStamp++;
fTimeStamps.put(timeStamp, key);
fInverseTimeStamps.put(key, timeStamp);
fCache.put(key, lookup);
// Check if we're over the limit and purge the
// LRU entry if we are.
if (fCache.size() > fMaxSize)
{
// Get rid of the oldest entry.
Long oldTime = fTimeStamps.firstKey();
LookupKey old = fTimeStamps.remove(oldTime);
fInverseTimeStamps.remove(old);
fCache.remove(old);
}
}
// Null out the ThreadLocal.
fToBeAdded.set(null);
}
/**
* Remove a Set of entries.
* @param keys The Set of entries.
*/
private void purgeEntries(Set<LookupKey> keys)
{
for (LookupKey key : keys)
{
fCache.remove(key);
Long time = fInverseTimeStamps.remove(key);
fTimeStamps.remove(time);
}
}
// Following are the cache invalidation calls. // Following are the cache invalidation calls.
/** /**
@@ -362,37 +201,25 @@ public class LookupCache
*/ */
public synchronized void onWrite(String storeName) public synchronized void onWrite(String storeName)
{ {
// Get or make up the purged Set for this transaction.
Set<LookupKey> purged = fToBePurged.get();
if (purged == null)
{
purged = new HashSet<LookupKey>();
fToBePurged.set(purged);
}
// Invalidate if it's a read lookup in the store, or // Invalidate if it's a read lookup in the store, or
// any read lookup is it's layered. // any read lookup is it's layered.
for (Map.Entry<LookupKey, Lookup> entry : fCache.entrySet()) List<LookupKey> keys = new ArrayList<LookupKey>();
for (LookupKey key : fCache.getKeys())
{ {
if ((entry.getKey().getStoreName().equals(storeName) && keys.add(key);
!entry.getKey().isWrite()) ||
(!entry.getKey().isWrite() && entry.getValue().isLayered()))
{
purged.add(entry.getKey());
}
} }
// Remove entries from the added set using the same criteria. for (LookupKey key : keys)
Map<LookupKey, Lookup> added = fToBeAdded.get();
if (added == null)
{ {
return; Lookup value = fCache.get(key);
} if ((key.getStoreName().equals(storeName) &&
for (Map.Entry<LookupKey, Lookup> entry : added.entrySet()) !key.isWrite()) || value == null ||
{ (!key.isWrite() && value.isLayered()))
if ((entry.getKey().getStoreName().equals(storeName) &&
!entry.getKey().isWrite()) ||
(!entry.getKey().isWrite() && entry.getValue().isLayered()))
{ {
added.remove(entry.getKey()); if (fgLogger.isDebugEnabled())
{
fgLogger.debug("Invalidating: " + key + ", " + (value != null ? value.getCurrentNode().getId() : -2));
}
fCache.remove(key);
} }
} }
} }
@@ -403,34 +230,23 @@ public class LookupCache
*/ */
public synchronized void onDelete(String storeName) public synchronized void onDelete(String storeName)
{ {
// Get or make up a fresh purged Set.
Set<LookupKey> purged = fToBePurged.get();
if (purged == null)
{
purged = new HashSet<LookupKey>();
fToBePurged.set(purged);
}
// Invalidate any entries that are in the store or are layered lookups. // Invalidate any entries that are in the store or are layered lookups.
for (Map.Entry<LookupKey, Lookup> entry : fCache.entrySet()) List<LookupKey> keys = new ArrayList<LookupKey>();
for (LookupKey key : fCache.getKeys())
{ {
if (entry.getKey().getStoreName().equals(storeName) || keys.add(key);
entry.getValue().isLayered())
{
purged.add(entry.getKey());
}
} }
// Get rid of any similarly matching elements in the added list. for (LookupKey key : keys)
Map<LookupKey, Lookup> added = fToBeAdded.get();
if (added == null)
{ {
return; Lookup value = fCache.get(key);
} if (key.getStoreName().equals(storeName) ||
for (Map.Entry<LookupKey, Lookup> entry : added.entrySet()) value == null || value.isLayered())
{
if (entry.getKey().getStoreName().equals(storeName) ||
entry.getValue().isLayered())
{ {
added.remove(entry.getKey()); if (fgLogger.isDebugEnabled())
{
fgLogger.debug("Invalidating: " + key + ", " + (value != null ? value.getCurrentNode().getId() : -2));
}
fCache.remove(key);
} }
} }
} }
@@ -441,48 +257,31 @@ public class LookupCache
*/ */
public synchronized void onSnapshot(String storeName) public synchronized void onSnapshot(String storeName)
{ {
// Get or make up a purged set.
Set<LookupKey> purged = fToBePurged.get();
if (purged == null)
{
purged = new HashSet<LookupKey>();
fToBePurged.set(purged);
}
// Invalidate any entries that in the store and writes or // Invalidate any entries that in the store and writes or
// any layered lookups. // any layered lookups.
for (Map.Entry<LookupKey, Lookup> entry : fCache.entrySet()) List<LookupKey> keys = new ArrayList<LookupKey>();
for (LookupKey key : fCache.getKeys())
{ {
if ((entry.getKey().getStoreName().equals(storeName) && keys.add(key);
entry.getKey().isWrite()) ||
entry.getValue().isLayered())
{
purged.add(entry.getKey());
}
} }
// Remove from the added list by the same criteria. for (LookupKey key : keys)
Map<LookupKey, Lookup> added = fToBeAdded.get();
if (added == null)
{ {
return; Lookup value = fCache.get(key);
} if ((key.getStoreName().equals(storeName) &&
for (Map.Entry<LookupKey, Lookup> entry : added.entrySet()) key.isWrite()) ||
{ value == null || value.isLayered())
if ((entry.getKey().getStoreName().equals(storeName) &&
entry.getKey().isWrite()) ||
entry.getValue().isLayered())
{ {
added.remove(entry.getKey()); if (fgLogger.isDebugEnabled())
{
fgLogger.debug("Invalidating: " + key + ", " + (value != null ? value.getCurrentNode().getId() : -2));
}
fCache.remove(key);
} }
} }
} }
/** public synchronized void reset()
* Called when a rollback has occurred.
*/
public synchronized void onRollback()
{ {
// Just toss the transaction level changes. fCache.clear();
fToBeAdded.set(null);
fToBePurged.set(null);
} }
} }

View File

@@ -3,14 +3,18 @@
*/ */
package org.alfresco.repo.avm; package org.alfresco.repo.avm;
import java.io.Serializable;
import org.alfresco.repo.avm.util.SimplePath; import org.alfresco.repo.avm.util.SimplePath;
/** /**
* This is the key by which Lookup's are retrieved from the cache. * This is the key by which Lookup's are retrieved from the cache.
* @author britt * @author britt
*/ */
public class LookupKey public class LookupKey implements Serializable
{ {
private static final long serialVersionUID = 8471482833953423406L;
/** /**
* The name of the store. * The name of the store.
*/ */

View File

@@ -3,12 +3,16 @@
*/ */
package org.alfresco.repo.avm.util; package org.alfresco.repo.avm.util;
import java.io.Serializable;
/** /**
* Holds a simple path. * Holds a simple path.
* @author britt * @author britt
*/ */
public class SimplePath public class SimplePath implements Serializable
{ {
private static final long serialVersionUID = 2696828491008988470L;
/** /**
* The names of the path's components. * The names of the path's components.
*/ */