mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Reworking of AVM to ADM RemoteStore patch to remove thread contention by precreating 'surf-config' folders for each site.
Also speeds up patch processing by ~20%. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@30559 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -23,9 +23,11 @@ import java.io.Serializable;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.SortedMap;
|
import java.util.SortedMap;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
@@ -40,7 +42,6 @@ import org.alfresco.repo.batch.BatchProcessor;
|
|||||||
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
|
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
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;
|
||||||
@@ -89,10 +90,12 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
|
|||||||
// name of the surf config folder
|
// name of the surf config folder
|
||||||
private static final String SURF_CONFIG = "surf-config";
|
private static final String SURF_CONFIG = "surf-config";
|
||||||
|
|
||||||
private static final int BATCH_THREADS = 8;
|
private static final int SITE_BATCH_THREADS = 8;
|
||||||
private static final int BATCH_SIZE = 100;
|
private static final int SITE_BATCH_SIZE = 100;
|
||||||
|
private static final int MIGRATE_BATCH_THREADS = 8;
|
||||||
|
private static final int MIGRATE_BATCH_SIZE = 100;
|
||||||
|
|
||||||
private Map<String, Pair<NodeRef, NodeRef>> siteReferenceCache = null;
|
private Map<String, NodeRef> siteReferenceCache = null;
|
||||||
private SortedMap<String, AVMNodeDescriptor> paths;
|
private SortedMap<String, AVMNodeDescriptor> paths;
|
||||||
private SortedMap<String, AVMNodeDescriptor> retryPaths;
|
private SortedMap<String, AVMNodeDescriptor> retryPaths;
|
||||||
private NodeRef surfConfigRef = null;
|
private NodeRef surfConfigRef = null;
|
||||||
@@ -208,21 +211,126 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// init our cache
|
// init the siteid to surf-config noderef cache
|
||||||
this.siteReferenceCache = new ConcurrentHashMap<String, Pair<NodeRef,NodeRef>>(16384);
|
this.siteReferenceCache = new ConcurrentHashMap<String, NodeRef>(16384);
|
||||||
|
|
||||||
|
// get user names that will be used to RunAs and set permissions later
|
||||||
|
String systemUser = AuthenticationUtil.getSystemUserName();
|
||||||
|
final String tenantSystemUser = this.tenantAdminService.getDomainUser(
|
||||||
|
systemUser, this.tenantAdminService.getCurrentUserDomain());
|
||||||
|
|
||||||
|
// build a set of unique site names
|
||||||
|
final Set<String> sites = new HashSet<String>(paths.size());
|
||||||
|
Matcher matcher;
|
||||||
|
for (String path: paths.keySet())
|
||||||
|
{
|
||||||
|
String siteName = null;
|
||||||
|
if ((matcher = SITE_PATTERN_1.matcher(path)).matches())
|
||||||
|
{
|
||||||
|
siteName = matcher.group(1);
|
||||||
|
}
|
||||||
|
else if ((matcher = SITE_PATTERN_2.matcher(path)).matches())
|
||||||
|
{
|
||||||
|
siteName = matcher.group(1);
|
||||||
|
}
|
||||||
|
if (siteName != null)
|
||||||
|
{
|
||||||
|
sites.add(siteName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve the sites for the batch work provider
|
||||||
|
final Iterator<String> siteItr = sites.iterator();
|
||||||
|
|
||||||
|
// the work provider for the site 'surf-config' folder pre-create step
|
||||||
|
BatchProcessWorkProvider<String> siteWorkProvider = new BatchProcessWorkProvider<String>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public synchronized Collection<String> getNextWork()
|
||||||
|
{
|
||||||
|
int batchCount = 0;
|
||||||
|
|
||||||
|
List<String> siteBatch = new ArrayList<String>(SITE_BATCH_SIZE);
|
||||||
|
while (siteItr.hasNext() && batchCount++ != SITE_BATCH_SIZE)
|
||||||
|
{
|
||||||
|
siteBatch.add(siteItr.next());
|
||||||
|
}
|
||||||
|
return siteBatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized int getTotalEstimatedWorkSize()
|
||||||
|
{
|
||||||
|
return sites.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// batch process the sites in the set and pre-create the 'surf-config' folders for each site
|
||||||
|
// add each config folder noderef to our cache ready for the config file migration processing
|
||||||
|
BatchProcessor<String> siteBatchProcessor = new BatchProcessor<String>(
|
||||||
|
"AVMToADMRemoteStorePatch",
|
||||||
|
this.transactionHelper,
|
||||||
|
siteWorkProvider,
|
||||||
|
SITE_BATCH_THREADS,
|
||||||
|
SITE_BATCH_SIZE,
|
||||||
|
this.applicationEventPublisher,
|
||||||
|
logger,
|
||||||
|
SITE_BATCH_SIZE * 10);
|
||||||
|
|
||||||
|
BatchProcessWorker<String> siteWorker = new BatchProcessWorker<String>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void beforeProcess() throws Throwable
|
||||||
|
{
|
||||||
|
AuthenticationUtil.setRunAsUser(tenantSystemUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterProcess() throws Throwable
|
||||||
|
{
|
||||||
|
AuthenticationUtil.clearCurrentSecurityContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentifier(String entry)
|
||||||
|
{
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(String siteName) throws Throwable
|
||||||
|
{
|
||||||
|
// get the Site NodeRef
|
||||||
|
NodeRef siteRef = getSiteNodeRef(siteName);
|
||||||
|
if (siteRef != null)
|
||||||
|
{
|
||||||
|
// create the 'surf-config' folder for the site and cache the NodeRef to it
|
||||||
|
NodeRef surfConfigRef = getSurfConfigNodeRef(siteRef);
|
||||||
|
siteReferenceCache.put(siteName, surfConfigRef);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.info("WARNING: unable to find site id: " + siteName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
siteBatchProcessor.process(siteWorker, true);
|
||||||
|
logger.info("Created 'surf-config' folders for: " + this.siteReferenceCache.size() + " sites in " + (System.currentTimeMillis()-start) + "ms");
|
||||||
|
|
||||||
// TODO: just retrieve a List of AVM NodeDescriptor objects - sort Collection based on Path?
|
|
||||||
// retrieve AVM NodeDescriptor objects for the paths
|
// retrieve AVM NodeDescriptor objects for the paths
|
||||||
final Iterator<String> pathItr = this.paths.keySet().iterator();
|
final Iterator<String> pathItr = this.paths.keySet().iterator();
|
||||||
BatchProcessWorkProvider<AVMNodeDescriptor> workProvider = new BatchProcessWorkProvider<AVMNodeDescriptor>()
|
|
||||||
|
// the work provider for the config file migration
|
||||||
|
BatchProcessWorkProvider<AVMNodeDescriptor> migrateWorkProvider = new BatchProcessWorkProvider<AVMNodeDescriptor>()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public synchronized Collection<AVMNodeDescriptor> getNextWork()
|
public synchronized Collection<AVMNodeDescriptor> getNextWork()
|
||||||
{
|
{
|
||||||
int batchCount = 0;
|
int batchCount = 0;
|
||||||
|
|
||||||
List<AVMNodeDescriptor> nodes = new ArrayList<AVMNodeDescriptor>(BATCH_SIZE);
|
List<AVMNodeDescriptor> nodes = new ArrayList<AVMNodeDescriptor>(MIGRATE_BATCH_SIZE);
|
||||||
while (pathItr.hasNext() && batchCount++ != BATCH_SIZE)
|
while (pathItr.hasNext() && batchCount++ != MIGRATE_BATCH_SIZE)
|
||||||
{
|
{
|
||||||
nodes.add(paths.get(pathItr.next()));
|
nodes.add(paths.get(pathItr.next()));
|
||||||
}
|
}
|
||||||
@@ -240,16 +348,13 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
|
|||||||
BatchProcessor<AVMNodeDescriptor> batchProcessor = new BatchProcessor<AVMNodeDescriptor>(
|
BatchProcessor<AVMNodeDescriptor> batchProcessor = new BatchProcessor<AVMNodeDescriptor>(
|
||||||
"AVMToADMRemoteStorePatch",
|
"AVMToADMRemoteStorePatch",
|
||||||
this.transactionHelper,
|
this.transactionHelper,
|
||||||
workProvider,
|
migrateWorkProvider,
|
||||||
BATCH_THREADS,
|
MIGRATE_BATCH_THREADS,
|
||||||
BATCH_SIZE,
|
MIGRATE_BATCH_SIZE,
|
||||||
this.applicationEventPublisher,
|
this.applicationEventPublisher,
|
||||||
logger,
|
logger,
|
||||||
BATCH_SIZE * 10);
|
MIGRATE_BATCH_SIZE * 10);
|
||||||
|
|
||||||
String systemUser = AuthenticationUtil.getSystemUserName();
|
|
||||||
final String tenantSystemUser = this.tenantAdminService.getDomainUser(
|
|
||||||
systemUser, this.tenantAdminService.getCurrentUserDomain());
|
|
||||||
BatchProcessWorker<AVMNodeDescriptor> worker = new BatchProcessWorker<AVMNodeDescriptor>()
|
BatchProcessWorker<AVMNodeDescriptor> worker = new BatchProcessWorker<AVMNodeDescriptor>()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
@@ -276,8 +381,6 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
|
|||||||
migrateNode(entry);
|
migrateNode(entry);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
batchProcessor.process(worker, true);
|
batchProcessor.process(worker, true);
|
||||||
|
|
||||||
// retry the paths that were blocked due to multiple threads attemping to create
|
// retry the paths that were blocked due to multiple threads attemping to create
|
||||||
@@ -361,57 +464,24 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
|
|||||||
}
|
}
|
||||||
|
|
||||||
NodeRef surfConfigRef;
|
NodeRef surfConfigRef;
|
||||||
try
|
if (siteName != null)
|
||||||
{
|
{
|
||||||
if (siteName != null)
|
if (debug) logger.debug("...resolved site id: " + siteName);
|
||||||
|
surfConfigRef = siteReferenceCache.get(siteName);
|
||||||
|
if (surfConfigRef == null)
|
||||||
{
|
{
|
||||||
if (debug) logger.debug("...resolved site id: " + siteName);
|
logger.info("WARNING: unable to migrate path as site id cannot be found: " + siteName);
|
||||||
NodeRef siteRef = null;
|
|
||||||
String key = AlfrescoTransactionSupport.getTransactionId() + siteName;
|
|
||||||
Pair<NodeRef, NodeRef> refCache = siteReferenceCache.get(key);
|
|
||||||
if (refCache == null)
|
|
||||||
{
|
|
||||||
refCache = new Pair<NodeRef, NodeRef>(null, null);
|
|
||||||
siteReferenceCache.put(key, refCache);
|
|
||||||
}
|
|
||||||
siteRef = refCache.getFirst();
|
|
||||||
if (siteRef == null)
|
|
||||||
{
|
|
||||||
siteRef = getSiteNodeRef(siteName);
|
|
||||||
refCache.setFirst(siteRef);
|
|
||||||
}
|
|
||||||
if (siteRef != null)
|
|
||||||
{
|
|
||||||
surfConfigRef = refCache.getSecond();
|
|
||||||
if (surfConfigRef == null)
|
|
||||||
{
|
|
||||||
surfConfigRef = getSurfConfigNodeRef(siteRef);
|
|
||||||
refCache.setSecond(surfConfigRef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.info("WARNING: unable to migrate path as site id cannot be found: " + siteName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (userId != null)
|
|
||||||
{
|
|
||||||
if (debug) logger.debug("...resolved user id: " + userId);
|
|
||||||
surfConfigRef = this.surfConfigRef;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (debug) logger.debug("...resolved generic path.");
|
|
||||||
surfConfigRef = this.surfConfigRef;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ConcurrencyFailureException conErr)
|
else if (userId != null)
|
||||||
{
|
{
|
||||||
logger.warn("Unable to create folder: surf-config for path: " + avmNode.getPath() +
|
if (debug) logger.debug("...resolved user id: " + userId);
|
||||||
" - as another txn is busy, will retry later.");
|
surfConfigRef = this.surfConfigRef;
|
||||||
retryPaths.put(avmNode.getPath(), avmNode);
|
}
|
||||||
return;
|
else
|
||||||
|
{
|
||||||
|
if (debug) logger.debug("...resolved generic path.");
|
||||||
|
surfConfigRef = this.surfConfigRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure folders exist down to the specified parent
|
// ensure folders exist down to the specified parent
|
||||||
|
Reference in New Issue
Block a user