Merged V2.9 to HEAD

9845: Merged V2.2 to V2.9
      9733: Merged V2.1 to V2.2
         9281: Improvements to index AUTO recovery
         9316: Fixed ETWOONE-193: Transactional caches not being cleaned up after rollback (2.1.4 regression)
         9317: Fixed ETWOONE-194: Faster void handling during index tracking
         9365: Improved performance for finding which snapshots have been indexed
         9413: Support to retrieve read/write state of the transaction and ensure Lucene commits are handled last
         9414: ACT-3245: Updating node properties and aspects don't bump the alf_node.version value
         9415: Code cleanup: Removed unnecessary empty methods
         9416: Fixed creation of multiple thread pools
         9417: Full index recovery absorbs indexing exceptions by default
         9418: Added AUTO index recovery option to sample in line with Wiki docs
         9419: ETWOONE-194: Index tracking is too slow
         9420: Fixed ETWOONE-201: Better logging and configurability for RetryingTransactionHelper
         9421: Fixed ETWOONE-202: SPlit person cleanup doesn't break read-only transactions
         9422: Follow up on CHK-3317: Removed use of JDK 1.6 NavigableMap interface
         9423: Fixed unit test after CHK-3317
         9424: More test fixes after CHK-3317
         9425: Ensure that index tracking tests don't run too long.
         9426: Made concurrent reindexing optional.  It is on by default.
         9509: ACT-3539: Mid-transaction locking on Lucene resources
         9547: Multithreaded index tracking startup: Handle previously lagging single-threaded rebuilds


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@10592 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2008-08-30 03:11:18 +00:00
parent 75646b4234
commit 0ac7884d1b
31 changed files with 1934 additions and 536 deletions

View File

@@ -27,20 +27,27 @@ package org.alfresco.repo.security.person;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.NoSuchPersonException;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.BaseSpringTest;
import org.alfresco.util.EqualsHelper;
import org.alfresco.util.GUID;
public class PersonTest extends BaseSpringTest
{
private TransactionService transactionService;
private PersonService personService;
private NodeService nodeService;
@@ -55,6 +62,7 @@ public class PersonTest extends BaseSpringTest
protected void onSetUpInTransaction() throws Exception
{
transactionService = (TransactionService) applicationContext.getBean("transactionService");
personService = (PersonService) applicationContext.getBean("personService");
nodeService = (NodeService) applicationContext.getBean("nodeService");
@@ -66,6 +74,7 @@ public class PersonTest extends BaseSpringTest
nodeService.deleteNode(nodeRef);
}
personService.setCreateMissingPeople(true);
}
protected void onTearDownInTransaction() throws Exception
@@ -409,5 +418,143 @@ public class PersonTest extends BaseSpringTest
}
personService.getPerson("Derek");
}
public void testReadOnlyTransactionHandling() throws Exception
{
// Kill the annoying Spring-managed txn
super.setComplete();
super.endTransaction();
boolean createMissingPeople = personService.createMissingPeople();
assertTrue("Default should be to create missing people", createMissingPeople);
final String username = "Derek";
// Make sure that the person is missing
RetryingTransactionCallback<Object> deletePersonWork = new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
personService.deletePerson(username);
return null;
}
};
transactionService.getRetryingTransactionHelper().doInTransaction(deletePersonWork, false, true);
// Make a read-only transaction and check that we get NoSuchPersonException
RetryingTransactionCallback<NodeRef> getMissingPersonWork = new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
return personService.getPerson(username);
}
};
try
{
transactionService.getRetryingTransactionHelper().doInTransaction(getMissingPersonWork, true, true);
fail("Expected auto-creation of person to fail gracefully");
}
catch (NoSuchPersonException e)
{
// Expected
}
// It should work in a write transaction, though
transactionService.getRetryingTransactionHelper().doInTransaction(getMissingPersonWork, false, true);
}
public void testSplitPersonCleanup() throws Exception
{
// Kill the annoying Spring-managed txn
super.setComplete();
super.endTransaction();
boolean createMissingPeople = personService.createMissingPeople();
assertTrue("Default should be to create missing people", createMissingPeople);
PersonServiceImpl personServiceImpl = (PersonServiceImpl) personService;
personServiceImpl.setDuplicateMode("LEAVE");
// The user to duplicate
final String duplicateUsername = GUID.generate();
// Make sure that the person is missing
RetryingTransactionCallback<Object> deletePersonWork = new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
personService.deletePerson(duplicateUsername);
return null;
}
};
transactionService.getRetryingTransactionHelper().doInTransaction(deletePersonWork, false, true);
// Fire off 10 threads to create the same person
int threadCount = 10;
final CountDownLatch startLatch = new CountDownLatch(threadCount);
final CountDownLatch endLatch = new CountDownLatch(threadCount);
final Map<String, NodeRef> cleanableNodeRefs = new HashMap<String, NodeRef>(17);
Runnable createPersonRunnable = new Runnable()
{
public void run()
{
final RetryingTransactionCallback<NodeRef> createPersonWork = new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
// Wait for the trigger to start
try { startLatch.await(); } catch (InterruptedException e) {}
// Trigger
NodeRef personNodeRef = personService.getPerson(duplicateUsername);
return personNodeRef;
}
};
startLatch.countDown();
try
{
NodeRef nodeRef = transactionService.getRetryingTransactionHelper().doInTransaction(createPersonWork, false, true);
// Store the noderef for later checking
String threadName = Thread.currentThread().getName();
cleanableNodeRefs.put(threadName, nodeRef);
}
catch (Throwable e)
{
// Errrm
e.printStackTrace();
}
endLatch.countDown();
}
};
// Fire the threads
for (int i = 0; i < threadCount; i++)
{
Thread thread = new Thread(createPersonRunnable);
thread.setName(getName() + "-" + i);
thread.setDaemon(true);
thread.start();
}
// Wait for the threads to have finished
try { endLatch.await(60, TimeUnit.SECONDS); } catch (InterruptedException e) {}
// Now, get the user with full split person handling
personServiceImpl.setDuplicateMode("DELETE");
RetryingTransactionCallback<NodeRef> getPersonWork = new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
return personService.getPerson(duplicateUsername);
}
};
NodeRef remainingNodeRef = transactionService.getRetryingTransactionHelper().doInTransaction(getPersonWork, false, true);
// Should all be cleaned up now, but no way to check
for (NodeRef nodeRef : cleanableNodeRefs.values())
{
if (nodeRef.equals(remainingNodeRef))
{
// This one should still be around
continue;
}
if (nodeService.exists(nodeRef))
{
fail("Expected unused person noderef to have been cleaned up: " + nodeRef);
}
}
}
}