package org.infinispan.query.indexmanager; import java.io.IOException; import javax.transaction.Transaction; import javax.transaction.TransactionManager; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.store.Directory; import org.apache.lucene.store.Lock; import org.apache.lucene.store.LockObtainFailedException; import org.hibernate.search.indexes.spi.DirectoryBasedIndexManager; import org.infinispan.lucene.impl.DirectoryExtensions; import org.infinispan.query.backend.TransactionHelper; import org.infinispan.query.logging.Log; import org.infinispan.util.logging.LogFactory; /** * Used to control and override the ownership of the Lucene index lock. * <p> * Rather than wrapping the Directory or the LockManager directly, we need to wrap the IndexManager * as the Directory initialization is deferred. * * @author Sanne Grinovero <sanne@hibernate.org> (C) 2014 Red Hat Inc. * @since 7.0 */ final class IndexManagerBasedLockController implements IndexLockController { private static final Log log = LogFactory.getLog(IndexManagerBasedLockController.class, Log.class); private final DirectoryBasedIndexManager indexManager; private final TransactionHelper transactionHelper; public IndexManagerBasedLockController(DirectoryBasedIndexManager indexManager, TransactionManager tm) { this.indexManager = indexManager; this.transactionHelper = new TransactionHelper(tm); } @Override public boolean waitForAvailability() { final Transaction tx = transactionHelper.suspendTxIfExists(); try { boolean waitForAvailabilityInternal = waitForAvailabilityInternal(); log.waitingForLockAcquired(waitForAvailabilityInternal); return waitForAvailabilityInternal; } finally { transactionHelper.resume(tx); } } /** * This is returning as soon as the lock is available, or after 10 seconds. * * @return true if the lock is free at the time of returning. */ private boolean waitForAvailabilityInternal() { final Directory directory = indexManager.getDirectoryProvider().getDirectory(); try { Lock lock = directory.obtainLock(IndexWriter.WRITE_LOCK_NAME); lock.close(); return true; } catch (LockObtainFailedException lofe) { return false; } catch (IOException e) { log.error(e); return false; } } @Override public void forceLockClear() { final Transaction tx = transactionHelper.suspendTxIfExists(); try { forceLockClearInternal(); } finally { transactionHelper.resume(tx); } } private void forceLockClearInternal() { final Directory directory = indexManager.getDirectoryProvider().getDirectory(); log.warn("Forcing clear of index lock"); ((DirectoryExtensions) directory).forceUnlock(IndexWriter.WRITE_LOCK_NAME); } }