/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
*/
package org.alfresco.repo.avm;
import java.util.List;
import java.util.SortedMap;
import javax.transaction.UserTransaction;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avmsync.AVMDifference;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchService;
/**
* AVM concurrency and search
*
* @author andyh, janv
*/
public class AVMServiceConcurrentTest extends AVMServiceTestBase
{
public void testSetup() throws Exception
{
super.testSetup();
}
public void test_CreateDelete() throws Exception
{
int threads= 4;
int loops = 10;
int snapshotsPerLoop = 4;
assertEquals(1, fService.getStoreVersions("main").size());
fService.createDirectory("main:/", "test");
int startVersion = fService.createSnapshot("main", null, null).get("main");
assertEquals(2, fService.getStoreVersions("main").size());
assertEquals(0, fService.getDirectoryListing(-1, "main:/test").size());
UserTransaction testTX = fTransactionService.getUserTransaction();
testTX.begin();
StoreRef storeRef = AVMNodeConverter.ToStoreRef("main");
SearchService searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true);
ResultSet results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\"");
assertEquals(0, results.length());
results.close();
testTX.commit();
Thread runner = null;
for (int i = 0; i < threads; i++)
{
runner = new Nester("Concurrent-" + i, runner, false, snapshotsPerLoop, Nester.Mode.CREATE, loops);
}
if (runner != null)
{
runner.start();
try
{
runner.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
System.out.println("Snapshot count: "+fService.getStoreVersions("main").size());
SortedMap listing = fService.getDirectoryListing(-1, "main:/test");
assertEquals(loops, listing.size());
for(AVMNodeDescriptor node : listing.values())
{
System.out.println("Listed: "+node.getPath()+" "+node.getVersionID());
}
List diffs = fSyncService.compare(startVersion, "main:/", -1, "main:/", null);
assertEquals(loops, diffs.size());
for(AVMDifference diff : diffs)
{
AVMNodeDescriptor desc = fService.lookup(diff.getDestinationVersion(), diff.getDestinationPath(), true);
assertFalse(desc.isDeleted());
}
testTX = fTransactionService.getUserTransaction();
testTX.begin();
try
{
searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true);
results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\"");
for(ResultSetRow row : results)
{
System.out.println("Found: "+row.getNodeRef());
}
assertEquals(loops, results.length());
results.close();
}
finally
{
try { testTX.commit(); } catch (Exception e) {}
}
// delete
runner = null;
for (int i = 0; i < threads; i++)
{
runner = new Nester("Concurrent-" + i, runner, false, snapshotsPerLoop, Nester.Mode.DELETE, loops);
}
if (runner != null)
{
runner.start();
try
{
runner.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
assertEquals(0, fService.getDirectoryListing(-1, "main:/test").size());
System.out.println("Snapshot count: "+fService.getStoreVersions("main").size());
/*
for(org.alfresco.service.cmr.avm.VersionDescriptor v : fService.getStoreVersions("main"))
{
System.out.println(v);
}
*/
testTX = fTransactionService.getUserTransaction();
testTX.begin();
searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true);
results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\"");
for(ResultSetRow row : results)
{
System.out.println("Found: "+row.getNodeRef());
}
assertEquals(0, results.length());
results.close();
testTX.commit();
}
public void test_ALF_786() throws Exception
{
int threads= 4;
int loops = 10;
int snapshotsPerLoop = 4;
fService.createDirectory("main:/", "test");
int startVersion = fService.createSnapshot("main", null, null).get("main");
assertEquals(0, fService.getDirectoryListing(-1, "main:/test").size());
UserTransaction testTX = fTransactionService.getUserTransaction();
testTX.begin();
StoreRef storeRef = AVMNodeConverter.ToStoreRef("main");
SearchService searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true);
ResultSet results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\"");
assertEquals(0, results.length());
results.close();
testTX.commit();
// create
Thread runner = null;
for (int i = 0; i < threads; i++)
{
runner = new Nester("Concurrent-" + i, runner, false, snapshotsPerLoop, Nester.Mode.CREATE, loops);
}
if (runner != null)
{
runner.start();
try
{
runner.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
SortedMap listing = fService.getDirectoryListing(-1, "main:/test");
assertEquals(loops, listing.size());
for(AVMNodeDescriptor node : listing.values())
{
System.out.println("Listed: "+node.getPath()+" "+node.getVersionID());
}
List diffs = fSyncService.compare(startVersion, "main:/", -1, "main:/", null);
assertEquals(loops, diffs.size());
for(AVMDifference diff : diffs)
{
AVMNodeDescriptor desc = fService.lookup(diff.getDestinationVersion(), diff.getDestinationPath(), true);
assertFalse(desc.isDeleted());
}
testTX = fTransactionService.getUserTransaction();
testTX.begin();
try
{
searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true);
results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\"");
for(ResultSetRow row : results)
{
System.out.println("Found: "+row.getNodeRef());
}
assertEquals(loops, results.length());
results.close();
}
finally
{
try { testTX.commit(); } catch (Exception e) {}
}
// update
runner = null;
for (int i = 0; i < threads; i++)
{
runner = new Nester("Concurrent-" + i, runner, false, snapshotsPerLoop, Nester.Mode.UPDATE, loops);
}
if (runner != null)
{
runner.start();
try
{
runner.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
testTX = fTransactionService.getUserTransaction();
testTX.begin();
searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true);
results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\"");
for(ResultSetRow row : results)
{
System.out.println("Found: "+row.getNodeRef());
}
assertEquals(loops, results.length());
results.close();
testTX.commit();
// delete
runner = null;
for (int i = 0; i < threads; i++)
{
runner = new Nester("Concurrent-" + i, runner, false, snapshotsPerLoop, Nester.Mode.DELETE, loops);
}
if (runner != null)
{
runner.start();
try
{
runner.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
assertEquals(0, fService.getDirectoryListing(-1, "main:/test").size());
testTX = fTransactionService.getUserTransaction();
testTX.begin();
searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true);
results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\"");
for(ResultSetRow row : results)
{
System.out.println("Found: "+row.getNodeRef());
}
assertEquals(0, results.length());
results.close();
testTX.commit();
// recreate
runner = null;
for (int i = 0; i < threads; i++)
{
runner = new Nester("Concurrent-" + i, runner, false, snapshotsPerLoop, Nester.Mode.CREATE, loops);
}
if (runner != null)
{
runner.start();
try
{
runner.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
testTX = fTransactionService.getUserTransaction();
testTX.begin();
searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true);
results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\"");
for(ResultSetRow row : results)
{
System.out.println("Found: "+row.getNodeRef());
}
assertEquals(loops, results.length());
results.close();
testTX.commit();
// move
runner = null;
for (int i = 0; i < threads; i++)
{
runner = new Nester("Concurrent-" + i, runner, false, snapshotsPerLoop, Nester.Mode.MOVE, loops);
}
if (runner != null)
{
runner.start();
try
{
runner.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
testTX = fTransactionService.getUserTransaction();
testTX.begin();
searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true);
results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\"");
for(ResultSetRow row : results)
{
System.out.println("Found: "+row.getNodeRef());
}
assertEquals(loops, results.length());
results.close();
testTX.commit();
}
public void xtest_ALF_786_PLUS() throws Exception
{
int startVersion;
UserTransaction testTX = fTransactionService.getUserTransaction();
testTX.begin();
fService.createDirectory("main:/", "test");
startVersion = fService.createSnapshot("main", null, null).get("main");
testTX.commit();
testTX = fTransactionService.getUserTransaction();
testTX.begin();
StoreRef storeRef = AVMNodeConverter.ToStoreRef("main");
SearchService searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true);
ResultSet results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\"");
assertEquals(0, results.length());
results.close();
testTX.commit();
Thread runner = null;
for (int i = 0; i < 10; i++)
{
runner = new Nester("Concurrent-" + i, runner, true, 10, Nester.Mode.CREATE, 10 );
}
if (runner != null)
{
runner.start();
try
{
runner.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
testTX = fTransactionService.getUserTransaction();
testTX.begin();
// snap
testTX.commit();
testTX = fTransactionService.getUserTransaction();
testTX.begin();;
SortedMap listing = fService.getDirectoryListing(-1, "main:/test");
assertEquals(100, listing.size());
for(AVMNodeDescriptor node : listing.values())
{
System.out.println("Listed: "+node.getPath()+" "+node.getVersionID());
}
List diffs = fSyncService.compare(startVersion, "main:/", -1, "main:/", null);
assertEquals(100, diffs.size());
for(AVMDifference diff : diffs)
{
AVMNodeDescriptor desc = fService.lookup(diff.getDestinationVersion(), diff.getDestinationPath(), true);
assertFalse(desc.isDeleted());
}
searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true);
results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\"");
for(ResultSetRow row : results)
{
System.out.println("Found: "+row.getNodeRef());
}
assertEquals(100, results.length());
results.close();
testTX.commit();
}
static class Nester extends Thread
{
enum Mode {CREATE, UPDATE, DELETE, MOVE};
Thread waiter;
int i;
boolean multiThread;
int snapshotCount;
Mode mode;
int loopCount;
Nester(String name, Thread waiter, boolean multiThread, int snapshotCount, Mode mode, int loopCount)
{
super(name);
this.setDaemon(true);
this.waiter = waiter;
this.multiThread = multiThread;
this.snapshotCount = snapshotCount;
this.mode = mode;
this.loopCount = loopCount;
}
public void run()
{
fAuthenticationComponent.setSystemUserAsCurrentUser();
if (waiter != null)
{
waiter.start();
}
try
{
//System.out.println("Start " + this.getName());
for(i = 0; i < loopCount; i++)
{
RetryingTransactionCallback create = new RetryingTransactionCallback()
{
public Void execute() throws Throwable
{
System.out.println("Create file: " + "main:/test/" + getName()+"-"+i);
fService.createFile("main:/test", getName()+"-"+i).close();
return null;
}
};
RetryingTransactionCallback update = new RetryingTransactionCallback()
{
public Void execute() throws Throwable
{
System.out.println("Update file mime type: " + "main:/test/" + getName()+"-"+i);
fService.setMimeType("main:/test/"+getName()+"-"+i, "text/plain");
return null;
}
};
RetryingTransactionCallback delete = new RetryingTransactionCallback()
{
public Void execute() throws Throwable
{
System.out.println("Remove file: " + "main:/test/" + getName()+"-"+i);
fService.removeNode("main:/test/"+getName()+"-"+i);
return null;
}
};
RetryingTransactionCallback move = new RetryingTransactionCallback()
{
public Void execute() throws Throwable
{
System.out.println("Rename file: " + "main:/test/" + getName()+"-"+i);
fService.rename("main:/test/", getName()+"-"+i, "main:/test/", "MOVED-"+getName()+"-"+i);
return null;
}
};
if(multiThread || (waiter == null))
{
// only one thread creates for 786
switch(mode)
{
case CREATE:
fRetryingTransactionHelper.doInTransaction(create);
break;
case UPDATE:
fRetryingTransactionHelper.doInTransaction(update);
break;
case DELETE:
fRetryingTransactionHelper.doInTransaction(delete);
break;
case MOVE:
fRetryingTransactionHelper.doInTransaction(move);
break;
default:
}
}
RetryingTransactionCallback snap = new RetryingTransactionCallback()
{
public Void execute() throws Throwable
{
//System.out.println("Snap: main:/");
fService.createSnapshot("main", null, null);
return null;
}
};
for(int s = 0; s < snapshotCount; s++)
{
fRetryingTransactionHelper.doInTransaction(snap);
}
}
//System.out.println("End " + this.getName());
}
catch (Exception e)
{
System.out.println("End " + this.getName() + " with error " + e.getMessage());
e.printStackTrace();
}
finally
{
fAuthenticationComponent.clearCurrentSecurityContext();
}
if (waiter != null)
{
try
{
waiter.join();
System.out.println("Waited for " + waiter.getName()+" by "+this.getName());
}
catch (InterruptedException e)
{
}
}
}
}
}