mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Merged BRANCHES/DEV/V3.4-BUG-FIX to HEAD
28236: ALF-8810: Removed trailing space from discussion.discussion_for Italian translation 28241: Incremented version revision for 3.4.4 28284: ALF-835 - WCM/AVM: copy (empty) folder into itself 28285: ALF-6863: More than one cifs device breaks the web UI (explorer) 28290: ALF-8840: user-*.atomentry.ftl 28291: ALF-6863: Continuation of fix by Arseny 28336: ALF-8768: Fixed typo in comment on wcm-bootstrap-context.xml 28363: Merged DEV to V3.4-BUG-FIX 28262: ALF-8847: WCM: OrphanReaper contention throws error after 39 retries. Checkin Comment: Use JobLockService to make sure that only one OrphanReaper job is working. Generate list of nodes that must be processed in OrphanReaper.doBatch() transaction. 28386: ALF-9100: Merged PATCHES/V3.4.1 to V3.4-BUG-FIX 28249: ALF-8946: Avoid one full table scan per batch in full reindex - Now each batch scans a single time sample, dynamically adjusted based on the number of transactions in the previous sample, always aiming for 1000 transactions per sample. 28394: Fixed ALF-9090: NPE during inter-cluster subsystem messaging - Bean ID is a List<String> and might not be recognized on receiving machine - Log warning when bean ID is not available (unsymmetrical configuration, perhaps?) 28396: Merged DEV to V3.4-BUG-FIX 28384: ALF-6150: Initial state lost when non-versionable document is saved for the first time Creation of new version of document before writing its content was added to - AbstractAlfrescoMethodHandler->putDocument (this method is used by Office 2003, 2007) - VtiIfHeaderAction->doPut (this method is used by Office 2007 and 2010 on Windows 7) Creation of new version was added twice to AbstractAlfrescoMethodHandler to avoid affecting initial version when transaction is committed. 28432: Merged DEV to V3.4-BUG-FIX 28431: ALF-8530: Pressing the info icon creates an unrecorded file in the ContentStore Use ContentService.getTempWriter() in BaseContentNode$TemplateContentData.getContentAsText() method. 28435: Merged DEV/TEMPORARY to V3.4-BUG-FIX 28428: ALF-9015: cm:modifier not updated when document is updated via CIFS In ContentDiskDriver.closeFile() added ContentModel.PROP_MODIFIER property update. 28436: ALF-8550: Number of http requests (currentThreadsBusy) increases when session times out during creation of webform - Corrected use of read and write locks 28465: Fix for ALF-8023 Share preview doesn't work if... fixed as outlined by Dmitry. 28478: Merged BRANCHES/DEV/ALAN/AUDIT to BRANCHES/DEV/V3.4-BUG-FIX: 28062-28477 (28062,28063,28080,28081,28302,28303,28334,28340,28464,28469,28477) ALF-8438 Need higher level audit of user actions git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28481 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -18,20 +18,21 @@
|
||||
|
||||
package org.alfresco.repo.avm;
|
||||
|
||||
import java.sql.Savepoint;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.domain.avm.AVMHistoryLinkEntity;
|
||||
import org.alfresco.repo.domain.avm.AVMMergeLinkEntity;
|
||||
import org.alfresco.repo.domain.control.ControlDAO;
|
||||
import org.alfresco.repo.domain.permissions.Acl;
|
||||
import org.alfresco.repo.lock.JobLockService;
|
||||
import org.alfresco.repo.lock.LockAcquisitionException;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
|
||||
/**
|
||||
* This is the background thread for reaping no longer referenced nodes in the AVM repository. These orphans arise from
|
||||
@@ -107,13 +108,14 @@ public class OrphanReaper
|
||||
|
||||
private Log fgLogger = LogFactory.getLog(OrphanReaper.class);
|
||||
|
||||
private static final QName LOCK = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "OrphanReaper");
|
||||
private JobLockService jobLockService;
|
||||
|
||||
/**
|
||||
* The Transaction Service
|
||||
*/
|
||||
private TransactionService fTransactionService;
|
||||
|
||||
private ControlDAO controlDAO;
|
||||
|
||||
/**
|
||||
* Active base sleep interval.
|
||||
*/
|
||||
@@ -129,16 +131,6 @@ public class OrphanReaper
|
||||
*/
|
||||
private boolean fActive;
|
||||
|
||||
/**
|
||||
* The maximum length of the queue.
|
||||
*/
|
||||
private int fQueueLength;
|
||||
|
||||
/**
|
||||
* The linked list containing ids of nodes that are purgable.
|
||||
*/
|
||||
private LinkedList<Long> fPurgeQueue;
|
||||
|
||||
private boolean fDone = false;
|
||||
|
||||
private boolean fRunning = false;
|
||||
@@ -150,7 +142,6 @@ public class OrphanReaper
|
||||
{
|
||||
fActiveBaseSleep = 1000;
|
||||
fBatchSize = 50;
|
||||
fQueueLength = 1000;
|
||||
fActive = false;
|
||||
}
|
||||
|
||||
@@ -190,19 +181,11 @@ public class OrphanReaper
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum size of the queue of purgeable nodes.
|
||||
*
|
||||
* @param queueLength
|
||||
* The max length.
|
||||
* @param jobLockService service used to ensure that reaper runs are not duplicated
|
||||
*/
|
||||
public void setMaxQueueLength(int queueLength)
|
||||
public void setJobLockService(JobLockService jobLockService)
|
||||
{
|
||||
fQueueLength = queueLength;
|
||||
}
|
||||
|
||||
public void setControlDAO(ControlDAO controlDAO)
|
||||
{
|
||||
this.controlDAO = controlDAO;
|
||||
this.jobLockService = jobLockService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,6 +204,38 @@ public class OrphanReaper
|
||||
fDone = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get the lock. If the lock couldn't be taken, then <tt>null</tt> is returned.
|
||||
*
|
||||
* @return Returns the lock token or <tt>null</tt>
|
||||
*/
|
||||
private String getLock(long time)
|
||||
{
|
||||
try
|
||||
{
|
||||
return jobLockService.getLock(LOCK, time);
|
||||
}
|
||||
catch (LockAcquisitionException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get the lock. If it fails, the current transaction is marked for rollback.
|
||||
*
|
||||
* @return Returns the lock token
|
||||
*/
|
||||
private void refreshLock(String lockToken, long time)
|
||||
{
|
||||
if (lockToken == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Must provide existing lockToken");
|
||||
}
|
||||
jobLockService.refreshLock(lockToken, LOCK, time);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sit in a loop, periodically querying for orphans. When orphans are found, unhook them in bite sized batches.
|
||||
*/
|
||||
@@ -270,14 +285,21 @@ public class OrphanReaper
|
||||
{
|
||||
public Object execute() throws Exception
|
||||
{
|
||||
String lockToken = getLock(20000L);
|
||||
if (lockToken == null)
|
||||
{
|
||||
fgLogger.warn("Can't get lock. Assume multiple reapers ...");
|
||||
fActive = false;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (fgLogger.isTraceEnabled())
|
||||
{
|
||||
fgLogger.trace("Orphan reaper doBatch: batchSize="+fBatchSize+", maxQueueLength="+fQueueLength+", fActiveBaseSleep="+fActiveBaseSleep);
|
||||
fgLogger.trace("Orphan reaper doBatch: batchSize="+fBatchSize+", fActiveBaseSleep="+fActiveBaseSleep);
|
||||
}
|
||||
|
||||
if (fPurgeQueue == null)
|
||||
{
|
||||
List<AVMNode> nodes = AVMDAOs.Instance().fAVMNodeDAO.getOrphans(fQueueLength);
|
||||
refreshLock(lockToken, fBatchSize * 100L);
|
||||
List<AVMNode> nodes = AVMDAOs.Instance().fAVMNodeDAO.getOrphans(fBatchSize);
|
||||
if (nodes.size() == 0)
|
||||
{
|
||||
if (fgLogger.isTraceEnabled())
|
||||
@@ -289,7 +311,8 @@ public class OrphanReaper
|
||||
return null;
|
||||
}
|
||||
|
||||
fPurgeQueue = new LinkedList<Long>();
|
||||
refreshLock(lockToken, nodes.size() * 100L);
|
||||
LinkedList<Long> fPurgeQueue = new LinkedList<Long>();
|
||||
for (AVMNode node : nodes)
|
||||
{
|
||||
fPurgeQueue.add(node.getId());
|
||||
@@ -299,14 +322,6 @@ public class OrphanReaper
|
||||
{
|
||||
fgLogger.debug("Queue was empty so got more orphans from DB. Orphan queue size = "+fPurgeQueue.size());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fgLogger.isDebugEnabled())
|
||||
{
|
||||
fgLogger.debug("Queue was not empty. Orphan queue size = "+fPurgeQueue.size());
|
||||
}
|
||||
}
|
||||
|
||||
fActive = true;
|
||||
|
||||
@@ -327,16 +342,9 @@ public class OrphanReaper
|
||||
break;
|
||||
}
|
||||
|
||||
refreshLock(lockToken, 10000L);
|
||||
Long nodeId = fPurgeQueue.removeFirst();
|
||||
AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(nodeId);
|
||||
if (node == null)
|
||||
{
|
||||
// eg. cluster, multiple reapers
|
||||
|
||||
fgLogger.warn("Node ["+nodeId+"] not found - assume multiple reapers ...");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save away the ancestor and merged from fields from this node.
|
||||
|
||||
@@ -418,30 +426,13 @@ public class OrphanReaper
|
||||
}
|
||||
}
|
||||
|
||||
Savepoint savepoint = controlDAO.createSavepoint("OrphanReaper");
|
||||
|
||||
try
|
||||
{
|
||||
// Finally, delete it
|
||||
AVMDAOs.Instance().fAVMNodeDAO.delete(node);
|
||||
controlDAO.releaseSavepoint(savepoint);
|
||||
|
||||
if (fgLogger.isTraceEnabled())
|
||||
{
|
||||
fgLogger.trace("Deleted Node ["+node.getId()+"]");
|
||||
}
|
||||
}
|
||||
catch (ConcurrencyFailureException e)
|
||||
{
|
||||
// Since we are deleting the row, it doesn't matter
|
||||
// if it is deleted here or not.
|
||||
controlDAO.rollbackToSavepoint(savepoint);
|
||||
|
||||
if (fgLogger.isTraceEnabled())
|
||||
{
|
||||
fgLogger.trace("Node already deleted ["+node.getId()+"]");
|
||||
}
|
||||
}
|
||||
|
||||
reapCnt++;
|
||||
}
|
||||
|
Reference in New Issue
Block a user