xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/index/IndexCheck.java (revision 1b93561956b1fb47c6797767615e69b0b4fefced)
11277512bSVladimir Kotal /*
21277512bSVladimir Kotal  * CDDL HEADER START
31277512bSVladimir Kotal  *
41277512bSVladimir Kotal  * The contents of this file are subject to the terms of the
51277512bSVladimir Kotal  * Common Development and Distribution License (the "License").
61277512bSVladimir Kotal  * You may not use this file except in compliance with the License.
71277512bSVladimir Kotal  *
81277512bSVladimir Kotal  * See LICENSE.txt included in this distribution for the specific
91277512bSVladimir Kotal  * language governing permissions and limitations under the License.
101277512bSVladimir Kotal  *
111277512bSVladimir Kotal  * When distributing Covered Code, include this CDDL HEADER in each
121277512bSVladimir Kotal  * file and include the License file at LICENSE.txt.
131277512bSVladimir Kotal  * If applicable, add the following below this CDDL HEADER, with the
141277512bSVladimir Kotal  * fields enclosed by brackets "[]" replaced with your own identifying
151277512bSVladimir Kotal  * information: Portions Copyright [yyyy] [name of copyright owner]
161277512bSVladimir Kotal  *
171277512bSVladimir Kotal  * CDDL HEADER END
181277512bSVladimir Kotal  */
191277512bSVladimir Kotal 
201277512bSVladimir Kotal /*
211277512bSVladimir Kotal  * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
221277512bSVladimir Kotal  * Portions Copyright (c) 2018, Chris Fraire <cfraire@me.com>.
231277512bSVladimir Kotal  */
241277512bSVladimir Kotal package org.opengrok.indexer.index;
251277512bSVladimir Kotal 
261277512bSVladimir Kotal import java.io.File;
271277512bSVladimir Kotal import java.io.IOException;
28*1b935619SVladimir Kotal import java.util.Collection;
291277512bSVladimir Kotal import java.util.logging.Level;
301277512bSVladimir Kotal import java.util.logging.Logger;
311277512bSVladimir Kotal import org.apache.lucene.index.SegmentInfos;
321277512bSVladimir Kotal import org.apache.lucene.store.Directory;
331277512bSVladimir Kotal import org.apache.lucene.store.FSDirectory;
341277512bSVladimir Kotal import org.apache.lucene.store.LockFactory;
351277512bSVladimir Kotal import org.apache.lucene.store.NativeFSLockFactory;
361277512bSVladimir Kotal import org.apache.lucene.util.Version;
37552e80caSAdam Hornacek import org.jetbrains.annotations.NotNull;
38552e80caSAdam Hornacek import org.opengrok.indexer.configuration.Configuration;
391277512bSVladimir Kotal import org.opengrok.indexer.logger.LoggerFactory;
401277512bSVladimir Kotal 
411277512bSVladimir Kotal /**
421277512bSVladimir Kotal  * Index checker.
431277512bSVladimir Kotal  *
441277512bSVladimir Kotal  * @author Vladimír Kotal
451277512bSVladimir Kotal  */
461277512bSVladimir Kotal public class IndexCheck {
471277512bSVladimir Kotal     private static final Logger LOGGER = LoggerFactory.getLogger(IndexCheck.class);
481277512bSVladimir Kotal 
491277512bSVladimir Kotal     /**
501277512bSVladimir Kotal      * Exception thrown when index version does not match Lucene version.
511277512bSVladimir Kotal      */
521277512bSVladimir Kotal     public static class IndexVersionException extends Exception {
531277512bSVladimir Kotal 
541277512bSVladimir Kotal         private static final long serialVersionUID = 5693446916108385595L;
551277512bSVladimir Kotal 
56552e80caSAdam Hornacek         private final int luceneIndexVersion;
57552e80caSAdam Hornacek         private final int indexVersion;
581277512bSVladimir Kotal 
IndexVersionException(String s, int luceneIndexVersion, int indexVersion)591277512bSVladimir Kotal         public IndexVersionException(String s, int luceneIndexVersion, int indexVersion) {
601277512bSVladimir Kotal             super(s);
611277512bSVladimir Kotal 
621277512bSVladimir Kotal             this.indexVersion = indexVersion;
631277512bSVladimir Kotal             this.luceneIndexVersion = luceneIndexVersion;
641277512bSVladimir Kotal         }
651277512bSVladimir Kotal 
661277512bSVladimir Kotal         @Override
toString()671277512bSVladimir Kotal         public String toString() {
681277512bSVladimir Kotal             return getMessage() + ": " + String.format("Lucene version = %d", luceneIndexVersion) + ", " +
691277512bSVladimir Kotal                     String.format("index version = %d", indexVersion);
701277512bSVladimir Kotal         }
711277512bSVladimir Kotal     }
721277512bSVladimir Kotal 
IndexCheck()731277512bSVladimir Kotal     private IndexCheck() {
741277512bSVladimir Kotal         // utility class
751277512bSVladimir Kotal     }
761277512bSVladimir Kotal 
771277512bSVladimir Kotal     /**
781277512bSVladimir Kotal      * Check if version of index(es) matches major Lucene version.
79552e80caSAdam Hornacek      * @param configuration configuration based on which to perform the check
80*1b935619SVladimir Kotal      * @param subFilesList collection of paths. If non-empty, only projects matching these paths will be checked.
811277512bSVladimir Kotal      * @return true on success, false on failure
821277512bSVladimir Kotal      */
check(@otNull Configuration configuration, Collection<String> subFilesList)83*1b935619SVladimir Kotal     public static boolean check(@NotNull Configuration configuration, Collection<String> subFilesList) {
84552e80caSAdam Hornacek         File indexRoot = new File(configuration.getDataRoot(), IndexDatabase.INDEX_DIR);
85*1b935619SVladimir Kotal         LOGGER.log(Level.FINE, "Checking for Lucene index version mismatch in {0}", indexRoot);
861277512bSVladimir Kotal         int ret = 0;
871277512bSVladimir Kotal 
881277512bSVladimir Kotal         if (!subFilesList.isEmpty()) {
891277512bSVladimir Kotal             // Assumes projects are enabled.
901277512bSVladimir Kotal             for (String projectName : subFilesList) {
911277512bSVladimir Kotal                 LOGGER.log(Level.FINER,
921277512bSVladimir Kotal                         "Checking Lucene index version in project {0}",
931277512bSVladimir Kotal                         projectName);
941277512bSVladimir Kotal                 ret |= checkDirNoExceptions(new File(indexRoot, projectName));
951277512bSVladimir Kotal             }
961277512bSVladimir Kotal         } else {
97552e80caSAdam Hornacek             if (configuration.isProjectsEnabled()) {
98552e80caSAdam Hornacek                 for (String projectName : configuration.getProjects().keySet()) {
991277512bSVladimir Kotal                     LOGGER.log(Level.FINER,
1001277512bSVladimir Kotal                             "Checking Lucene index version in project {0}",
1011277512bSVladimir Kotal                             projectName);
1021277512bSVladimir Kotal                     ret |= checkDirNoExceptions(new File(indexRoot, projectName));
1031277512bSVladimir Kotal                 }
1041277512bSVladimir Kotal             } else {
1051277512bSVladimir Kotal                 LOGGER.log(Level.FINER, "Checking Lucene index version in {0}",
1061277512bSVladimir Kotal                         indexRoot);
1071277512bSVladimir Kotal                 ret |= checkDirNoExceptions(indexRoot);
1081277512bSVladimir Kotal             }
1091277512bSVladimir Kotal         }
1101277512bSVladimir Kotal 
1111277512bSVladimir Kotal         return ret == 0;
1121277512bSVladimir Kotal     }
1131277512bSVladimir Kotal 
checkDirNoExceptions(File dir)1141277512bSVladimir Kotal     private static int checkDirNoExceptions(File dir) {
1151277512bSVladimir Kotal         try {
1161277512bSVladimir Kotal             checkDir(dir);
1171277512bSVladimir Kotal         } catch (Exception e) {
118552e80caSAdam Hornacek             LOGGER.log(Level.WARNING, "Index check for directory " + dir + " failed", e);
1191277512bSVladimir Kotal             return 1;
1201277512bSVladimir Kotal         }
1211277512bSVladimir Kotal 
1221277512bSVladimir Kotal         return 0;
1231277512bSVladimir Kotal     }
1241277512bSVladimir Kotal 
1251277512bSVladimir Kotal     /**
1261277512bSVladimir Kotal      * Check index in given directory. It assumes that that all commits (if any)
1271277512bSVladimir Kotal      * in the Lucene segment file were done with the same version.
1281277512bSVladimir Kotal      *
1291277512bSVladimir Kotal      * @param dir directory with index
1301277512bSVladimir Kotal      * @throws IOException if the directory cannot be opened
1311277512bSVladimir Kotal      * @throws IndexVersionException if the version of the index does not match Lucene index version
1321277512bSVladimir Kotal      */
checkDir(File dir)1331277512bSVladimir Kotal     public static void checkDir(File dir) throws IndexVersionException, IOException {
1341277512bSVladimir Kotal         LockFactory lockFactory = NativeFSLockFactory.INSTANCE;
1351277512bSVladimir Kotal         int segVersion;
1361277512bSVladimir Kotal 
1371277512bSVladimir Kotal         try (Directory indexDirectory = FSDirectory.open(dir.toPath(), lockFactory)) {
138433284daSVladimir Kotal             SegmentInfos segInfos = SegmentInfos.readLatestCommit(indexDirectory);
1391277512bSVladimir Kotal             segVersion = segInfos.getIndexCreatedVersionMajor();
1401277512bSVladimir Kotal         }
1411277512bSVladimir Kotal 
1421277512bSVladimir Kotal         if (segVersion != Version.LATEST.major) {
1431277512bSVladimir Kotal             throw new IndexVersionException(
144552e80caSAdam Hornacek                 String.format("Directory %s has index version discrepancy", dir),
1451277512bSVladimir Kotal                     Version.LATEST.major, segVersion);
1461277512bSVladimir Kotal         }
1471277512bSVladimir Kotal     }
1481277512bSVladimir Kotal }
149