Skip to content

Commit

Permalink
[CORE] Support parsing lucene minor version strings
Browse files Browse the repository at this point in the history
We parse the version that is shipped with the Lucene segments in order
to find the version of lucene that wrote a particular segment. Yet, some lucene
version ie:
 * 4.3.1 (Elasticsearch 0.90.2)
 * 4.5.1 (Elasticsearch 0.90.7)
 * 3.6.1 (pre Elasticsearch 0.90.0)

wrote illegal strings containing the minor version which causes IAE exceptions
being thrown from lucenes parsing method.

Closes elastic#7055
  • Loading branch information
s1monw committed Jul 28, 2014
1 parent f3b46a1 commit 2cd2fe8
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 8 deletions.
3 changes: 3 additions & 0 deletions core-signatures.txt
Expand Up @@ -66,3 +66,6 @@ java.nio.channels.ReadableByteChannel#read(java.nio.ByteBuffer)
java.nio.channels.ScatteringByteChannel#read(java.nio.ByteBuffer[])
java.nio.channels.ScatteringByteChannel#read(java.nio.ByteBuffer[], int, int)
java.nio.channels.FileChannel#read(java.nio.ByteBuffer, long)

@defaultMessage Use Lucene.parseLenient instead it strips off minor version
org.apache.lucene.util.Version#parseLeniently(java.lang.String)
3 changes: 3 additions & 0 deletions pom.xml
Expand Up @@ -1181,6 +1181,9 @@
<!-- start exclude for Channels utility class -->
<exclude>org/elasticsearch/common/io/Channels.class</exclude>
<!-- end exclude for Channels -->
<!-- start exclude for Lucene utility class -->
<exclude>org/elasticsearch/common/lucene/Lucene$LenientParser.class</exclude>
<!-- end exclude for Lucene -->
</excludes>
<bundledSignatures>
<!-- This will automatically choose the right signatures based on 'targetVersion': -->
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/org/elasticsearch/common/lucene/Lucene.java
Expand Up @@ -32,6 +32,7 @@
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.logging.ESLogger;
Expand All @@ -40,6 +41,9 @@
import org.elasticsearch.index.fielddata.IndexFieldData;

import java.io.IOException;
import java.util.Locale;

import static org.elasticsearch.common.lucene.search.NoopCollector.NOOP_COLLECTOR;

/**
*
Expand Down Expand Up @@ -402,4 +406,27 @@ public static final boolean indexExists(final Directory directory) throws IOExce
public static boolean isCorruptionException(Throwable t) {
return ExceptionsHelper.unwrap(t, CorruptIndexException.class) != null;
}

/**
* Parses the version string lenient and returns the the default value if the given string is null or emtpy
*/
public static Version parseVersionLenient(String toParse, Version defaultValue) {
return LenientParser.parse(toParse, defaultValue);
}

private static final class LenientParser {
public static Version parse(String toParse, Version defaultValue) {
if (Strings.hasLength(toParse)) {
try {
return Version.parseLeniently(toParse);
} catch (IllegalArgumentException e) {
final String parsedMatchVersion = toParse
.toUpperCase(Locale.ROOT)
.replaceFirst("^(\\d+)\\.(\\d+).(\\d+)$", "LUCENE_$1_$2");
return Version.valueOf(parsedMatchVersion);
}
}
return defaultValue;
}
}
}
Expand Up @@ -24,6 +24,7 @@
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
Expand Down Expand Up @@ -255,7 +256,7 @@ public static FileInfo fromXContent(XContentParser parser) throws IOException {
} else if ("part_size".equals(currentFieldName)) {
partSize = new ByteSizeValue(parser.longValue());
} else if ("written_by".equals(currentFieldName)) {
writtenBy = Version.parseLeniently(parser.text());
writtenBy = Lucene.parseVersionLenient(parser.text(), null);
} else {
throw new ElasticsearchParseException("unknown parameter [" + currentFieldName + "]");
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/elasticsearch/index/store/Store.java
Expand Up @@ -448,7 +448,7 @@ ImmutableMap<String, StoreFileMetaData> buildMetadata(Directory directory, ESLog
Version maxVersion = Version.LUCENE_3_0; // we don't know which version was used to write so we take the max version.
Set<String> added = new HashSet<>();
for (SegmentCommitInfo info : segmentCommitInfos) {
final Version version = Version.parseLeniently(info.info.getVersion());
final Version version = Lucene.parseVersionLenient(info.info.getVersion(), Version.LUCENE_3_0);
if (version.onOrAfter(maxVersion)) {
maxVersion = version;
}
Expand Down
Expand Up @@ -19,12 +19,12 @@

package org.elasticsearch.index.store;

import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Streamable;
import org.elasticsearch.common.lucene.Lucene;

import java.io.IOException;

Expand Down Expand Up @@ -102,7 +102,7 @@ public void readFrom(StreamInput in) throws IOException {
checksum = in.readOptionalString();
if (in.getVersion().onOrAfter(org.elasticsearch.Version.V_1_3_0)) {
String versionString = in.readOptionalString();
writtenBy = versionString == null ? null : Version.parseLeniently(versionString);
writtenBy = Lucene.parseVersionLenient(versionString, null);
}
}

Expand Down
Expand Up @@ -21,10 +21,10 @@

import org.apache.lucene.util.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.index.store.StoreFileMetaData;
import org.elasticsearch.transport.TransportRequest;
Expand Down Expand Up @@ -101,7 +101,7 @@ public void readFrom(StreamInput in) throws IOException {
Version writtenBy = null;
if (in.getVersion().onOrAfter(org.elasticsearch.Version.V_1_3_0)) {
String versionString = in.readOptionalString();
writtenBy = versionString == null ? null : Version.parseLeniently(versionString);
writtenBy = Lucene.parseVersionLenient(versionString, null);
}
metaData = new StoreFileMetaData(name, length, checksum, writtenBy);
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/elasticsearch/plugins/PluginsService.java
Expand Up @@ -33,6 +33,7 @@
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
Expand Down Expand Up @@ -571,7 +572,7 @@ public static boolean checkLuceneCompatibility(Class<? extends Plugin> pluginCla
String parts[] = luceneVersion.split("\\.");

// Should fail if the running node is too old!
org.apache.lucene.util.Version luceneExpectedVersion = org.apache.lucene.util.Version.parseLeniently(parts[0]+"."+parts[1]);
org.apache.lucene.util.Version luceneExpectedVersion = Lucene.parseVersionLenient(parts[0] + "." + parts[1], null);

if (Version.CURRENT.luceneVersion.equals(luceneExpectedVersion)) {
logger.debug("starting analysis plugin for Lucene [{}].", luceneExpectedVersion);
Expand Down
22 changes: 21 additions & 1 deletion src/test/java/org/elasticsearch/VersionTests.java
Expand Up @@ -20,10 +20,14 @@
package org.elasticsearch;

import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.hamcrest.Matchers;
import org.junit.Test;

import java.util.Locale;

import static org.elasticsearch.Version.V_0_20_0;
import static org.elasticsearch.Version.V_0_90_0;
import static org.hamcrest.CoreMatchers.equalTo;
Expand Down Expand Up @@ -104,4 +108,20 @@ public void testVersion() {
final Version version = randomFrom(Version.V_0_18_0, Version.V_0_90_13, Version.V_1_3_0);
assertEquals(version, Version.indexCreated(ImmutableSettings.builder().put(IndexMetaData.SETTING_UUID, "foo").put(IndexMetaData.SETTING_VERSION_CREATED, version).build()));
}
}

@Test
public void parseLenient() {
int numIters = randomIntBetween(10, 100);
for (int i = 0; i < numIters; i++) {
Version version = randomVersion(getRandom());
org.apache.lucene.util.Version luceneVersion = version.luceneVersion;
String string = luceneVersion.name().toUpperCase(Locale.ROOT)
.replaceFirst("^LUCENE_(\\d+)_(\\d+)$", "$1.$2");
if (randomBoolean()) {
string = string + "." + randomIntBetween(0, 100);
}
assertThat(luceneVersion, Matchers.equalTo(Lucene.parseVersionLenient(string, null)));
}
}

}

0 comments on commit 2cd2fe8

Please sign in to comment.