use of org.alfresco.repo.lock.LockAcquisitionException in project alfresco-repository by Alfresco.
the class AbstractLockDAOImpl method getLock.
@Override
public void getLock(QName lockQName, String lockToken, long timeToLive) {
String qnameNamespaceUri = lockQName.getNamespaceURI();
String qnameLocalName = lockQName.getLocalName();
// Force lower case for case insensitivity
if (!qnameLocalName.toLowerCase().equals(qnameLocalName)) {
lockQName = QName.createQName(qnameNamespaceUri, qnameLocalName.toLowerCase());
qnameLocalName = lockQName.getLocalName();
}
// Force the lock token to lowercase
lockToken = lockToken.toLowerCase();
// Resolve the namespace
Long qnameNamespaceId = qnameDAO.getOrCreateNamespace(qnameNamespaceUri).getFirst();
// Get the lock resource for the exclusive lock.
// All the locks that are created will need the exclusive case.
LockResourceEntity exclusiveLockResource = getLockResource(qnameNamespaceId, qnameLocalName);
if (exclusiveLockResource == null) {
// Create it
exclusiveLockResource = createLockResource(qnameNamespaceId, qnameLocalName);
}
Long requiredExclusiveLockResourceId = exclusiveLockResource.getId();
// Split the lock name
List<QName> lockQNames = splitLockQName(lockQName);
List<Long> requiredLockResourceIds = new ArrayList<Long>(lockQNames.size());
// Create the lock resources
for (QName lockQNameIter : lockQNames) {
String localname = lockQNameIter.getLocalName();
// Get the basic lock resource, forcing a create
LockResourceEntity lockResource = getLockResource(qnameNamespaceId, localname);
if (lockResource == null) {
// Create it
lockResource = createLockResource(qnameNamespaceId, localname);
}
requiredLockResourceIds.add(lockResource.getId());
}
// Now, get all locks for the resources we will need
List<LockEntity> existingLocks = getLocksBySharedResourceIds(requiredLockResourceIds);
Map<LockEntity, LockEntity> existingLocksMap = new HashMap<LockEntity, LockEntity>();
// Check them and make sure they don't prevent locks
for (LockEntity existingLock : existingLocks) {
boolean canTakeLock = canTakeLock(existingLock, lockToken, requiredExclusiveLockResourceId);
if (!canTakeLock) {
throw new LockAcquisitionException(LockAcquisitionException.ERR_EXCLUSIVE_LOCK_EXISTS, lockQName, lockToken, existingLock);
}
existingLocksMap.put(existingLock, existingLock);
}
// Existing locks must be updated, if required.
for (Long requiredLockResourceId : requiredLockResourceIds) {
LockEntity requiredLock = new LockEntity();
requiredLock.setSharedResourceId(requiredLockResourceId);
requiredLock.setExclusiveResourceId(requiredExclusiveLockResourceId);
// Does it exist?
if (existingLocksMap.containsKey(requiredLock)) {
requiredLock = existingLocksMap.get(requiredLock);
// Do an update
try {
updateLock(requiredLock, lockToken, timeToLive);
} catch (Throwable e) {
throw new LockAcquisitionException(// Keep this for possible retrying
e, LockAcquisitionException.ERR_FAILED_TO_ACQUIRE_LOCK, lockQName, lockToken);
}
} else {
try {
// Create it
requiredLock = createLock(requiredLockResourceId, requiredExclusiveLockResourceId, lockToken, timeToLive);
} catch (Throwable e) {
throw new LockAcquisitionException(// Keep this for possible retrying
e, LockAcquisitionException.ERR_FAILED_TO_ACQUIRE_LOCK, lockQName, lockToken);
}
}
}
// Done
}
use of org.alfresco.repo.lock.LockAcquisitionException in project alfresco-repository by Alfresco.
the class UpdateTagScopesActionExecuter method executeImpl.
/**
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
@SuppressWarnings("unchecked")
protected void executeImpl(final Action action, final NodeRef actionedUponNodeRef) {
try {
// Grab the list of tag scopes to work on
List<NodeRef> tagScopeNodes = (List<NodeRef>) action.getParameterValue(PARAM_TAG_SCOPES);
if (logger.isDebugEnabled()) {
logger.debug("About to process tag scope updates for scopes " + tagScopeNodes);
}
// Process each tag scope in turn
for (NodeRef tmpTagScope : tagScopeNodes) {
final NodeRef tagScope = tmpTagScope;
// to worry as they'll handle the update for us!
try {
String lock = lockTagScope(tagScope);
// processing this tag scope
if (logger.isDebugEnabled()) {
logger.debug("Locked tag scope " + tagScope + " for updates");
}
// Grab all the pending work in chunks, and process
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Void>() {
public Void doWork() throws Exception {
final MutableInt updatesRemain = new MutableInt(1);
while (updatesRemain.intValue() > 0) {
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>() {
public Void execute() throws Throwable {
// Search for updates
Map<String, Integer> updates = new HashMap<String, Integer>();
List<Long> entryIds = searchForUpdates(tagScope, updates);
// Log what we found
if (logger.isDebugEnabled()) {
if (updates.size() > 0) {
logger.debug("Found updates for tag scope " + tagScope + " : " + updates);
} else if (updatesRemain.intValue() > 1) {
logger.debug("All updates now processed for tag scope " + tagScope);
} else {
logger.debug("No updates needed for tag scope " + tagScope);
}
}
// Does any work remain?
if (entryIds.size() == 0) {
updatesRemain.setValue(0);
return null;
}
updatesRemain.setValue(updatesRemain.intValue() + 1);
// Update the tags
performUpdates(tagScope, updates);
// Mark these entries as finished with
markUpdatesPerformed(entryIds);
// Done for now
return null;
}
}, false, true);
}
// We're done searching+updating for this tag scope
return null;
}
}, AuthenticationUtil.getSystemUserName());
// We're done with this tag scope
unlockTagScope(tagScope, lock);
} catch (LockAcquisitionException e) {
if (logger.isDebugEnabled()) {
logger.debug("Tag scope " + tagScope + " is already being processed by another action, skipping");
}
}
// Now proceed to the next tag scope
}
} catch (RuntimeException exception) {
exception.printStackTrace();
throw new RuntimeException("Unable to update the tag scopes.", exception);
}
}
use of org.alfresco.repo.lock.LockAcquisitionException in project alfresco-repository by Alfresco.
the class NodeArchiveServiceImpl method doBulkOperation.
/**
* Do batch-controlled work
*/
private void doBulkOperation(final String user, StoreRef originalStoreRef, BatchProcessWorker<NodeRef> worker) {
String lockToken = null;
try {
// Get a lock to keep refreshing
lockToken = jobLockService.getLock(LOCK_QNAME, LOCK_TTL);
// TODO: Should merely trigger a background job i.e. perhaps it should not be
// triggered by a user-based thread
BatchProcessor<NodeRef> batchProcessor = new BatchProcessor<NodeRef>("ArchiveBulkPurgeOrRestore", transactionService.getRetryingTransactionHelper(), getArchivedNodesWorkProvider(originalStoreRef, lockToken), 2, 20, null, null, 1000);
batchProcessor.process(worker, true);
} catch (LockAcquisitionException e) {
throw new AlfrescoRuntimeException(MSG_BUSY);
} finally {
try {
if (lockToken != null) {
jobLockService.releaseLock(lockToken, LOCK_QNAME);
}
} catch (LockAcquisitionException e) {
// Ignore
}
}
}
use of org.alfresco.repo.lock.LockAcquisitionException in project alfresco-repository by Alfresco.
the class ChainingUserRegistrySynchronizer method synchronizeInternal.
private void synchronizeInternal(boolean forceUpdate, boolean isFullSync, final boolean splitTxns) {
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled()) {
if (forceUpdate) {
ChainingUserRegistrySynchronizer.logger.debug("Running a full sync.");
} else {
ChainingUserRegistrySynchronizer.logger.debug("Running a differential sync.");
}
if (allowDeletions) {
ChainingUserRegistrySynchronizer.logger.debug("deletions are allowed");
} else {
ChainingUserRegistrySynchronizer.logger.debug("deletions are not allowed");
}
// Don't proceed with the sync if the repository is read only
if (this.transactionService.isReadOnly()) {
ChainingUserRegistrySynchronizer.logger.warn("Unable to proceed with user registry synchronization. Repository is read only.");
return;
}
}
// Don't proceed with the sync if the repository is read only
if (this.transactionService.isReadOnly()) {
ChainingUserRegistrySynchronizer.logger.warn("Unable to proceed with user registry synchronization. Repository is read only.");
return;
}
// Create a background executor that will refresh our lock. This means we can request a lock with a relatively
// small persistence time and not worry about it lasting after server restarts. Note we use an independent
// executor because this is a compound operation that spans accross multiple batch processors.
String lockToken = null;
TraceableThreadFactory threadFactory = new TraceableThreadFactory();
threadFactory.setNamePrefix("ChainingUserRegistrySynchronizer lock refresh");
threadFactory.setThreadDaemon(true);
ScheduledExecutorService lockRefresher = new ScheduledThreadPoolExecutor(1, threadFactory);
// Let's ensure all exceptions get logged
try {
// First, try to obtain a lock to ensure we are the only node trying to run this job
try {
if (splitTxns) {
// If this is an automated sync on startup or scheduled sync, don't even wait around for the lock.
// Assume the sync will be completed on another node.
lockToken = this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<String>() {
public String execute() throws Throwable {
return ChainingUserRegistrySynchronizer.this.jobLockService.getLock(ChainingUserRegistrySynchronizer.LOCK_QNAME, ChainingUserRegistrySynchronizer.LOCK_TTL, 0, 1);
}
}, false, splitTxns);
} else {
// If this is a login-triggered sync, give it a few retries before giving up
lockToken = this.jobLockService.getLock(ChainingUserRegistrySynchronizer.LOCK_QNAME, ChainingUserRegistrySynchronizer.LOCK_TTL, 3000, 10);
}
} catch (LockAcquisitionException e) {
// Don't proceed with the sync if it is running on another node
ChainingUserRegistrySynchronizer.logger.warn("User registry synchronization already running in another thread. Synchronize aborted");
return;
}
// Schedule the lock refresh to run at regular intervals
final String token = lockToken;
lockRefresher.scheduleAtFixedRate(new Runnable() {
public void run() {
ChainingUserRegistrySynchronizer.this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>() {
public Object execute() throws Throwable {
ChainingUserRegistrySynchronizer.this.jobLockService.refreshLock(token, ChainingUserRegistrySynchronizer.LOCK_QNAME, ChainingUserRegistrySynchronizer.LOCK_TTL);
return null;
}
}, false, splitTxns);
}
}, ChainingUserRegistrySynchronizer.LOCK_TTL / 2, ChainingUserRegistrySynchronizer.LOCK_TTL / 2, TimeUnit.MILLISECONDS);
Set<String> visitedZoneIds = new TreeSet<String>();
Collection<String> instanceIds = this.applicationContextManager.getInstanceIds();
// Work out the set of all zone IDs in the authentication chain so that we can decide which users / groups
// need 're-zoning'
Set<String> allZoneIds = new TreeSet<String>();
for (String id : instanceIds) {
allZoneIds.add(AuthorityService.ZONE_AUTH_EXT_PREFIX + id);
}
// Collect the plugins that we can sync : zoneId, plugin
Map<String, UserRegistry> plugins = new HashMap<String, UserRegistry>();
for (String id : instanceIds) {
UserRegistry plugin;
try {
ApplicationContext context = this.applicationContextManager.getApplicationContext(id);
plugin = (UserRegistry) context.getBean(this.sourceBeanName);
} catch (RuntimeException e) {
// The bean doesn't exist or this subsystem won't start. The reason would have been logged. Ignore and continue.
continue;
}
if (!(plugin instanceof ActivateableBean) || ((ActivateableBean) plugin).isActive()) {
// yes this plugin needs to be synced
plugins.put(id, plugin);
}
}
/**
* Sync starts here
*/
notifySyncStart(plugins.keySet());
for (String id : instanceIds) {
UserRegistry plugin = plugins.get(id);
if (plugin != null) {
// If debug is enabled then dump out the contents of the authentication JMX bean
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled()) {
mbeanServer = (MBeanServerConnection) getApplicationContext().getBean("alfrescoMBeanServer");
try {
StringBuilder nameBuff = new StringBuilder(200).append("Alfresco:Type=Configuration,Category=Authentication,id1=managed,id2=").append(URLDecoder.decode(id, "UTF-8"));
ObjectName name = new ObjectName(nameBuff.toString());
if (mbeanServer != null && mbeanServer.isRegistered(name)) {
MBeanInfo info = mbeanServer.getMBeanInfo(name);
MBeanAttributeInfo[] attributes = info.getAttributes();
ChainingUserRegistrySynchronizer.logger.debug(id + " attributes:");
for (MBeanAttributeInfo attribute : attributes) {
Object value = mbeanServer.getAttribute(name, attribute.getName());
ChainingUserRegistrySynchronizer.logger.debug(attribute.getName() + " = " + value);
}
}
} catch (UnsupportedEncodingException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (MalformedObjectNameException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (InstanceNotFoundException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (IntrospectionException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (AttributeNotFoundException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (ReflectionException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (MBeanException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (IOException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
}
}
// end of debug dump of active JMX bean
if (ChainingUserRegistrySynchronizer.logger.isInfoEnabled()) {
ChainingUserRegistrySynchronizer.logger.info("Synchronizing users and groups with user registry '" + id + "'");
}
if (isFullSync && ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
if (allowDeletions) {
ChainingUserRegistrySynchronizer.logger.warn("Some users and groups previously created by synchronization with this user registry may be removed.");
} else {
ChainingUserRegistrySynchronizer.logger.warn("Deletions are disabled. Users and groups removed from this registry will be logged only and will remain in the repository. Users previously found in a different registry will be moved in the repository rather than recreated.");
}
}
// Work out whether we should do the work in a separate transaction (it's most performant if we
// bunch it into small transactions, but if we are doing a sync on login, it has to be the same
// transaction)
boolean requiresNew = splitTxns || AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY;
try {
/**
* Do the sync with the specified plugin
*/
syncWithPlugin(id, plugin, forceUpdate, isFullSync, requiresNew, visitedZoneIds, allZoneIds);
this.applicationEventPublisher.publishEvent(new SynchronizeDirectoryEndEvent(this, id));
} catch (final RuntimeException e) {
notifySyncDirectoryEnd(id, e);
throw e;
}
}
// if plugin exists
}
// for each instanceId
// End of successful synchronization here
notifySyncEnd();
} catch (final RuntimeException e) {
notifySyncEnd(e);
ChainingUserRegistrySynchronizer.logger.error("Synchronization aborted due to error", e);
throw e;
} finally {
// Release the lock if necessary
if (lockToken != null) {
// Cancel the lock refresher
// Because we may hit a perfect storm when trying to interrupt workers in their unsynchronized getTask()
// method we can't wait indefinitely and may have to retry the shutdown
int trys = 0;
do {
lockRefresher.shutdown();
try {
lockRefresher.awaitTermination(ChainingUserRegistrySynchronizer.LOCK_TTL, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
}
} while (!lockRefresher.isTerminated() && trys++ < 3);
if (!lockRefresher.isTerminated()) {
lockRefresher.shutdownNow();
ChainingUserRegistrySynchronizer.logger.error("Failed to shut down lock refresher");
}
final String token = lockToken;
this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>() {
public Object execute() throws Throwable {
ChainingUserRegistrySynchronizer.this.jobLockService.releaseLock(token, ChainingUserRegistrySynchronizer.LOCK_QNAME);
return null;
}
}, false, splitTxns);
}
}
}
use of org.alfresco.repo.lock.LockAcquisitionException in project alfresco-repository by Alfresco.
the class LockingJobTest method testJobInClusterNotLocked.
@Test
public void testJobInClusterNotLocked() throws Exception {
// mock the job context
JobExecutionContext mockJobExecutionContext = mock(JobExecutionContext.class);
// create the hb collector
SimpleHBDataCollector simpleCollector = spy(new SimpleHBDataCollector("simpleCollector"));
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("collector", simpleCollector);
jobDataMap.put("hbDataSenderService", mockDataSenderService);
jobDataMap.put("jobLockService", mockJobLockService);
JobDetail jobDetail = JobBuilder.newJob().setJobData(jobDataMap).ofType(LockingJob.class).build();
when(mockJobExecutionContext.getJobDetail()).thenReturn(jobDetail);
// collector job is not locked from an other collector
String lockToken = "locked";
Runnable r1 = () -> {
// if a second job tries to get the lock before we finished that will raise the exception
when(mockJobLockService.getLock(isA(QName.class), anyLong())).thenReturn(lockToken).thenThrow(new LockAcquisitionException("", ""));
try {
new LockingJob().execute(mockJobExecutionContext);
} catch (JobExecutionException e) {
//
} finally {
// when we are finished an other job can have the lock
when(mockJobLockService.getLock(isA(QName.class), anyLong())).thenReturn(lockToken);
}
};
Runnable r2 = () -> {
try {
new LockingJob().execute(mockJobExecutionContext);
} catch (JobExecutionException e) {
//
}
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
Thread.sleep(500);
t2.start();
// Wait for threads to finish before testing
Thread.sleep(1000);
// verify that we collected and send data but just one time
verify(simpleCollector, Mockito.times(2)).collectData();
verify(mockDataSenderService, Mockito.times(2)).sendData(any(List.class));
verify(mockDataSenderService, Mockito.times(0)).sendData(any(HBData.class));
verify(mockJobLockService, Mockito.times(2)).getLock(any(QName.class), anyLong());
verify(mockJobLockService, Mockito.times(2)).refreshLock(eq(lockToken), any(QName.class), anyLong(), any(JobLockService.JobLockRefreshCallback.class));
}
Aggregations