[infinispan-commits] Infinispan SVN: r1606 - in trunk/lucene-directory/src: main/java/org/infinispan/lucene/locking and 2 other directories.
infinispan-commits at lists.jboss.org
infinispan-commits at lists.jboss.org
Sun Mar 14 14:56:43 EDT 2010
Author: sannegrinovero
Date: 2010-03-14 14:56:42 -0400 (Sun, 14 Mar 2010)
New Revision: 1606
Added:
trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/BaseLockFactory.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/BaseLuceneLock.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/TransactionalLockFactory.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/TransactionalSharedLuceneLock.java
Removed:
trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/LuceneLockFactory.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/SharedLuceneLock.java
Modified:
trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanDirectory.java
trunk/lucene-directory/src/test/java/org/infinispan/lucene/CacheTestSupport.java
trunk/lucene-directory/src/test/java/org/infinispan/lucene/locking/LockManagerFunctionalTest.java
Log:
[ISPN-372] (Create a plain Lucene LockFactory not using a TransactionManager)
Modified: trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanDirectory.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanDirectory.java 2010-03-14 18:44:18 UTC (rev 1605)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanDirectory.java 2010-03-14 18:56:42 UTC (rev 1606)
@@ -31,7 +31,7 @@
import org.apache.lucene.store.IndexOutput;
import org.apache.lucene.store.LockFactory;
import org.infinispan.Cache;
-import org.infinispan.lucene.locking.LuceneLockFactory;
+import org.infinispan.lucene.locking.BaseLockFactory;
import org.infinispan.util.concurrent.ConcurrentHashSet;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
@@ -39,12 +39,12 @@
/**
* Implementation that uses Infinispan to store Lucene indices.
*
- * Directory locking is assured with {@link org.infinispan.lucene.locking.SharedLuceneLock}
+ * Directory locking is assured with {@link org.infinispan.lucene.locking.TransactionalSharedLuceneLock}
*
* @since 4.0
* @author Lukasz Moren
* @author Sanne Grinovero
- * @see org.infinispan.lucene.locking.LuceneLockFactory
+ * @see org.infinispan.lucene.locking.TransactionalLockFactory
*/
// todo add support for ConcurrentMergeSheduler
public class InfinispanDirectory extends Directory {
@@ -77,11 +77,11 @@
}
public InfinispanDirectory(Cache<CacheKey, Object> cache, String indexName, int chunkSize) {
- this(cache, indexName, new LuceneLockFactory(cache, indexName), chunkSize);
+ this(cache, indexName, new BaseLockFactory(cache, indexName), chunkSize);
}
public InfinispanDirectory(Cache<CacheKey, Object> cache, String indexName) {
- this(cache, indexName, new LuceneLockFactory(cache, indexName), InfinispanIndexIO.DEFAULT_BUFFER_SIZE);
+ this(cache, indexName, new BaseLockFactory(cache, indexName), InfinispanIndexIO.DEFAULT_BUFFER_SIZE);
}
public InfinispanDirectory(Cache<CacheKey, Object> cache) {
Added: trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/BaseLockFactory.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/BaseLockFactory.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/BaseLockFactory.java 2010-03-14 18:56:42 UTC (rev 1606)
@@ -0,0 +1,93 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This 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.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene.locking;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.store.LockFactory;
+import org.infinispan.Cache;
+import org.infinispan.lucene.CacheKey;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+/**
+ * Default factory for locks obtained in <code>InfinispanDirectory</code>,
+ * this factory produces instances of <code>BaseLuceneLock</code>.
+ *
+ * @since 4.0
+ * @author Sanne Grinovero
+ * @see org.infinispan.lucene.InfinispanDirectory
+ * @see org.infinispan.lucene.locking.BaseLuceneLock
+ */
+public class BaseLockFactory extends LockFactory {
+
+ private static final Log log = LogFactory.getLog(BaseLockFactory.class);
+ static final String DEF_LOCK_NAME = IndexWriter.WRITE_LOCK_NAME;
+
+ private final Cache<CacheKey, Object> cache;
+ private final String indexName;
+ private final BaseLuceneLock defLock;
+
+ public BaseLockFactory(Cache<CacheKey, Object> cache, String indexName) {
+ this.cache = cache;
+ this.indexName = indexName;
+ defLock = new BaseLuceneLock(cache, indexName, DEF_LOCK_NAME);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public BaseLuceneLock makeLock(String lockName) {
+ BaseLuceneLock lock;
+ //It appears Lucene always uses the same name so we give locks
+ //having this name a special treatment:
+ if (DEF_LOCK_NAME.equals(lockName)) {
+ lock = defLock;
+ }
+ else {
+ // this branch is never taken with current Lucene version.
+ lock = new BaseLuceneLock(cache, indexName, lockName);
+ }
+ if (log.isTraceEnabled()) {
+ log.trace("Lock prepared, not acquired: {0} for index {1}", lockName, indexName);
+ }
+ return lock;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void clearLock(String lockName) throws IOException {
+ //Same special care as above for locks named DEF_LOCK_NAME:
+ if (DEF_LOCK_NAME.equals(lockName)) {
+ defLock.clearLock();
+ }
+ else {
+ new BaseLuceneLock(cache, indexName, lockName).clearLock();
+ }
+ if (log.isTraceEnabled()) {
+ log.trace("Removed lock: {0} for index {1}", lockName, indexName);
+ }
+ }
+
+}
Copied: trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/BaseLuceneLock.java (from rev 1604, trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/SharedLuceneLock.java)
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/BaseLuceneLock.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/BaseLuceneLock.java 2010-03-14 18:56:42 UTC (rev 1606)
@@ -0,0 +1,105 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This 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.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene.locking;
+
+import java.io.IOException;
+
+import org.apache.lucene.store.Lock;
+import org.infinispan.AdvancedCache;
+import org.infinispan.Cache;
+import org.infinispan.context.Flag;
+import org.infinispan.lucene.CacheKey;
+import org.infinispan.lucene.FileCacheKey;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+/**
+ * Inter-IndexWriter Lucene index lock based on Infinispan.
+ * This implementation is not bound to and does not need a TransactionManager,
+ * is more suited for large batch work and index optimization.
+ *
+ * @since 4.0
+ * @author Sanne Grinovero
+ * @see org.apache.lucene.store.Lock
+ */
+class BaseLuceneLock extends Lock {
+
+ private static final Log log = LogFactory.getLog(BaseLuceneLock.class);
+ private static final Flag[] lockFlags = new Flag[]{Flag.SKIP_CACHE_STORE};
+
+ private final AdvancedCache<CacheKey, Object> cache;
+ private final String lockName;
+ private final String indexName;
+ private final FileCacheKey keyOfLock;
+
+ BaseLuceneLock(Cache<CacheKey, Object> cache, String indexName, String lockName) {
+ this.cache = cache.getAdvancedCache();
+ this.lockName = lockName;
+ this.indexName = indexName;
+ this.keyOfLock = new FileCacheKey(indexName, lockName, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean obtain() throws IOException {
+ Object previousValue = cache.withFlags(lockFlags).putIfAbsent(keyOfLock, keyOfLock);
+ if (previousValue == null) {
+ if (log.isTraceEnabled()) {
+ log.trace("Lock: {0} acquired for index: {1}", lockName, indexName);
+ }
+ // we own the lock:
+ return true;
+ } else {
+ if (log.isTraceEnabled()) {
+ log.trace("Lock: {0} not aquired for index: {1}, was taken already.", lockName, indexName);
+ }
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void release() throws IOException {
+ clearLock();
+ }
+
+ /**
+ * Used by Lucene at Directory creation: we expect the lock to not exist in this case.
+ */
+ public void clearLock() {
+ Object previousValue = cache.withFlags(lockFlags).remove(keyOfLock);
+ if (previousValue!=null && log.isTraceEnabled()) {
+ log.trace("Lock removed for index: {0}", indexName);
+ }
+ }
+
+ @Override
+ public boolean isLocked() {
+ boolean locked = cache.withFlags(lockFlags).containsKey(keyOfLock);
+ return locked;
+ }
+
+}
\ No newline at end of file
Deleted: trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/LuceneLockFactory.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/LuceneLockFactory.java 2010-03-14 18:44:18 UTC (rev 1605)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/LuceneLockFactory.java 2010-03-14 18:56:42 UTC (rev 1606)
@@ -1,109 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2009, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This 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.1 of
- * the License, or (at your option) any later version.
- *
- * This software 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 software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.infinispan.lucene.locking;
-
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.store.LockFactory;
-import org.infinispan.Cache;
-import org.infinispan.CacheException;
-import org.infinispan.lifecycle.ComponentStatus;
-import org.infinispan.lucene.CacheKey;
-import org.infinispan.util.logging.Log;
-import org.infinispan.util.logging.LogFactory;
-
-import javax.transaction.TransactionManager;
-import java.io.IOException;
-
-/**
- * Factory for locks obtained in <code>InfinispanDirectory</code>
- *
- * @since 4.0
- * @author Sanne Grinovero
- * @author Lukasz Moren
- * @see org.infinispan.lucene.InfinispanDirectory
- * @see org.infinispan.lucene.locking.SharedLuceneLock
- */
-public class LuceneLockFactory extends LockFactory {
-
- private static final Log log = LogFactory.getLog(LuceneLockFactory.class);
- static final String DEF_LOCK_NAME = IndexWriter.WRITE_LOCK_NAME;
-
- private final Cache<CacheKey, Object> cache;
- private final String indexName;
- private final TransactionManager tm;
- private final SharedLuceneLock defLock;
-
- public LuceneLockFactory(Cache<CacheKey, Object> cache, String indexName) {
- this.cache = cache;
- this.indexName = indexName;
- tm = cache.getAdvancedCache().getTransactionManager();
- if (tm == null) {
- ComponentStatus status = cache.getAdvancedCache().getComponentRegistry().getStatus();
- if (status.equals(ComponentStatus.RUNNING)) {
- throw new CacheException(
- "Failed looking up TransactionManager. Check if any transaction manager is associated with Infinispan cache: \'"
- + cache.getName() + "\'");
- }
- else {
- throw new CacheException("Failed looking up TransactionManager: the cache is not running");
- }
- }
- defLock = new SharedLuceneLock(cache, indexName, DEF_LOCK_NAME, tm);
- }
-
- /**
- * {@inheritDoc}
- */
- public SharedLuceneLock makeLock(String lockName) {
- SharedLuceneLock lock;
- //It appears Lucene always uses the same name so we give locks
- //having this name a special treatment:
- if (DEF_LOCK_NAME.equals(lockName)) {
- lock = defLock;
- }
- else {
- // this branch is never taken with current Lucene version.
- lock = new SharedLuceneLock(cache, indexName, lockName, tm);
- }
- if (log.isTraceEnabled()) {
- log.trace("Lock prepared, not acquired: {0} for index {1}", lockName, indexName);
- }
- return lock;
- }
-
- /**
- * {@inheritDoc}
- */
- public void clearLock(String lockName) throws IOException {
- //Same special care as above for locks named DEF_LOCK_NAME:
- if (DEF_LOCK_NAME.equals(lockName)) {
- defLock.clearLockSuspending();
- }
- else {
- new SharedLuceneLock(cache, indexName, lockName, tm).clearLockSuspending();
- }
- if (log.isTraceEnabled()) {
- log.trace("Removed lock: {0} for index {1}", lockName, indexName);
- }
- }
-
-}
Deleted: trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/SharedLuceneLock.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/SharedLuceneLock.java 2010-03-14 18:44:18 UTC (rev 1605)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/SharedLuceneLock.java 2010-03-14 18:56:42 UTC (rev 1606)
@@ -1,196 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2009, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This 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.1 of
- * the License, or (at your option) any later version.
- *
- * This software 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 software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.infinispan.lucene.locking;
-
-import java.io.IOException;
-
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-
-import org.apache.lucene.store.Lock;
-import org.infinispan.AdvancedCache;
-import org.infinispan.Cache;
-import org.infinispan.CacheException;
-import org.infinispan.context.Flag;
-import org.infinispan.lucene.CacheKey;
-import org.infinispan.lucene.FileCacheKey;
-import org.infinispan.util.logging.Log;
-import org.infinispan.util.logging.LogFactory;
-
-/**
- * Inter-IndexWriter Lucene index lock based on Infinispan.
- *
- * @since 4.0
- * @author Sanne Grinovero
- * @see org.apache.lucene.store.Lock
- */
-class SharedLuceneLock extends Lock {
-
- private static final Log log = LogFactory.getLog(SharedLuceneLock.class);
- private static final Flag[] lockFlags = new Flag[]{Flag.SKIP_CACHE_STORE};
-
- private final AdvancedCache<CacheKey, Object> cache;
- private final String lockName;
- private final String indexName;
- private final TransactionManager tm;
- private final FileCacheKey keyOfLock;
-
- SharedLuceneLock(Cache<CacheKey, Object> cache, String indexName, String lockName, TransactionManager tm) {
- this.cache = cache.getAdvancedCache();
- this.lockName = lockName;
- this.indexName = indexName;
- this.tm = tm;
- this.keyOfLock = new FileCacheKey(indexName, lockName, true);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean obtain() throws IOException {
- Object previousValue = cache.withFlags(lockFlags).putIfAbsent(keyOfLock, keyOfLock);
- if (previousValue == null) {
- if (log.isTraceEnabled()) {
- log.trace("Lock: {0} acquired for index: {1}", lockName, indexName);
- }
- // we own the lock:
- startTransaction();
- return true;
- } else {
- if (log.isTraceEnabled()) {
- log.trace("Lock: {0} not aquired for index: {1}, was taken already.", lockName, indexName);
- }
- return false;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void release() throws IOException {
- try {
- commitTransactions();
- }
- finally {
- clearLock();
- }
- }
-
- /**
- * Removes the lock, without committing pending changes or involving transactions. Used by Lucene
- * at Directory creation: we expect the lock to not exist in this case.
- */
- private void clearLock() {
- Object previousValue = cache.withFlags(lockFlags).remove(keyOfLock);
- if (previousValue!=null && log.isTraceEnabled()) {
- log.trace("Lock removed for index: {0}", indexName);
- }
- }
-
- @Override
- public boolean isLocked() {
- boolean locked = false;
- Transaction tx = null;
- try {
- // if there is an ongoing transaction we need to suspend it
- if ((tx = tm.getTransaction()) != null) {
- tm.suspend();
- }
- locked = cache.withFlags(lockFlags).containsKey(keyOfLock);
- } catch (Exception e) {
- log.error("Error in suspending transaction", e);
- } finally {
- if (tx != null) {
- try {
- tm.resume(tx);
- } catch (Exception e) {
- throw new CacheException("Unable to resume suspended transaction " + tx, e);
- }
- }
- }
- return locked;
- }
-
- /**
- * Starts a new transaction. Used to batch changes in LuceneDirectory:
- * a transaction is created at lock acquire, and closed on release.
- * It's also committed and started again at each IndexWriter.commit();
- *
- * @throws IOException wraps Infinispan exceptions to adapt to Lucene's API
- */
- private void startTransaction() throws IOException {
- try {
- tm.begin();
- } catch (Exception e) {
- log.error("Unable to start transaction", e);
- throw new IOException("SharedLuceneLock could not start a transaction after having acquired the lock", e);
- }
- if (log.isTraceEnabled()) {
- log.trace("Batch transaction started for index: {0}", indexName);
- }
- }
-
- /**
- * Commits the existing transaction.
- * It's illegal to call this if a transaction was not started.
- *
- * @throws IOException wraps Infinispan exceptions to adapt to Lucene's API
- */
- private void commitTransactions() throws IOException {
- try {
- tm.commit();
- } catch (Exception e) {
- log.error("Unable to commit work done!", e);
- throw new IOException("SharedLuceneLock could not commit a transaction", e);
- }
- if (log.isTraceEnabled()) {
- log.trace("Batch transaction commited for index: {0}", indexName);
- }
- }
-
- /**
- * FIXME Comment this
- *
- */
- public void clearLockSuspending() {
- Transaction tx = null;
- try {
- // if there is an ongoing transaction we need to suspend it
- if ((tx = tm.getTransaction()) != null) {
- tm.suspend();
- }
- clearLock();
- } catch (Exception e) {
- log.error("Error in suspending transaction", e);
- } finally {
- if (tx != null) {
- try {
- tm.resume(tx);
- } catch (Exception e) {
- throw new CacheException("Unable to resume suspended transaction " + tx, e);
- }
- }
- }
- }
-
-}
\ No newline at end of file
Copied: trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/TransactionalLockFactory.java (from rev 1604, trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/LuceneLockFactory.java)
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/TransactionalLockFactory.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/TransactionalLockFactory.java 2010-03-14 18:56:42 UTC (rev 1606)
@@ -0,0 +1,120 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This 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.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene.locking;
+
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.store.LockFactory;
+import org.infinispan.Cache;
+import org.infinispan.CacheException;
+import org.infinispan.lifecycle.ComponentStatus;
+import org.infinispan.lucene.CacheKey;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+import javax.transaction.TransactionManager;
+import java.io.IOException;
+
+/**
+ * <p>Factory for locks obtained in <code>InfinispanDirectory</code>,
+ * this factory produces instances of <code>TransactionalSharedLuceneLock</code>.</p>
+ * <p>Usually Lucene acquires the lock when creating an IndexWriter and releases it
+ * when closing it; this is open-close is mapped to transactions as begin-commit,
+ * so all changes are going to be effective at IndexWriter close and could need
+ * much memory until it's committed.
+ * The advantage is that a transaction rollback will be able to undo all changes
+ * applied to the index.</p>
+ * <p>Using a TransactionalSharedLuceneLock is not compatible with Lucene's
+ * default MergeScheduler: use an in-thread implementation like SerialMergeScheduler
+ * <code>iwriter.setMergeScheduler( new SerialMergeScheduler() );</code></p>
+ *
+ * @since 4.0
+ * @author Sanne Grinovero
+ * @author Lukasz Moren
+ * @see org.infinispan.lucene.InfinispanDirectory
+ * @see org.infinispan.lucene.locking.TransactionalSharedLuceneLock
+ * @see org.apache.lucene.index.SerialMergeScheduler
+ */
+public class TransactionalLockFactory extends LockFactory {
+
+ private static final Log log = LogFactory.getLog(TransactionalLockFactory.class);
+ static final String DEF_LOCK_NAME = IndexWriter.WRITE_LOCK_NAME;
+
+ private final Cache<CacheKey, Object> cache;
+ private final String indexName;
+ private final TransactionManager tm;
+ private final TransactionalSharedLuceneLock defLock;
+
+ public TransactionalLockFactory(Cache<CacheKey, Object> cache, String indexName) {
+ this.cache = cache;
+ this.indexName = indexName;
+ tm = cache.getAdvancedCache().getTransactionManager();
+ if (tm == null) {
+ ComponentStatus status = cache.getAdvancedCache().getComponentRegistry().getStatus();
+ if (status.equals(ComponentStatus.RUNNING)) {
+ throw new CacheException(
+ "Failed looking up TransactionManager. Check if any transaction manager is associated with Infinispan cache: \'"
+ + cache.getName() + "\'");
+ }
+ else {
+ throw new CacheException("Failed looking up TransactionManager: the cache is not running");
+ }
+ }
+ defLock = new TransactionalSharedLuceneLock(cache, indexName, DEF_LOCK_NAME, tm);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public TransactionalSharedLuceneLock makeLock(String lockName) {
+ TransactionalSharedLuceneLock lock;
+ //It appears Lucene always uses the same name so we give locks
+ //having this name a special treatment:
+ if (DEF_LOCK_NAME.equals(lockName)) {
+ lock = defLock;
+ }
+ else {
+ // this branch is never taken with current Lucene version.
+ lock = new TransactionalSharedLuceneLock(cache, indexName, lockName, tm);
+ }
+ if (log.isTraceEnabled()) {
+ log.trace("Lock prepared, not acquired: {0} for index {1}", lockName, indexName);
+ }
+ return lock;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void clearLock(String lockName) throws IOException {
+ //Same special care as above for locks named DEF_LOCK_NAME:
+ if (DEF_LOCK_NAME.equals(lockName)) {
+ defLock.clearLockSuspending();
+ }
+ else {
+ new TransactionalSharedLuceneLock(cache, indexName, lockName, tm).clearLockSuspending();
+ }
+ if (log.isTraceEnabled()) {
+ log.trace("Removed lock: {0} for index {1}", lockName, indexName);
+ }
+ }
+
+}
Copied: trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/TransactionalSharedLuceneLock.java (from rev 1604, trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/SharedLuceneLock.java)
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/TransactionalSharedLuceneLock.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/locking/TransactionalSharedLuceneLock.java 2010-03-14 18:56:42 UTC (rev 1606)
@@ -0,0 +1,199 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This 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.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene.locking;
+
+import java.io.IOException;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.apache.lucene.store.Lock;
+import org.infinispan.AdvancedCache;
+import org.infinispan.Cache;
+import org.infinispan.CacheException;
+import org.infinispan.context.Flag;
+import org.infinispan.lucene.CacheKey;
+import org.infinispan.lucene.FileCacheKey;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+/**
+ * Inter-IndexWriter Lucene index lock based on Infinispan.
+ * There are pros and cons about using this implementation, please see javadoc on
+ * the factory class <code>org.infinispan.lucene.locking.TransactionalLockFactory</code>
+ *
+ * @since 4.0
+ * @author Sanne Grinovero
+ * @see org.infinispan.lucene.locking.TransactionalLockFactory
+ * @see org.apache.lucene.store.Lock
+ */
+class TransactionalSharedLuceneLock extends Lock {
+
+ private static final Log log = LogFactory.getLog(TransactionalSharedLuceneLock.class);
+ private static final Flag[] lockFlags = new Flag[]{Flag.SKIP_CACHE_STORE};
+
+ private final AdvancedCache<CacheKey, Object> cache;
+ private final String lockName;
+ private final String indexName;
+ private final TransactionManager tm;
+ private final FileCacheKey keyOfLock;
+
+ TransactionalSharedLuceneLock(Cache<CacheKey, Object> cache, String indexName, String lockName, TransactionManager tm) {
+ this.cache = cache.getAdvancedCache();
+ this.lockName = lockName;
+ this.indexName = indexName;
+ this.tm = tm;
+ this.keyOfLock = new FileCacheKey(indexName, lockName, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean obtain() throws IOException {
+ Object previousValue = cache.withFlags(lockFlags).putIfAbsent(keyOfLock, keyOfLock);
+ if (previousValue == null) {
+ if (log.isTraceEnabled()) {
+ log.trace("Lock: {0} acquired for index: {1}", lockName, indexName);
+ }
+ // we own the lock:
+ startTransaction();
+ return true;
+ } else {
+ if (log.isTraceEnabled()) {
+ log.trace("Lock: {0} not aquired for index: {1}, was taken already.", lockName, indexName);
+ }
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void release() throws IOException {
+ try {
+ commitTransactions();
+ }
+ finally {
+ clearLock();
+ }
+ }
+
+ /**
+ * Removes the lock, without committing pending changes or involving transactions. Used by Lucene
+ * at Directory creation: we expect the lock to not exist in this case.
+ */
+ private void clearLock() {
+ Object previousValue = cache.withFlags(lockFlags).remove(keyOfLock);
+ if (previousValue!=null && log.isTraceEnabled()) {
+ log.trace("Lock removed for index: {0}", indexName);
+ }
+ }
+
+ @Override
+ public boolean isLocked() {
+ boolean locked = false;
+ Transaction tx = null;
+ try {
+ // if there is an ongoing transaction we need to suspend it
+ if ((tx = tm.getTransaction()) != null) {
+ tm.suspend();
+ }
+ locked = cache.withFlags(lockFlags).containsKey(keyOfLock);
+ } catch (Exception e) {
+ log.error("Error in suspending transaction", e);
+ } finally {
+ if (tx != null) {
+ try {
+ tm.resume(tx);
+ } catch (Exception e) {
+ throw new CacheException("Unable to resume suspended transaction " + tx, e);
+ }
+ }
+ }
+ return locked;
+ }
+
+ /**
+ * Starts a new transaction. Used to batch changes in LuceneDirectory:
+ * a transaction is created at lock acquire, and closed on release.
+ * It's also committed and started again at each IndexWriter.commit();
+ *
+ * @throws IOException wraps Infinispan exceptions to adapt to Lucene's API
+ */
+ private void startTransaction() throws IOException {
+ try {
+ tm.begin();
+ } catch (Exception e) {
+ log.error("Unable to start transaction", e);
+ throw new IOException("SharedLuceneLock could not start a transaction after having acquired the lock", e);
+ }
+ if (log.isTraceEnabled()) {
+ log.trace("Batch transaction started for index: {0}", indexName);
+ }
+ }
+
+ /**
+ * Commits the existing transaction.
+ * It's illegal to call this if a transaction was not started.
+ *
+ * @throws IOException wraps Infinispan exceptions to adapt to Lucene's API
+ */
+ private void commitTransactions() throws IOException {
+ try {
+ tm.commit();
+ } catch (Exception e) {
+ log.error("Unable to commit work done!", e);
+ throw new IOException("SharedLuceneLock could not commit a transaction", e);
+ }
+ if (log.isTraceEnabled()) {
+ log.trace("Batch transaction commited for index: {0}", indexName);
+ }
+ }
+
+ /**
+ * Will clear the lock, eventually suspending a running transaction to make sure the
+ * release is immediately taking effect.
+ */
+ public void clearLockSuspending() {
+ Transaction tx = null;
+ try {
+ // if there is an ongoing transaction we need to suspend it
+ if ((tx = tm.getTransaction()) != null) {
+ tm.suspend();
+ }
+ clearLock();
+ } catch (Exception e) {
+ log.error("Error in suspending transaction", e);
+ } finally {
+ if (tx != null) {
+ try {
+ tm.resume(tx);
+ } catch (Exception e) {
+ throw new CacheException("Unable to resume suspended transaction " + tx, e);
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
Modified: trunk/lucene-directory/src/test/java/org/infinispan/lucene/CacheTestSupport.java
===================================================================
--- trunk/lucene-directory/src/test/java/org/infinispan/lucene/CacheTestSupport.java 2010-03-14 18:44:18 UTC (rev 1605)
+++ trunk/lucene-directory/src/test/java/org/infinispan/lucene/CacheTestSupport.java 2010-03-14 18:56:42 UTC (rev 1606)
@@ -92,8 +92,7 @@
// this is a write
IndexWriter writer = null;
try {
- writer = new IndexWriter(d, LuceneSettings.analyzer, IndexWriter.MaxFieldLength.UNLIMITED);
- writer.setMergeScheduler(new SerialMergeScheduler());
+ writer = LuceneSettings.openWriter(d);
log.info("IndexWriter was constructed");
Document doc = new Document();
Modified: trunk/lucene-directory/src/test/java/org/infinispan/lucene/locking/LockManagerFunctionalTest.java
===================================================================
--- trunk/lucene-directory/src/test/java/org/infinispan/lucene/locking/LockManagerFunctionalTest.java 2010-03-14 18:44:18 UTC (rev 1605)
+++ trunk/lucene-directory/src/test/java/org/infinispan/lucene/locking/LockManagerFunctionalTest.java 2010-03-14 18:56:42 UTC (rev 1606)
@@ -45,12 +45,12 @@
@SuppressWarnings("unchecked")
public void testLuceneIndexLocking() throws IOException {
final String commonIndexName = "myIndex";
- LuceneLockFactory lockManagerA = new LuceneLockFactory(cache(0, "lucene"), commonIndexName);
- LuceneLockFactory lockManagerB = new LuceneLockFactory(cache(1, "lucene"), commonIndexName);
- LuceneLockFactory isolatedLockManager = new LuceneLockFactory(cache(0, "lucene"), "anotherIndex");
- SharedLuceneLock luceneLockA = lockManagerA.makeLock(LuceneLockFactory.DEF_LOCK_NAME);
- SharedLuceneLock luceneLockB = lockManagerB.makeLock(LuceneLockFactory.DEF_LOCK_NAME);
- SharedLuceneLock anotherLock = isolatedLockManager.makeLock(LuceneLockFactory.DEF_LOCK_NAME);
+ TransactionalLockFactory lockManagerA = new TransactionalLockFactory(cache(0, "lucene"), commonIndexName);
+ TransactionalLockFactory lockManagerB = new TransactionalLockFactory(cache(1, "lucene"), commonIndexName);
+ TransactionalLockFactory isolatedLockManager = new TransactionalLockFactory(cache(0, "lucene"), "anotherIndex");
+ TransactionalSharedLuceneLock luceneLockA = lockManagerA.makeLock(TransactionalLockFactory.DEF_LOCK_NAME);
+ TransactionalSharedLuceneLock luceneLockB = lockManagerB.makeLock(TransactionalLockFactory.DEF_LOCK_NAME);
+ TransactionalSharedLuceneLock anotherLock = isolatedLockManager.makeLock(TransactionalLockFactory.DEF_LOCK_NAME);
assert luceneLockA.obtain();
assert luceneLockB.isLocked();
@@ -60,7 +60,7 @@
luceneLockA.release();
assert ! luceneLockB.isLocked();
assert luceneLockB.obtain();
- lockManagerA.clearLock(LuceneLockFactory.DEF_LOCK_NAME);
+ lockManagerA.clearLock(TransactionalLockFactory.DEF_LOCK_NAME);
assert ! luceneLockB.isLocked();
}
More information about the infinispan-commits
mailing list