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