Merge remote-tracking branch 'origin/master'

This commit is contained in:
Noble Paul 2016-10-20 20:07:15 +05:30
commit a4952b11fe
7 changed files with 499 additions and 38 deletions

View File

@ -109,6 +109,8 @@ Improvements
* LUCENE-7439: FuzzyQuery now matches all terms within the specified
edit distance, even if they are short terms (Mike McCandless)
* LUCENE-7496: Better toString for SweetSpotSimilarity (janhoy)
Optimizations
* LUCENE-7501: BKDReader should not store the split dimension explicitly in the

View File

@ -223,4 +223,20 @@ public class SweetSpotSimilarity extends ClassicSimilarity {
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("SweetSpotSimilarity")
.append("(")
.append("ln_min="+ln_min+", ")
.append("ln_max=").append(ln_max).append(", ")
.append("ln_steep=").append(ln_steep).append(", ")
.append("tf_base=").append(tf_base).append(", ")
.append("tf_min=").append(tf_min).append(", ")
.append("tf_hyper_min=").append(tf_hyper_min).append(", ")
.append("tf_hyper_max=").append(tf_hyper_max).append(", ")
.append("tf_hyper_base=").append(tf_hyper_base).append(", ")
.append("tf_hyper_xoffset=").append(tf_hyper_xoffset)
.append(")");
return sb.toString();
}
}

View File

@ -86,8 +86,12 @@ Upgrade Notes
prefix, then you will now get an error as these options are incompatible with numeric faceting.
* Solr's logging verbosity at the INFO level has been greatly reduced, and
you may need to update the log configs to use the DEBUG level to get the
same logging messages as before.
you may need to update the log configs to use the DEBUG level to see all the
logging messages you used to see at INFO level before.
* We are no longer backing up solr.log and solr_gc.log files in date-stamped copies forever. If you relied on
the solr_log_<date> or solr_gc_log_<date> being in the logs folder that will no longer be the case.
See SOLR-9570 for details.
* The create/deleteCollection methods on MiniSolrCloudCluster have been
deprecated. Clients should instead use the CollectionAdminRequest API. In
@ -308,6 +312,13 @@ Other Changes
* SOLR-7850: Moved defaults within bin/solr.in.sh (and bin/solr.in.cmd on Windows) to bin/solr (and bin/solr.cmd)
such that the default state of these files is to set nothing. This makes Solr work better with Docker. (David Smiley)
* SOLR-9570: Various log tidying now happens at Solr startup:
Old solr_log_<date> and solr_gc_log_<date> files are removed, avoiding disks to fill up,
solr.log.X files are rotated, preserving solr.log from last run in solr.log.1, solr.log.1 => solr.log.2 etc
solr-*-console.log files are moved into $SOLR_LOGS_DIR/archived/ instead of being overwritten
Last JVM garbage collection log solr_gc.log is moved into $SOLR_LOGS_DIR/archived/
(janhoy)
================== 6.2.1 ==================
Bug Fixes

View File

@ -1387,20 +1387,10 @@ if [ ! -e "$SOLR_HOME" ]; then
exit 1
fi
# backup the log files before starting
if [ -f "$SOLR_LOGS_DIR/solr.log" ]; then
if $verbose ; then
echo "Backing up $SOLR_LOGS_DIR/solr.log"
fi
mv "$SOLR_LOGS_DIR/solr.log" "$SOLR_LOGS_DIR/solr_log_$(date +"%Y%m%d_%H%M")"
fi
if [ -f "$SOLR_LOGS_DIR/solr_gc.log" ]; then
if $verbose ; then
echo "Backing up $SOLR_LOGS_DIR/solr_gc.log"
fi
mv "$SOLR_LOGS_DIR/solr_gc.log" "$SOLR_LOGS_DIR/solr_gc_log_$(date +"%Y%m%d_%H%M")"
fi
run_tool utils -s "$DEFAULT_SERVER_DIR" -l "$SOLR_LOGS_DIR" -remove_old_solr_logs 7 || echo "Failed removing old solr logs"
run_tool utils -s "$DEFAULT_SERVER_DIR" -l "$SOLR_LOGS_DIR" -archive_gc_logs || echo "Failed archiving old GC logs"
run_tool utils -s "$DEFAULT_SERVER_DIR" -l "$SOLR_LOGS_DIR" -archive_console_logs || echo "Failed archiving old console logs"
run_tool utils -s "$DEFAULT_SERVER_DIR" -l "$SOLR_LOGS_DIR" -rotate_solr_logs 9 || echo "Failed rotating old solr logs"
java_ver_out=`echo "$("$JAVA" -version 2>&1)"`
JAVA_VERSION=`echo $java_ver_out | grep "java version" | awk '{ print substr($3, 2, length($3)-2); }'`

View File

@ -860,19 +860,11 @@ IF ERRORLEVEL 1 (
set IS_64bit=true
)
REM backup log files (use current timestamp for backup name)
For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c-%%a-%%b)
For /f "tokens=1-2 delims=/:" %%a in ("%TIME%") do (set mytime=%%a%%b)
set now_ts=!mydate!_!mytime!
IF EXIST "!SOLR_LOGS_DIR!\solr.log" (
echo Backing up !SOLR_LOGS_DIR!\solr.log
move /Y "!SOLR_LOGS_DIR!\solr.log" "!SOLR_LOGS_DIR!\solr_log_!now_ts!"
)
IF EXIST "!SOLR_LOGS_DIR!\solr_gc.log" (
echo Backing up !SOLR_LOGS_DIR!\solr_gc.log
move /Y "!SOLR_LOGS_DIR!\solr_gc.log" "!SOLR_LOGS_DIR!\solr_gc_log_!now_ts!"
)
REM Clean up and rotate logs
call :run_utils "-remove_old_solr_logs 7" || echo "Failed removing old solr logs"
call :run_utils "-archive_gc_logs" || echo "Failed archiving old GC logs"
call :run_utils "-archive_console_logs" || echo "Failed archiving old console logs"
call :run_utils "-rotate_solr_logs 9" || echo "Failed rotating old solr logs"
IF NOT "%ZK_HOST%"=="" set SOLR_MODE=solrcloud
@ -1136,6 +1128,16 @@ goto done
org.apache.solr.util.SolrCLI version
goto done
:run_utils
set "TOOL_CMD=%~1"
"%JAVA%" %SOLR_SSL_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" -Dlog4j.configuration="file:%DEFAULT_SERVER_DIR%\scripts\cloud-scripts\log4j.properties" ^
-classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^
org.apache.solr.util.SolrCLI utils -s "%DEFAULT_SERVER_DIR%" -l "%SOLR_LOGS_DIR%" %TOOL_CMD%
if errorlevel 1 (
exit /b 1
)
goto done
:parse_create_args
IF [%1]==[] goto run_create
IF "%1"=="-c" goto set_create_name

View File

@ -29,7 +29,10 @@ import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.FileOwnerAttributeView;
import java.time.Instant;
import java.time.Period;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -44,6 +47,8 @@ import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@ -108,11 +113,11 @@ import org.slf4j.LoggerFactory;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.solr.common.params.CommonParams.NAME;
/**
* Command-line utility for working with Solr.
*/
public class SolrCLI {
/**
* Defines the interface to a Solr tool that can be run from this command-line app.
*/
@ -233,7 +238,6 @@ public class SolrCLI {
};
private static void exit(int exitStatus) {
// TODO: determine if we're running in a test and don't exit
try {
System.exit(exitStatus);
} catch (java.lang.SecurityException secExc) {
@ -259,6 +263,18 @@ public class SolrCLI {
exit(0);
}
Tool tool = findTool(args);
CommandLine cli = parseCmdLine(args, tool.getOptions());
System.exit(tool.runTool(cli));
}
public static Tool findTool(String[] args) throws Exception {
String toolType = args[0].trim().toLowerCase(Locale.ROOT);
return newTool(toolType);
}
public static CommandLine parseCmdLine(String[] args, Option[] toolOptions) throws Exception {
String builderClassName = System.getProperty("solr.authentication.httpclient.builder");
if (builderClassName!=null) {
try {
@ -272,10 +288,6 @@ public class SolrCLI {
}
}
// Determine the tool
String toolType = args[0].trim().toLowerCase(Locale.ROOT);
Tool tool = newTool(toolType);
// the parser doesn't like -D props
List<String> toolArgList = new ArrayList<String>();
List<String> dashDList = new ArrayList<String>();
@ -291,7 +303,7 @@ public class SolrCLI {
// process command-line args to configure this application
CommandLine cli =
processCommandLineArgs(joinCommonAndToolOptions(tool.getOptions()), toolArgs);
processCommandLineArgs(joinCommonAndToolOptions(toolOptions), toolArgs);
List argList = cli.getArgList();
argList.addAll(dashDList);
@ -303,8 +315,7 @@ public class SolrCLI {
checkSslStoreSysProp(solrInstallDir, "trustStore");
}
// run the tool
exit(tool.runTool(cli));
return cli;
}
protected static void checkSslStoreSysProp(String solrInstallDir, String key) {
@ -368,6 +379,8 @@ public class SolrCLI {
return new ZkLsTool();
else if ("assert".equals(toolType))
return new AssertTool();
else if ("utils".equals(toolType))
return new UtilsTool();
// If you add a built-in tool to this class, add it here to avoid
// classpath scanning
@ -3339,4 +3352,246 @@ public class SolrCLI {
}
}
} // end AssertTool class
public static class UtilsTool extends ToolBase {
private Path serverPath;
private Path logsPath;
private boolean beQuiet;
public UtilsTool() { this(System.out); }
public UtilsTool(PrintStream stdout) { super(stdout); }
public String getName() {
return "prestart";
}
@SuppressWarnings("static-access")
public Option[] getOptions() {
return new Option[]{
OptionBuilder
.withArgName("path")
.hasArg()
.withDescription("Path to server dir. Required if logs path is relative")
.create("s"),
OptionBuilder
.withArgName("path")
.hasArg()
.withDescription("Path to logs dir. If relative, also provide server dir with -s")
.create("l"),
OptionBuilder
.withDescription("Be quiet, don't print to stdout, only return exit codes")
.create("q"),
OptionBuilder
.withArgName("daysToKeep")
.hasArg()
.withType(Integer.class)
.withDescription("Path to logs directory")
.create("remove_old_solr_logs"),
OptionBuilder
.withArgName("generations")
.hasArg()
.withType(Integer.class)
.withDescription("Rotate solr.log to solr.log.1 etc")
.create("rotate_solr_logs"),
OptionBuilder
.withDescription("Archive old garbage collection logs into archive/")
.create("archive_gc_logs"),
OptionBuilder
.withDescription("Archive old console logs into archive/")
.create("archive_console_logs")
};
}
@Override
public int runTool(CommandLine cli) throws Exception {
if (cli.getOptions().length == 0 || cli.getArgs().length > 0 || cli.hasOption("h")) {
new HelpFormatter().printHelp("bin/solr utils [OPTIONS]", getToolOptions(this));
return 1;
}
if (cli.hasOption("s")) {
serverPath = Paths.get(cli.getOptionValue("s"));
}
if (cli.hasOption("l")) {
logsPath = Paths.get(cli.getOptionValue("l"));
}
if (cli.hasOption("q")) {
beQuiet = cli.hasOption("q");
}
if (cli.hasOption("remove_old_solr_logs")) {
if (removeOldSolrLogs(Integer.parseInt(cli.getOptionValue("remove_old_solr_logs"))) > 0) return 1;
}
if (cli.hasOption("rotate_solr_logs")) {
if (rotateSolrLogs(Integer.parseInt(cli.getOptionValue("rotate_solr_logs"))) > 0) return 1;
}
if (cli.hasOption("archive_gc_logs")) {
if (archiveGcLogs() > 0) return 1;
}
if (cli.hasOption("archive_console_logs")) {
if (archiveConsoleLogs() > 0) return 1;
}
return 0;
}
/**
* Moves gc logs into archived/
* @return 0 on success
* @throws Exception on failure
*/
public int archiveGcLogs() throws Exception {
prepareLogsPath();
Path archivePath = logsPath.resolve("archived");
if (!archivePath.toFile().exists()) {
Files.createDirectories(archivePath);
}
List<Path> archived = Files.find(archivePath, 1, (f, a)
-> a.isRegularFile() && String.valueOf(f.getFileName()).startsWith("solr_gc_"))
.collect(Collectors.toList());
for (Path p : archived) {
Files.delete(p);
}
List<Path> files = Files.find(logsPath, 1, (f, a)
-> a.isRegularFile() && String.valueOf(f.getFileName()).startsWith("solr_gc_"))
.collect(Collectors.toList());
if (files.size() > 0) {
out("Archiving " + files.size() + " old GC log files to " + archivePath);
for (Path p : files) {
Files.move(p, archivePath.resolve(p.getFileName()), StandardCopyOption.REPLACE_EXISTING);
}
}
return 0;
}
/**
* Moves console log(s) into archiced/
* @return 0 on success
* @throws Exception on failure
*/
public int archiveConsoleLogs() throws Exception {
prepareLogsPath();
Path archivePath = logsPath.resolve("archived");
if (!archivePath.toFile().exists()) {
Files.createDirectories(archivePath);
}
List<Path> archived = Files.find(archivePath, 1, (f, a)
-> a.isRegularFile() && String.valueOf(f.getFileName()).endsWith("-console.log"))
.collect(Collectors.toList());
for (Path p : archived) {
Files.delete(p);
}
List<Path> files = Files.find(logsPath, 1, (f, a)
-> a.isRegularFile() && String.valueOf(f.getFileName()).endsWith("-console.log"))
.collect(Collectors.toList());
if (files.size() > 0) {
out("Archiving " + files.size() + " console log files");
for (Path p : files) {
Files.move(p, archivePath.resolve(p.getFileName()), StandardCopyOption.REPLACE_EXISTING);
}
}
return 0;
}
/**
* Rotates solr.log before starting Solr. Mimics log4j2 behavior, i.e. with generations=9:
* <pre>
* solr.log.9 (and higher) are deleted
* solr.log.8 -&gt; solr.log.9
* solr.log.7 -&gt; solr.log.8
* ...
* solr.log -&gt; solr.log.1
* </pre>
* @param generations number of generations to keep. Should agree with setting in log4j.properties
* @return 0 if success
* @throws Exception if problems
*/
public int rotateSolrLogs(int generations) throws Exception {
prepareLogsPath();
if (logsPath.toFile().exists() && logsPath.resolve("solr.log").toFile().exists()) {
out("Rotating solr logs, keeping a max of "+generations+" generations");
try (Stream<Path> files = Files.find(logsPath, 1,
(f, a) -> a.isRegularFile() && String.valueOf(f.getFileName()).startsWith("solr.log."))
.sorted((b,a) -> new Integer(a.getFileName().toString().substring(9))
.compareTo(new Integer(b.getFileName().toString().substring(9))))) {
files.forEach(p -> {
try {
int number = Integer.parseInt(p.getFileName().toString().substring(9));
if (number >= generations) {
Files.delete(p);
} else {
Path renamed = p.getParent().resolve("solr.log." + (number + 1));
Files.move(p, renamed);
}
} catch (IOException e) {
out("Problem during rotation of log files: " + e.getMessage());
}
});
} catch (NumberFormatException nfe) {
throw new Exception("Do not know how to rotate solr.log.<ext> with non-numeric extension. Rotate aborted.", nfe);
}
Files.move(logsPath.resolve("solr.log"), logsPath.resolve("solr.log.1"));
}
return 0;
}
/**
* Deletes time-stamped old solr logs, if older than n days
* @param daysToKeep number of days logs to keep before deleting
* @return 0 on success
* @throws Exception on failure
*/
public int removeOldSolrLogs(int daysToKeep) throws Exception {
prepareLogsPath();
if (logsPath.toFile().exists()) {
try (Stream<Path> stream = Files.find(logsPath, 2, (f, a) -> a.isRegularFile()
&& Instant.now().minus(Period.ofDays(daysToKeep)).isAfter(a.lastModifiedTime().toInstant())
&& String.valueOf(f.getFileName()).startsWith("solr_log_"))) {
List<Path> files = stream.collect(Collectors.toList());
if (files.size() > 0) {
out("Deleting "+files.size() + " solr_log_* files older than " + daysToKeep + " days.");
for (Path p : files) {
Files.delete(p);
}
}
}
}
return 0;
}
// Private methods to follow
private void out(String message) {
if (!beQuiet) {
stdout.print(message + "\n");
}
}
private void prepareLogsPath() throws Exception {
if (logsPath == null) {
throw new Exception("Command requires the -l <log-directory> option");
}
if (!logsPath.isAbsolute()) {
if (serverPath != null && serverPath.isAbsolute() && serverPath.toFile().exists()) {
logsPath = serverPath.resolve(logsPath);
} else {
throw new Exception("Logs directory must be an absolute path, or -s must be supplied");
}
}
}
@Override
protected void runImpl(CommandLine cli) throws Exception {
}
public void setLogPath(Path logsPath) {
this.logsPath = logsPath;
}
public void setServerPath(Path serverPath) {
this.serverPath = serverPath;
}
public void setQuiet(boolean shouldPrintStdout) {
this.beQuiet = shouldPrintStdout;
}
} // end UtilsTool class
}

View File

@ -0,0 +1,185 @@
/*
* 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.solr.util;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.time.Period;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.cli.CommandLine;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.apache.solr.util.SolrCLI.findTool;
import static org.apache.solr.util.SolrCLI.parseCmdLine;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Unit test for SolrCLI's UtilsTool
*/
public class UtilsToolTest {
private Path dir;
private SolrCLI.UtilsTool tool;
private List<String> files = Arrays.asList(
"solr.log",
"solr.log.1",
"solr.log.2",
"solr.log.3",
"solr.log.9",
"solr.log.10",
"solr.log.11",
"solr_log_20160102",
"solr_log_20160304",
"solr-8983-console.log",
"solr_gc_log_20160102",
"solr_gc_log_2");
@Before
public void setUp() throws IOException {
dir = Files.createTempDirectory("Utils Tool Test");
files.stream().forEach(f -> {
try {
dir.resolve(f).toFile().createNewFile();
} catch (IOException e) {
assertTrue(false);
}
});
}
@After
public void tearDown() throws IOException {
org.apache.commons.io.FileUtils.deleteDirectory(dir.toFile());
}
@Test
public void testEmptyAndQuiet() throws Exception {
String[] args = {"utils", "-remove_old_solr_logs", "7",
"-rotate_solr_logs", "9",
"-archive_gc_logs",
"-archive_console_logs",
"-q",
"-l", dir.toString()};
assertEquals(0, runTool(args));
}
@Test
public void testNonexisting() throws Exception {
String nonexisting = dir.resolve("non-existing").toString();
String[] args = {"utils", "-remove_old_solr_logs", "7",
"-rotate_solr_logs", "9",
"-archive_gc_logs",
"-archive_console_logs",
"-l", nonexisting};
assertEquals(0, runTool(args));
}
@Test
public void testRemoveOldSolrLogs() throws Exception {
String[] args = {"utils", "-remove_old_solr_logs", "1", "-l", dir.toString()};
assertEquals(files.size(), fileCount());
assertEquals(0, runTool(args));
assertEquals(files.size(), fileCount()); // No logs older than 1 day
Files.setLastModifiedTime(dir.resolve("solr_log_20160102"), FileTime.from(Instant.now().minus(Period.ofDays(2))));
assertEquals(0, runTool(args));
assertEquals(files.size()-1, fileCount()); // One logs older than 1 day
Files.setLastModifiedTime(dir.resolve("solr_log_20160304"), FileTime.from(Instant.now().minus(Period.ofDays(3))));
assertEquals(0, runTool(args));
assertEquals(files.size()-2, fileCount()); // Two logs older than 1 day
}
@Test
public void testRelativePath() throws Exception {
String[] args = {"utils", "-remove_old_solr_logs", "0", "-l", dir.getFileName().toString(), "-s", dir.getParent().toString()};
assertEquals(files.size(), fileCount());
assertEquals(0, runTool(args));
assertEquals(files.size()-2, fileCount());
}
@Test
public void testRelativePathError() throws Exception {
String[] args = {"utils", "-remove_old_solr_logs", "0", "-l", dir.getFileName().toString()};
try {
runTool(args);
} catch (Exception e) {
return;
}
assertTrue(false);
}
@Test
public void testRemoveOldGcLogs() throws Exception {
String[] args = {"utils", "-archive_gc_logs", "-l", dir.toString()};
assertEquals(files.size(), fileCount());
assertEquals(0, runTool(args));
assertEquals(files.size()-2, fileCount());
assertFalse(listFiles().contains("solr_gc_log_2"));
assertTrue(Files.exists(dir.resolve("archived").resolve("solr_gc_log_2")));
assertEquals(0, runTool(args));
assertFalse(Files.exists(dir.resolve("archived").resolve("solr_gc_log_2")));
}
@Test
public void testArchiveConsoleLogs() throws Exception {
String[] args = {"utils", "-archive_console_logs", "-l", dir.toString()};
assertEquals(files.size(), fileCount());
assertEquals(0, runTool(args));
assertEquals(files.size()-1, fileCount());
assertFalse(listFiles().contains("solr-8983-console.log"));
assertTrue(Files.exists(dir.resolve("archived").resolve("solr-8983-console.log")));
assertEquals(0, runTool(args));
assertFalse(Files.exists(dir.resolve("archived").resolve("solr-8983-console.log")));
}
@Test
public void testRotateSolrLogs() throws Exception {
String[] args = {"utils", "-rotate_solr_logs", "9", "-l", dir.toString()};
assertEquals(files.size(), fileCount());
assertTrue(listFiles().contains("solr.log"));
assertEquals(0, runTool(args));
assertEquals(files.size()-3, fileCount());
assertTrue(listFiles().contains("solr.log.4"));
assertFalse(listFiles().contains("solr.log"));
assertFalse(listFiles().contains("solr.log.9"));
assertFalse(listFiles().contains("solr.log.10"));
assertFalse(listFiles().contains("solr.log.11"));
}
private List<String> listFiles() throws IOException {
return Files.find(dir, 1, (p, a) -> a.isRegularFile()).map(p -> p.getFileName().toString()).collect(Collectors.toList());
}
private long fileCount() throws IOException {
return listFiles().size();
}
private int runTool(String[] args) throws Exception {
SolrCLI.Tool tool = findTool(args);
CommandLine cli = parseCmdLine(args, tool.getOptions());
return tool.runTool(cli);
}
}