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);
}
}