package org.exist.collections;
import org.exist.storage.DBBroker;
import org.exist.xmldb.DatabaseInstanceManager;
import org.exist.xmldb.XPathQueryServiceImpl;
import org.junit.AfterClass;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.BeforeClass;
import org.junit.Test;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.Database;
import org.xmldb.api.base.Resource;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.CollectionManagementService;
import org.xmldb.api.modules.XQueryService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Test concurrent access to collections.
*/
public class ConcurrencyTest {
private static final int N_THREADS = 10;
private static final int DOC_COUNT = 200;
private static final int QUERY_COUNT = 20;
private static final String QUERY = "/test/c";
private static final String REMOVE =
"declare namespace xdb=\"http://exist-db.org/xquery/xmldb\";\n" +
"declare namespace util=\"http://exist-db.org/xquery/util\";" +
"declare variable $start external; " +
"let $dummy := util:log('DEBUG', ('Removing $start: ', $start, ' to ', $start + 9)) " +
"for $i in $start to $start + 9 " +
"let $resource := /test[@id = xs:integer($i)] " +
"return" +
" xdb:remove(util:collection-name($resource), util:document-name($resource))";
@Test
public void runTasks() {
ExecutorService executor = Executors.newFixedThreadPool(N_THREADS);
for (int i = 1; i <= 20; i++) {
executor.submit(new QueryTask(REMOVE, i * 10, true));
for (int j = 0; j < QUERY_COUNT; j++) {
executor.submit(new QueryTask(QUERY, 0, true));
}
}
executor.shutdown();
boolean terminated = false;
try {
terminated = executor.awaitTermination(60 * 60, TimeUnit.SECONDS);
} catch (InterruptedException e) {
}
assertTrue(terminated);
}
private class QueryTask implements Runnable {
String query;
int start = 0;
boolean protect = false;
private QueryTask(String query, int start, boolean protect) {
this.query = query;
this.protect = protect;
this.start = start;
}
public void run() {
try {
Collection collection = DatabaseManager.getCollection("xmldb:exist:///db/test", "admin", null);
XPathQueryServiceImpl service = (XPathQueryServiceImpl) collection.getService("XQueryService", "1.0");
service.beginProtected();
try {
if (start > 0)
service.declareVariable("start", new Integer(start));
service.query(query);
} finally {
service.endProtected();
}
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
}
@BeforeClass
public static void initDB() {
// initialize XML:DB driver
try {
Class cl = Class.forName("org.exist.xmldb.DatabaseImpl");
Database database = (Database) cl.newInstance();
database.setProperty("create-database", "true");
DatabaseManager.registerDatabase(database);
org.xmldb.api.base.Collection root = DatabaseManager.getCollection("xmldb:exist://" + DBBroker.ROOT_COLLECTION, "admin", null);
CollectionManagementService mgmt = (CollectionManagementService) root.getService("CollectionManagementService", "1.0");
Collection test = mgmt.createCollection("test");
for (int i = 1; i <= DOC_COUNT; i++) {
Resource r = test.createResource("test" + i + ".xml", "XMLResource");
String XML =
"<test id='" + i + "'>" +
" <a>b</a>" +
" <c>d</c>" +
"</test>";
r.setContent(XML);
test.storeResource(r);
}
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@AfterClass
public static void closeDB() {
try {
Collection root = DatabaseManager.getCollection("xmldb:exist://" + DBBroker.ROOT_COLLECTION, "admin", null);
CollectionManagementService cmgr = (CollectionManagementService) root.getService("CollectionManagementService", "1.0");
cmgr.removeCollection("test");
// Collection configRoot = DatabaseManager.getCollection("xmldb:exist://" + CollectionConfigurationManager.CONFIG_COLLECTION,
// "admin", null);
// cmgr = (CollectionManagementService) configRoot.getService("CollectionManagementService", "1.0");
// cmgr.removeCollection("db");
DatabaseInstanceManager mgr = (DatabaseInstanceManager) root.getService("DatabaseInstanceManager", "1.0");
mgr.shutdown();
} catch (XMLDBException e) {
e.printStackTrace();
fail(e.getMessage());
}
}
}