[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