diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 27e4606b26e..fe4f8dcc3eb 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -198,6 +198,8 @@ Bug Fixes and getCore that could cause a request to attempt to use a core that has shut down. (yonik) +* SOLR-4926: Fixed rare replication bug that normally only manifested when + using compound file format. (yonik, Mark Miller) Optimizations ---------------------- diff --git a/solr/core/src/java/org/apache/solr/handler/SnapPuller.java b/solr/core/src/java/org/apache/solr/handler/SnapPuller.java index 2717473504a..cc4259bdb3f 100644 --- a/solr/core/src/java/org/apache/solr/handler/SnapPuller.java +++ b/solr/core/src/java/org/apache/solr/handler/SnapPuller.java @@ -403,7 +403,14 @@ public class SnapPuller { successfulInstall = modifyIndexProps(tmpIdxDirName); deleteTmpIdxDir = false; } else { - successfulInstall = moveIndexFiles(tmpIndexDir, indexDir); + solrCore.getUpdateHandler().getSolrCoreState() + .closeIndexWriter(core, true); + try { + successfulInstall = moveIndexFiles(tmpIndexDir, indexDir); + } finally { + solrCore.getUpdateHandler().getSolrCoreState() + .openIndexWriter(core); + } } if (successfulInstall) { if (isFullCopyNeeded) { @@ -426,7 +433,12 @@ public class SnapPuller { successfulInstall = modifyIndexProps(tmpIdxDirName); deleteTmpIdxDir = false; } else { - successfulInstall = moveIndexFiles(tmpIndexDir, indexDir); + solrCore.getUpdateHandler().getSolrCoreState().closeIndexWriter(core, true); + try { + successfulInstall = moveIndexFiles(tmpIndexDir, indexDir); + } finally { + solrCore.getUpdateHandler().getSolrCoreState().openIndexWriter(core); + } } if (successfulInstall) { logReplicationTimeAndConfFiles(modifiedConfFiles, successfulInstall); @@ -443,7 +455,11 @@ public class SnapPuller { core.getDirectoryFactory().remove(indexDir); } } - openNewWriterAndSearcher(isFullCopyNeeded); + if (isFullCopyNeeded) { + solrCore.getUpdateHandler().newIndexWriter(isFullCopyNeeded); + } + + openNewSearcherAndUpdateCommitPoint(isFullCopyNeeded); } replicationStartTime = 0; @@ -615,11 +631,9 @@ public class SnapPuller { return sb; } - private void openNewWriterAndSearcher(boolean isFullCopyNeeded) throws IOException { + private void openNewSearcherAndUpdateCommitPoint(boolean isFullCopyNeeded) throws IOException { SolrQueryRequest req = new LocalSolrQueryRequest(solrCore, new ModifiableSolrParams()); - // reboot the writer on the new index and get a new searcher - solrCore.getUpdateHandler().newIndexWriter(isFullCopyNeeded); RefCounted searcher = null; IndexCommit commitPoint; diff --git a/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java b/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java index 2b345442179..ef0a2a98287 100644 --- a/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java +++ b/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java @@ -187,6 +187,76 @@ public final class DefaultSolrCoreState extends SolrCoreState implements Recover } } } + + @Override + public synchronized void closeIndexWriter(SolrCore core, boolean rollback) + throws IOException { + log.info("Closing IndexWriter..."); + String coreName = core.getName(); + synchronized (writerPauseLock) { + if (closed) { + throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE, "Already closed"); + } + + // we need to wait for the Writer to fall out of use + // first lets stop it from being lent out + pauseWriter = true; + // then lets wait until its out of use + log.info("Waiting until IndexWriter is unused... core=" + coreName); + + while (!writerFree) { + try { + writerPauseLock.wait(100); + } catch (InterruptedException e) {} + + if (closed) { + throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE, + "SolrCoreState already closed"); + } + } + + if (indexWriter != null) { + if (!rollback) { + try { + log.info("Closing old IndexWriter... core=" + coreName); + indexWriter.close(); + } catch (Throwable t) { + SolrException.log(log, "Error closing old IndexWriter. core=" + + coreName, t); + } + } else { + try { + log.info("Rollback old IndexWriter... core=" + coreName); + indexWriter.rollback(); + } catch (Throwable t) { + SolrException.log(log, "Error rolling back old IndexWriter. core=" + + coreName, t); + } + } + } + + } + } + + @Override + public synchronized void openIndexWriter(SolrCore core) throws IOException { + log.info("Creating new IndexWriter..."); + synchronized (writerPauseLock) { + if (closed) { + throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE, "Already closed"); + } + + try { + indexWriter = createMainIndexWriter(core, "DirectUpdateHandler2"); + log.info("New IndexWriter is ready to be used."); + // we need to null this so it picks up the new writer next get call + refCntWriter = null; + } finally { + pauseWriter = false; + writerPauseLock.notifyAll(); + } + } + } @Override public synchronized void rollbackIndexWriter(SolrCore core) throws IOException { diff --git a/solr/core/src/java/org/apache/solr/update/SolrCoreState.java b/solr/core/src/java/org/apache/solr/update/SolrCoreState.java index cad8671e7b1..5464d2894a4 100644 --- a/solr/core/src/java/org/apache/solr/update/SolrCoreState.java +++ b/solr/core/src/java/org/apache/solr/update/SolrCoreState.java @@ -88,6 +88,26 @@ public abstract class SolrCoreState { */ public abstract void newIndexWriter(SolrCore core, boolean rollback) throws IOException; + + /** + * Expert method that closes the IndexWriter - you must call {@link #openIndexWriter(SolrCore)} + * in a finally block after calling this method. + * + * @param core that the IW belongs to + * @param rollback true if IW should rollback rather than close + * @throws IOException If there is a low-level I/O error. + */ + public abstract void closeIndexWriter(SolrCore core, boolean rollback) throws IOException; + + /** + * Expert method that opens the IndexWriter - you must call {@link #closeIndexWriter(SolrCore, boolean)} + * first, and then call this method in a finally block. + * + * @param core that the IW belongs to + * @throws IOException If there is a low-level I/O error. + */ + public abstract void openIndexWriter(SolrCore core) throws IOException; + /** * Get the current IndexWriter. If a new IndexWriter must be created, use the * settings from the given {@link SolrCore}.