Skip to content
Browse files

replace synchronization blocks by ReentrantReadWriteLock

  • Loading branch information...
1 parent 94bf450 commit 75fd5bebe398400fe25e89770e718d4539213d99 @shabanovd shabanovd committed Jan 12, 2014
Showing with 208 additions and 67 deletions.
  1. +139 −67 src/org/exist/collections/CollectionConfigurationManager.java
  2. +69 −0 src/org/exist/storage/lock/Locked.java
View
206 src/org/exist/collections/CollectionConfigurationManager.java
@@ -27,6 +27,7 @@
import org.exist.storage.DBBroker;
import org.exist.storage.IndexSpec;
import org.exist.storage.lock.Lock;
+import org.exist.storage.lock.Locked;
import org.exist.storage.txn.TransactionManager;
import org.exist.storage.txn.Txn;
import org.exist.util.LockException;
@@ -38,8 +39,11 @@
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
+
import java.io.StringReader;
import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.Callable;
/**
* Manages index configurations. Index configurations are stored in a collection
@@ -55,10 +59,10 @@
private static final Logger LOG = Logger.getLogger(CollectionConfigurationManager.class);
public final static String CONFIG_COLLECTION = XmldbURI.SYSTEM_COLLECTION + "/config";
+
/** /db/system/config **/
public final static XmldbURI CONFIG_COLLECTION_URI = XmldbURI.create(CONFIG_COLLECTION);
- // TODO : create using resolve()
/** /db/system/config/db **/
public final static XmldbURI ROOT_COLLECTION_CONFIG_URI = CONFIG_COLLECTION_URI.append(XmldbURI.ROOT_COLLECTION_NAME);
@@ -68,17 +72,17 @@
private Map<CollectionURI, CollectionConfiguration> configurations = new HashMap<CollectionURI, CollectionConfiguration>();
- private Object latch;
+ private Locked latch = new Locked();
private CollectionConfiguration defaultConfig;
public CollectionConfigurationManager(DBBroker broker) throws EXistException, CollectionConfigurationException, PermissionDeniedException, LockException {
- this.latch = broker.getBrokerPool().getCollectionsCache();
checkCreateCollection(broker, CONFIG_COLLECTION_URI);
checkCreateCollection(broker, ROOT_COLLECTION_CONFIG_URI);
loadAllConfigurations(broker);
+
defaultConfig = new CollectionConfiguration(broker.getBrokerPool());
defaultConfig.setIndexConfiguration(broker.getIndexConfiguration());
}
@@ -97,7 +101,7 @@ public CollectionConfigurationManager(DBBroker broker) throws EXistException, Co
* the xconf document as a String.
* @throws CollectionConfigurationException
*/
- public void addConfiguration(Txn txn, DBBroker broker, Collection collection, String config) throws CollectionConfigurationException {
+ public void addConfiguration(Txn txn, final DBBroker broker, Collection collection, String config) throws CollectionConfigurationException {
try {
final XmldbURI path = CONFIG_COLLECTION_URI.append(collection.getURI());
@@ -125,10 +129,17 @@ public void addConfiguration(Txn txn, DBBroker broker, Collection collection, St
confCol.store(txn, broker, info, config, false);
// broker.sync(Sync.MAJOR_SYNC);
- synchronized (latch) {
- configurations.remove(new CollectionURI(path.getRawCollectionPath()));
- loadConfiguration(broker, confCol);
- }
+ latch.writeE(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+
+ configurations.remove(new CollectionURI(path.getRawCollectionPath()));
+ loadConfiguration(broker, confCol);
+
+ return null;
+ }
+ });
+
} catch (final CollectionConfigurationException e) {
throw e;
} catch (final Exception e) {
@@ -168,20 +179,28 @@ public void testConfiguration(DBBroker broker, String config) throws CollectionC
}
}
- public List<Object> getCustomIndexSpecs(String customIndexId) {
- List<Object> configs = new ArrayList<Object>(10);
- synchronized (latch) {
- for (CollectionConfiguration config : configurations.values()) {
- IndexSpec spec = config.getIndexConfiguration();
- if (spec != null) {
- Object customConfig = spec.getCustomIndexSpec(customIndexId);
- if (customConfig != null) {
- configs.add(customConfig);
+ public List<Object> getCustomIndexSpecs(final String customIndexId) {
+
+ return latch.read(new Callable<List<Object>>() {
+
+ @Override
+ public List<Object> call() throws Exception {
+
+ List<Object> configs = new ArrayList<Object>(10);
+
+ for (CollectionConfiguration config: configurations.values()) {
+ IndexSpec spec = config.getIndexConfiguration();
+ if (spec != null) {
+ Object customConfig = spec.getCustomIndexSpec(customIndexId);
+ if (customConfig != null) {
+ configs.add(customConfig);
+ }
}
}
+
+ return configs;
}
- }
- return configs;
+ });
}
/**
@@ -206,19 +225,25 @@ protected CollectionConfiguration getConfiguration(DBBroker broker, Collection c
* the root, stopping at the first config file it finds. This should be
* more efficient, and fit more appropriately will the XmldbURI api
*/
- CollectionConfiguration conf;
+ return latch.read(new Callable<CollectionConfiguration>() {
- synchronized (latch) {
- while (!path.equals(COLLECTION_CONFIG_PATH)) {
- conf = configurations.get(path);
- if (conf != null) {
- return conf;
+ @Override
+ public CollectionConfiguration call() throws Exception {
+
+ CollectionConfiguration conf = null;
+
+ while(!path.equals(COLLECTION_CONFIG_PATH)) {
+ conf = configurations.get(path);
+ if (conf != null) {
+ return conf;
+ }
+ path.removeLastSegment();
}
- path.removeLastSegment();
+
+ // use default configuration
+ return defaultConfig;
}
- }
- // use default configuration
- return defaultConfig;
+ });
}
protected void loadAllConfigurations(DBBroker broker) throws CollectionConfigurationException, PermissionDeniedException, LockException {
@@ -243,7 +268,7 @@ protected void loadAllConfigurations(DBBroker broker, Collection configCollectio
}
}
- protected void loadConfiguration(DBBroker broker, Collection configCollection) throws CollectionConfigurationException, PermissionDeniedException,
+ protected void loadConfiguration(DBBroker broker, final Collection configCollection) throws CollectionConfigurationException, PermissionDeniedException,
LockException {
if (configCollection != null && configCollection.getDocumentCount(broker) > 0) {
for (final Iterator<DocumentImpl> i = configCollection.iterator(broker); i.hasNext();) {
@@ -254,9 +279,7 @@ protected void loadConfiguration(DBBroker broker, Collection configCollection) t
}
final CollectionConfiguration conf = new CollectionConfiguration(broker.getBrokerPool());
- // TODO DWES Temporary workaround for bug
- // [ 1807744 ] Invalid collection.xconf causes a non
- // startable database
+ // [ 1807744 ] Invalid collection.xconf causes a non startable database
// http://sourceforge.net/tracker/index.php?func=detail&aid=1807744&group_id=17691&atid=117691
try {
conf.read(broker, confDoc, false, configCollection.getURI(), confDoc.getFileURI());
@@ -266,33 +289,56 @@ protected void loadConfiguration(DBBroker broker, Collection configCollection) t
LOG.error(message);
System.out.println(message);
}
+
+ latch.write(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+
+ configurations.put(new CollectionURI(configCollection.getURI().getRawCollectionPath()), conf);
+
+ return null;
+ }
+ });
- synchronized (latch) {
- configurations.put(new CollectionURI(configCollection.getURI().getRawCollectionPath()), conf);
- }
// Allow just one configuration document per collection
- // TODO : do not break if a system property allows several
- // ones -pb
+ // TODO : do not break if a system property allows several ones -pb
break;
}
}
}
}
- public CollectionConfiguration getOrCreateCollectionConfiguration(DBBroker broker, Collection collection) {
+ public CollectionConfiguration getOrCreateCollectionConfiguration(final DBBroker broker, Collection collection) {
final CollectionURI path = new CollectionURI(COLLECTION_CONFIG_PATH);
path.append(collection.getURI().getRawCollectionPath());
+
+ CollectionConfiguration conf = latch.read(new Callable<CollectionConfiguration>() {
+ @Override
+ public CollectionConfiguration call() {
+ return configurations.get(path);
+ }
+ });
+
+ if (conf != null) {
+ return conf;
+ }
+
+ return latch.write(new Callable<CollectionConfiguration>() {
+ @Override
+ public CollectionConfiguration call() {
+
+ CollectionConfiguration conf = configurations.get(path);
+
+ if (conf != null) {
+ return conf;
+ }
- CollectionConfiguration conf;
- synchronized (latch) {
- conf = configurations.get(path);
- if (conf == null) {
conf = new CollectionConfiguration(broker.getBrokerPool());
configurations.put(path, conf);
- }
- }
- return conf;
+ return conf;
+ }
+ });
}
/**
@@ -302,16 +348,39 @@ public CollectionConfiguration getOrCreateCollectionConfiguration(DBBroker broke
*
* @param collectionPath
*/
- public void invalidateAll(XmldbURI collectionPath) {
- // TODO : use XmldbURI.resolve !
+ public void invalidateAll(final XmldbURI collectionPath) {
+
if (!collectionPath.startsWith(CONFIG_COLLECTION_URI)) {
return;
}
+
+ latch.write(new Callable<Void>() {
+ @Override
+ public Void call() {
- synchronized (latch) {
- LOG.debug("Invalidating collection " + collectionPath);
- configurations.remove(new CollectionURI(collectionPath.getRawCollectionPath()));
- }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Invalidating collection " + collectionPath + " and subcollections");
+ }
+
+ CollectionURI uri = new CollectionURI(collectionPath.getRawCollectionPath());
+
+ configurations.remove(uri);
+
+ String str = uri.toString();
+
+ Iterator<Entry<CollectionURI, CollectionConfiguration>> it = configurations.entrySet().iterator();
+
+ while (it.hasNext()) {
+ Entry<CollectionURI, CollectionConfiguration> entry = it.next();
+
+ if (entry.getKey().toString().startsWith(str)) {
+ it.remove();
+ }
+ }
+
+ return null;
+ }
+ });
}
/**
@@ -320,21 +389,24 @@ public void invalidateAll(XmldbURI collectionPath) {
*
* @param collectionPath
*/
- protected void invalidate(XmldbURI collectionPath) {
- // TODO : use XmldbURI.resolve !
- // if (!collectionPath.startsWith(XmldbURI.CONFIG_COLLECTION_URI))
- // return;
- // collectionPath =
- // collectionPath.trimFromBeginning(XmldbURI.CONFIG_COLLECTION_URI);
- // CollectionCache collectionCache = pool.getCollectionsCache();
- // synchronized (collectionCache) {
- // CollectionConfiguration config = (CollectionConfiguration)
- // cache.get(collectionPath);
- // if (config != null) {
- // config.getCollection().invalidateConfiguration();
- // cache.remove(collectionPath);
- // }
- // }
+ protected void invalidate(final XmldbURI collectionPath) {
+ if (!collectionPath.startsWith(CONFIG_COLLECTION_URI)) {
+ return;
+ }
+
+ latch.write(new Callable<Void>() {
+ @Override
+ public Void call() {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Invalidating collection " + collectionPath);
+ }
+
+ configurations.remove(new CollectionURI(collectionPath.getRawCollectionPath()));
+
+ return null;
+ }
+ });
}
/**
View
69 src/org/exist/storage/lock/Locked.java
@@ -0,0 +1,69 @@
+/*
+ * eXist Open Source Native XML Database
+ * Copyright (C) 2001-2013 The eXist Project
+ * http://exist-db.org
+ *
+ * This program 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package org.exist.storage.lock;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+
+/**
+ * @author <a href="mailto:shabanovd@gmail.com">Dmitriy Shabanov</a>
+ *
+ */
+public class Locked {
+
+ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+ private final ReadLock readLock = lock.readLock();
+ private final WriteLock writeLock = lock.writeLock();
+
+ public final <R> R read(final Callable<R> readOp) {
+ readLock.lock();
+ try {
+ return readOp.call();
+ } catch (Exception e) {
+ //can't be ignore
+ return (R)e;
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ public final <R> R write(final Callable<R> writeOp) {
+ writeLock.lock();
+ try {
+ return writeOp.call();
+ } catch (Exception e) {
+ //can't be ignore
+ return (R)e;
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ public final <R> R writeE(final Callable<R> writeOp) throws Exception {
+ writeLock.lock();
+ try {
+ return writeOp.call();
+ } finally {
+ writeLock.unlock();
+ }
+ }
+}

0 comments on commit 75fd5be

Please sign in to comment.
Something went wrong with that request. Please try again.