mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged DEV to HEAD:
29876: Removed emotive language from build.xml 29877: Made getter final; should make members final. 29879: Extra check for erroneous, pre-existing transactions 29880: ALF-8966: RSOLR 042: Node deletes keep DB ID (ALF-8965) - There is no longer code to change the store ID and UUID for an entry in alf_node - During store moves, new node entries are created and node data is moved onto the new node - Primarily affects archive/restore use cases - Any NodeRef can be tracked using the DB ID associated with it (see NodeService.getNodeStatus) 29926: Minor toString modification 29927: Code cleanup: line endings, non-javadoc and isDebugEnabled 29928: Moved exception absorbtion out of the non-propagating txn (and cleaned up unused code) 29930: Test for ALF-5714: Write transactions serialized on MySQL - The fix is to add this to the MySQL configuration and restart the MySQL server innodb_locks_unsafe_for_binlog = true See: http://dev.mysql.com/doc/refman/5.1/en/innodb-parameters.html#sysvar_innodb_locks_unsafe_for_binlog - The test holds DB resources from one archive process while doing another. It fails without the setting given. - TODO: Documentation required 29969: ALF-8966: RSOLR 042: Node deletes keep DB ID (ALF-8965) - Fixed timing of circular hierarchy detection 29972: ALF-8966: RSOLR 042: Node deletes keep DB ID (ALF-8965) - Fixed ACL retrieval from old parent node during move - Fixes PermissionServiceTest failures 29979: Fix test's initialization 29987: Fixed txn demarcation during write of transfer report git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@30044 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -31,6 +31,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransacti
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.MLText;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef.Status;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
@@ -188,4 +189,190 @@ public class NodeServiceTest extends TestCase
|
||||
"Node locale not set in setProperties(). ",
|
||||
Locale.GERMAN, nodeService.getProperty(nodeRef2, ContentModel.PROP_LOCALE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string of parent-child nodes to fill the given array of nodes
|
||||
*
|
||||
* @param workspaceRootNodeRef the store to use
|
||||
* @param liveNodeRefs the node array to fill
|
||||
*/
|
||||
private void buildNodeHierarchy(final NodeRef workspaceRootNodeRef, final NodeRef[] liveNodeRefs)
|
||||
{
|
||||
RetryingTransactionCallback<Void> setupCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
liveNodeRefs[0] = nodeService.createNode(
|
||||
workspaceRootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName(NAMESPACE, "depth-" + 0),
|
||||
ContentModel.TYPE_FOLDER).getChildRef();
|
||||
for (int i = 1; i < liveNodeRefs.length; i++)
|
||||
{
|
||||
liveNodeRefs[i] = nodeService.createNode(
|
||||
liveNodeRefs[i-1],
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NAMESPACE, "depth-" + i),
|
||||
ContentModel.TYPE_FOLDER).getChildRef();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
txnService.getRetryingTransactionHelper().doInTransaction(setupCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two separate node trees can be deleted concurrently at the database level.
|
||||
* This is not a concurren thread issue; instead we delete a hierarchy and hold the txn
|
||||
* open while we delete another in a new txn, thereby testing that DB locks don't prevent
|
||||
* concurrent deletes.
|
||||
* <p/>
|
||||
* See: <a href="https://issues.alfresco.com/jira/browse/ALF-5714">ALF-5714</a>
|
||||
*/
|
||||
public void testConcurrentArchive() throws Exception
|
||||
{
|
||||
final NodeRef workspaceRootNodeRef = nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
|
||||
final NodeRef[] nodesOne = new NodeRef[10];
|
||||
buildNodeHierarchy(workspaceRootNodeRef, nodesOne);
|
||||
final NodeRef[] nodesTwo = new NodeRef[10];
|
||||
buildNodeHierarchy(workspaceRootNodeRef, nodesTwo);
|
||||
|
||||
RetryingTransactionCallback<Void> outerCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// Delete the first hierarchy
|
||||
nodeService.deleteNode(nodesOne[0]);
|
||||
// Keep the txn hanging around to maintain DB locks
|
||||
// and start a second transaction to delete another hierarchy
|
||||
RetryingTransactionCallback<Void> innerCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
nodeService.deleteNode(nodesTwo[0]);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
txnService.getRetryingTransactionHelper().doInTransaction(innerCallback, false, true);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
txnService.getRetryingTransactionHelper().doInTransaction(outerCallback, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests archive and restore of simple hierarchy, checking that references and IDs are
|
||||
* used correctly.
|
||||
*/
|
||||
public void testArchiveAndRestore()
|
||||
{
|
||||
// First create a node structure (a very simple one) and record the references and IDs
|
||||
final NodeRef[] liveNodeRefs = new NodeRef[10];
|
||||
final NodeRef[] archivedNodeRefs = new NodeRef[10];
|
||||
|
||||
final NodeRef workspaceRootNodeRef = nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
|
||||
final NodeRef archiveRootNodeRef = nodeService.getRootNode(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE);
|
||||
|
||||
buildNodeHierarchy(workspaceRootNodeRef, liveNodeRefs);
|
||||
|
||||
// Get the node status details
|
||||
Long txnIdCreate = null;
|
||||
for (int i = 0; i < liveNodeRefs.length; i++)
|
||||
{
|
||||
StoreRef archivedStoreRef = archiveRootNodeRef.getStoreRef();
|
||||
archivedNodeRefs[i] = new NodeRef(archivedStoreRef, liveNodeRefs[i].getId());
|
||||
|
||||
Status liveStatus = nodeService.getNodeStatus(liveNodeRefs[i]);
|
||||
Status archivedStatus = nodeService.getNodeStatus(archivedNodeRefs[i]);
|
||||
|
||||
// Check that live node statuses are correct
|
||||
assertNotNull("'Live' node " + i + " status does not exist.", liveStatus);
|
||||
assertFalse("'Live' node " + i + " should be node be deleted", liveStatus.isDeleted());
|
||||
assertNull("'Archived' node " + i + " should not (yet) exist.", archivedStatus);
|
||||
|
||||
// Nodes in the hierarchy must be in the same txn
|
||||
if (txnIdCreate == null)
|
||||
{
|
||||
txnIdCreate = liveStatus.getDbTxnId();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure that the DB Txn ID is the same
|
||||
assertEquals(
|
||||
"DB TXN ID should have been the same for the hierarchy. ",
|
||||
txnIdCreate, liveStatus.getDbTxnId());
|
||||
}
|
||||
}
|
||||
|
||||
// Archive the top-level node
|
||||
nodeService.deleteNode(liveNodeRefs[0]);
|
||||
|
||||
// Recheck the nodes and make sure that all the 'live' nodes are deleted
|
||||
Long txnIdDelete = null;
|
||||
for (int i = 0; i < liveNodeRefs.length; i++)
|
||||
{
|
||||
Status liveStatus = nodeService.getNodeStatus(liveNodeRefs[i]);
|
||||
Status archivedStatus = nodeService.getNodeStatus(archivedNodeRefs[i]);
|
||||
|
||||
// Check that the ghosted nodes are marked as deleted and the archived nodes are not
|
||||
assertNotNull("'Live' node " + i + " status does not exist.", liveStatus);
|
||||
assertTrue("'Live' node " + i + " should be deleted (ghost entries)", liveStatus.isDeleted());
|
||||
assertNotNull("'Archived' node " + i + " does not exist.", archivedStatus);
|
||||
assertFalse("'Archived' node " + i + " should be undeleted", archivedStatus.isDeleted());
|
||||
|
||||
// Check that both old (ghosted deletes) and new nodes are in the same txn
|
||||
if (txnIdDelete == null)
|
||||
{
|
||||
txnIdDelete = liveStatus.getDbTxnId();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure that the DB Txn ID is the same
|
||||
assertEquals(
|
||||
"DB TXN ID should have been the same for the deleted (ghost) nodes. ",
|
||||
txnIdDelete, liveStatus.getDbTxnId());
|
||||
}
|
||||
assertEquals(
|
||||
"DB TXN ID should be the same for deletes across the hierarchy",
|
||||
txnIdDelete, archivedStatus.getDbTxnId());
|
||||
}
|
||||
|
||||
// Restore the top-level node
|
||||
nodeService.restoreNode(archivedNodeRefs[0], workspaceRootNodeRef, null, null);
|
||||
|
||||
// Recheck the nodes and make sure that all the 'archived' nodes are deleted and the 'live' nodes are back
|
||||
Long txnIdRestore = null;
|
||||
for (int i = 0; i < liveNodeRefs.length; i++)
|
||||
{
|
||||
Status liveStatus = nodeService.getNodeStatus(liveNodeRefs[i]);
|
||||
StoreRef archivedStoreRef = archiveRootNodeRef.getStoreRef();
|
||||
archivedNodeRefs[i] = new NodeRef(archivedStoreRef, liveNodeRefs[i].getId());
|
||||
Status archivedStatus = nodeService.getNodeStatus(archivedNodeRefs[i]);
|
||||
|
||||
// Check that the ghosted nodes are marked as deleted and the archived nodes are not
|
||||
assertNotNull("'Live' node " + i + " status does not exist.", liveStatus);
|
||||
assertFalse("'Live' node " + i + " should not be deleted", liveStatus.isDeleted());
|
||||
assertNotNull("'Archived' node " + i + " does not exist.", archivedStatus);
|
||||
assertTrue("'Archived' node " + i + " should be deleted (ghost entry)", archivedStatus.isDeleted());
|
||||
|
||||
// Check that both old (ghosted deletes) and new nodes are in the same txn
|
||||
if (txnIdRestore == null)
|
||||
{
|
||||
txnIdRestore = liveStatus.getDbTxnId();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure that the DB Txn ID is the same
|
||||
assertEquals(
|
||||
"DB TXN ID should have been the same for the restored nodes. ",
|
||||
txnIdRestore, liveStatus.getDbTxnId());
|
||||
}
|
||||
assertEquals(
|
||||
"DB TXN ID should be the same for the ex-archived (now-ghost) nodes. ",
|
||||
txnIdRestore, archivedStatus.getDbTxnId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user