All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.lucene.replicator.IndexAndTaxonomyReplicationHandler Maven / Gradle / Ivy

There is a newer version: 10.1.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.lucene.replicator;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexCommit;
import org.apache.lucene.replicator.ReplicationClient.ReplicationHandler;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.IOContext;
import org.apache.lucene.util.InfoStream;

/**
 * A {@link ReplicationHandler} for replication of an index and taxonomy pair. See {@link
 * IndexReplicationHandler} for more detail. This handler ensures that the search and taxonomy
 * indexes are replicated in a consistent way.
 *
 * 

NOTE: if you intend to recreate a taxonomy index, you should make sure to reopen an * IndexSearcher and TaxonomyReader pair via the provided callback, to guarantee that both indexes * are in sync. This handler does not prevent replicating such index and taxonomy pairs, and if they * are reopened by a different thread, unexpected errors can occur, as well as inconsistency between * the taxonomy and index readers. * * @see IndexReplicationHandler * @lucene.experimental * @deprecated use org.apache.lucene.replicator.nrt instead */ @Deprecated public class IndexAndTaxonomyReplicationHandler implements ReplicationHandler { /** * The component used to log messages to the {@link InfoStream#getDefault() default} {@link * InfoStream}. */ public static final String INFO_STREAM_COMPONENT = "IndexAndTaxonomyReplicationHandler"; private final Directory indexDir; private final Directory taxoDir; private final Callable callback; private volatile Map> currentRevisionFiles; private volatile String currentVersion; private volatile InfoStream infoStream = InfoStream.getDefault(); /** * Constructor with the given index directory and callback to notify when the indexes were * updated. */ public IndexAndTaxonomyReplicationHandler( Directory indexDir, Directory taxoDir, Callable callback) throws IOException { this.callback = callback; this.indexDir = indexDir; this.taxoDir = taxoDir; currentRevisionFiles = null; currentVersion = null; final boolean indexExists = DirectoryReader.indexExists(indexDir); final boolean taxoExists = DirectoryReader.indexExists(taxoDir); if (indexExists != taxoExists) { throw new IllegalStateException( "search and taxonomy indexes must either both exist or not: index=" + indexExists + " taxo=" + taxoExists); } if (indexExists) { // both indexes exist final IndexCommit indexCommit = IndexReplicationHandler.getLastCommit(indexDir); final IndexCommit taxoCommit = IndexReplicationHandler.getLastCommit(taxoDir); currentRevisionFiles = IndexAndTaxonomyRevision.revisionFiles(indexCommit, taxoCommit); currentVersion = IndexAndTaxonomyRevision.revisionVersion(indexCommit, taxoCommit); final InfoStream infoStream = InfoStream.getDefault(); if (infoStream.isEnabled(INFO_STREAM_COMPONENT)) { infoStream.message( INFO_STREAM_COMPONENT, "constructor(): currentVersion=" + currentVersion + " currentRevisionFiles=" + currentRevisionFiles); infoStream.message( INFO_STREAM_COMPONENT, "constructor(): indexCommit=" + indexCommit + " taxoCommit=" + taxoCommit); } } } @Override public String currentVersion() { return currentVersion; } @Override public Map> currentRevisionFiles() { return currentRevisionFiles; } @Override public void revisionReady( String version, Map> revisionFiles, Map> copiedFiles, Map sourceDirectory) throws IOException { Directory taxoClientDir = sourceDirectory.get(IndexAndTaxonomyRevision.TAXONOMY_SOURCE); Directory indexClientDir = sourceDirectory.get(IndexAndTaxonomyRevision.INDEX_SOURCE); List taxoFiles = copiedFiles.get(IndexAndTaxonomyRevision.TAXONOMY_SOURCE); List indexFiles = copiedFiles.get(IndexAndTaxonomyRevision.INDEX_SOURCE); String taxoSegmentsFile = IndexReplicationHandler.getSegmentsFile(taxoFiles, true); String indexSegmentsFile = IndexReplicationHandler.getSegmentsFile(indexFiles, false); String taxoPendingFile = taxoSegmentsFile == null ? null : "pending_" + taxoSegmentsFile; String indexPendingFile = "pending_" + indexSegmentsFile; boolean success = false; try { // copy taxonomy files before index files IndexReplicationHandler.copyFiles(taxoClientDir, taxoDir, taxoFiles); IndexReplicationHandler.copyFiles(indexClientDir, indexDir, indexFiles); // fsync all copied files (except segmentsFile) if (!taxoFiles.isEmpty()) { taxoDir.sync(taxoFiles); } indexDir.sync(indexFiles); // now copy, fsync, and rename segmentsFile, taxonomy first because it is ok if a // reader sees a more advanced taxonomy than the index. if (taxoSegmentsFile != null) { taxoDir.copyFrom(taxoClientDir, taxoSegmentsFile, taxoPendingFile, IOContext.READONCE); } indexDir.copyFrom(indexClientDir, indexSegmentsFile, indexPendingFile, IOContext.READONCE); if (taxoSegmentsFile != null) { taxoDir.sync(Collections.singletonList(taxoPendingFile)); } indexDir.sync(Collections.singletonList(indexPendingFile)); if (taxoSegmentsFile != null) { taxoDir.rename(taxoPendingFile, taxoSegmentsFile); taxoDir.syncMetaData(); } indexDir.rename(indexPendingFile, indexSegmentsFile); indexDir.syncMetaData(); success = true; } finally { if (!success) { if (taxoSegmentsFile != null) { taxoFiles.add(taxoSegmentsFile); // add it back so it gets deleted too taxoFiles.add(taxoPendingFile); } IndexReplicationHandler.cleanupFilesOnFailure(taxoDir, taxoFiles); indexFiles.add(indexSegmentsFile); // add it back so it gets deleted too indexFiles.add(indexPendingFile); IndexReplicationHandler.cleanupFilesOnFailure(indexDir, indexFiles); } } // all files have been successfully copied + sync'd. update the handler's state currentRevisionFiles = revisionFiles; currentVersion = version; if (infoStream.isEnabled(INFO_STREAM_COMPONENT)) { infoStream.message( INFO_STREAM_COMPONENT, "revisionReady(): currentVersion=" + currentVersion + " currentRevisionFiles=" + currentRevisionFiles); } // Cleanup the index directory from old and unused index files. // NOTE: we don't use IndexWriter.deleteUnusedFiles here since it may have // side-effects, e.g. if it hits sudden IO errors while opening the index // (and can end up deleting the entire index). It is not our job to protect // against those errors, app will probably hit them elsewhere. IndexReplicationHandler.cleanupOldIndexFiles(indexDir, indexSegmentsFile, infoStream); IndexReplicationHandler.cleanupOldIndexFiles(taxoDir, taxoSegmentsFile, infoStream); // successfully updated the index, notify the callback that the index is // ready. if (callback != null) { try { callback.call(); } catch (Exception e) { throw new IOException(e); } } } /** Sets the {@link InfoStream} to use for logging messages. */ public void setInfoStream(InfoStream infoStream) { if (infoStream == null) { infoStream = InfoStream.NO_OUTPUT; } this.infoStream = infoStream; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy