LUCENE-2523: Add IndexFormatTooOldException and IndexFormatTooNewException

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@965868 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Uwe Schindler 2010-07-20 14:55:47 +00:00
parent cc5882ab75
commit 72d4191588
38 changed files with 254 additions and 62 deletions

View File

@ -42,7 +42,8 @@ public class AppendingTermsDictReader extends StandardTermsDictReader {
@Override @Override
protected void readHeader(IndexInput in) throws IOException { protected void readHeader(IndexInput in) throws IOException {
CodecUtil.checkHeader(in, AppendingTermsDictWriter.CODEC_NAME, StandardTermsDictWriter.VERSION_CURRENT); CodecUtil.checkHeader(in, AppendingTermsDictWriter.CODEC_NAME,
StandardTermsDictWriter.VERSION_START, StandardTermsDictWriter.VERSION_CURRENT);
} }
@Override @Override

View File

@ -37,7 +37,8 @@ public class AppendingTermsIndexReader extends SimpleStandardTermsIndexReader {
@Override @Override
protected void readHeader(IndexInput input) throws IOException { protected void readHeader(IndexInput input) throws IOException {
CodecUtil.checkHeader(input, AppendingTermsIndexWriter.CODEC_NAME, AppendingTermsIndexWriter.VERSION_START); CodecUtil.checkHeader(input, AppendingTermsIndexWriter.CODEC_NAME,
AppendingTermsIndexWriter.VERSION_START, AppendingTermsIndexWriter.VERSION_START);
} }
@Override @Override

View File

@ -24,6 +24,7 @@ import org.apache.lucene.store.IndexInput;
import org.apache.lucene.document.AbstractField; // for javadocs import org.apache.lucene.document.AbstractField; // for javadocs
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.index.codecs.CodecProvider; import org.apache.lucene.index.codecs.CodecProvider;
import org.apache.lucene.index.codecs.DefaultSegmentInfosWriter;
import org.apache.lucene.util.Bits; import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
@ -343,12 +344,15 @@ public class CheckIndex {
String sFormat = ""; String sFormat = "";
boolean skip = false; boolean skip = false;
if (format == SegmentInfos.FORMAT_DIAGNOSTICS) if (format == DefaultSegmentInfosWriter.FORMAT_DIAGNOSTICS) {
sFormat = "FORMAT_DIAGNOSTICS [Lucene 2.9]"; sFormat = "FORMAT_DIAGNOSTICS [Lucene 2.9]";
else if (format == SegmentInfos.FORMAT_4_0) } else if (format == DefaultSegmentInfosWriter.FORMAT_4_0) {
sFormat = "FORMAT_FLEX_POSTINGS [Lucene 4.0]"; sFormat = "FORMAT_4_0 [Lucene 4.0]";
else if (format < SegmentInfos.CURRENT_FORMAT) { } else if (format < DefaultSegmentInfosWriter.FORMAT_CURRENT) {
sFormat = "int=" + format + " [newer version of Lucene than this tool]"; sFormat = "int=" + format + " [newer version of Lucene than this tool supports]";
skip = true;
} else if (format > DefaultSegmentInfosWriter.FORMAT_MINIMUM) {
sFormat = "int=" + format + " [older version of Lucene than this tool supports]";
skip = true; skip = true;
} }

View File

@ -39,7 +39,10 @@ public final class FieldInfos {
// First used in 2.9; prior to 2.9 there was no format header // First used in 2.9; prior to 2.9 there was no format header
public static final int FORMAT_START = -2; public static final int FORMAT_START = -2;
static final int CURRENT_FORMAT = FORMAT_START; // whenever you add a new format, make it 1 smaller (negative version logic)!
static final int FORMAT_CURRENT = FORMAT_START;
static final int FORMAT_MINIMUM = FORMAT_START;
static final byte IS_INDEXED = 0x1; static final byte IS_INDEXED = 0x1;
static final byte STORE_TERMVECTOR = 0x2; static final byte STORE_TERMVECTOR = 0x2;
@ -286,7 +289,7 @@ public final class FieldInfos {
} }
public void write(IndexOutput output) throws IOException { public void write(IndexOutput output) throws IOException {
output.writeVInt(CURRENT_FORMAT); output.writeVInt(FORMAT_CURRENT);
output.writeVInt(size()); output.writeVInt(size());
for (int i = 0; i < size(); i++) { for (int i = 0; i < size(); i++) {
FieldInfo fi = fieldInfo(i); FieldInfo fi = fieldInfo(i);
@ -307,8 +310,11 @@ public final class FieldInfos {
private void read(IndexInput input, String fileName) throws IOException { private void read(IndexInput input, String fileName) throws IOException {
format = input.readVInt(); format = input.readVInt();
if (format > FORMAT_START) { if (format > FORMAT_MINIMUM) {
throw new CorruptIndexException("unrecognized format " + format + " in file \"" + fileName + "\""); throw new IndexFormatTooOldException(fileName, format, FORMAT_MINIMUM, FORMAT_CURRENT);
}
if (format < FORMAT_CURRENT) {
throw new IndexFormatTooNewException(fileName, format, FORMAT_MINIMUM, FORMAT_CURRENT);
} }
final int size = input.readVInt(); //read in the size final int size = input.readVInt(); //read in the size

View File

@ -100,13 +100,15 @@ final class FieldsReader implements Cloneable {
fieldInfos = fn; fieldInfos = fn;
cloneableFieldsStream = d.openInput(IndexFileNames.segmentFileName(segment, "", IndexFileNames.FIELDS_EXTENSION), readBufferSize); cloneableFieldsStream = d.openInput(IndexFileNames.segmentFileName(segment, "", IndexFileNames.FIELDS_EXTENSION), readBufferSize);
cloneableIndexStream = d.openInput(IndexFileNames.segmentFileName(segment, "", IndexFileNames.FIELDS_INDEX_EXTENSION), readBufferSize); final String indexStreamFN = IndexFileNames.segmentFileName(segment, "", IndexFileNames.FIELDS_INDEX_EXTENSION);
cloneableIndexStream = d.openInput(indexStreamFN, readBufferSize);
format = cloneableIndexStream.readInt(); format = cloneableIndexStream.readInt();
if (format < FieldsWriter.FORMAT_MINIMUM)
throw new IndexFormatTooOldException(indexStreamFN, format, FieldsWriter.FORMAT_MINIMUM, FieldsWriter.FORMAT_CURRENT);
if (format > FieldsWriter.FORMAT_CURRENT) if (format > FieldsWriter.FORMAT_CURRENT)
throw new CorruptIndexException("Incompatible format version: " + format + " expected " throw new IndexFormatTooNewException(indexStreamFN, format, FieldsWriter.FORMAT_MINIMUM, FieldsWriter.FORMAT_CURRENT);
+ FieldsWriter.FORMAT_CURRENT + " or lower");
fieldsStream = (IndexInput) cloneableFieldsStream.clone(); fieldsStream = (IndexInput) cloneableFieldsStream.clone();
@ -185,11 +187,9 @@ final class FieldsReader implements Cloneable {
} }
boolean canReadRawDocs() { boolean canReadRawDocs() {
// Disable reading raw docs in 2.x format, because of the removal of compressed // Since we currently only support >3.0 format anymore, always return true!
// fields in 3.0. We don't want rawDocs() to decode field bits to figure out // I leave this method in because it may help for later format changes.
// if a field was compressed, hence we enforce ordinary (non-raw) stored field merges return true;
// for <3.0 indexes.
return format >= FieldsWriter.FORMAT_LUCENE_3_0_NO_COMPRESSED_FIELDS;
} }
final Document doc(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException { final Document doc(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException {
@ -306,7 +306,6 @@ final class FieldsReader implements Cloneable {
private void addField(Document doc, FieldInfo fi, boolean binary, boolean tokenize) throws CorruptIndexException, IOException { private void addField(Document doc, FieldInfo fi, boolean binary, boolean tokenize) throws CorruptIndexException, IOException {
//we have a binary stored field, and it may be compressed
if (binary) { if (binary) {
int toRead = fieldsStream.readVInt(); int toRead = fieldsStream.readVInt();
final byte[] b = new byte[toRead]; final byte[] b = new byte[toRead];

View File

@ -39,6 +39,9 @@ final class FieldsWriter
// switch to a new format! // switch to a new format!
static final int FORMAT_CURRENT = FORMAT_LUCENE_3_0_NO_COMPRESSED_FIELDS; static final int FORMAT_CURRENT = FORMAT_LUCENE_3_0_NO_COMPRESSED_FIELDS;
// when removing support for old versions, leave the last supported version here
static final int FORMAT_MINIMUM = FORMAT_LUCENE_3_0_NO_COMPRESSED_FIELDS;
private FieldInfos fieldInfos; private FieldInfos fieldInfos;
private IndexOutput fieldsStream; private IndexOutput fieldsStream;

View File

@ -0,0 +1,31 @@
/**
* 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.index;
/**
* This exception is thrown when Lucene detects
* an index that is newer than this Lucene version.
*/
public class IndexFormatTooNewException extends CorruptIndexException {
public IndexFormatTooNewException(String filename, int version, int minVersion, int maxVersion) {
super("Format version is not supported" + (filename!=null ? (" in file '" + filename + "'") : "") +
": " + version + " (needs to be between " + minVersion + " and " + maxVersion + ")");
}
}

View File

@ -0,0 +1,32 @@
/**
* 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.index;
/**
* This exception is thrown when Lucene detects
* an index that is too old for this Lucene version
*/
public class IndexFormatTooOldException extends CorruptIndexException {
public IndexFormatTooOldException(String filename, int version, int minVersion, int maxVersion) {
super("Format version is not supported" + (filename!=null ? (" in file '" + filename + "'") : "") +
": " + version + " (needs to be between " + minVersion + " and " + maxVersion +
"). This version of Lucene only supports indexes created with release 3.0 and later.");
}
}

View File

@ -22,6 +22,7 @@ import org.apache.lucene.store.IndexOutput;
import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexInput;
import org.apache.lucene.index.codecs.Codec; import org.apache.lucene.index.codecs.Codec;
import org.apache.lucene.index.codecs.CodecProvider; import org.apache.lucene.index.codecs.CodecProvider;
import org.apache.lucene.index.codecs.DefaultSegmentInfosWriter;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -154,7 +155,7 @@ public final class SegmentInfo {
docStoreSegment = name; docStoreSegment = name;
docStoreIsCompoundFile = false; docStoreIsCompoundFile = false;
} }
if (format > SegmentInfos.FORMAT_4_0) { if (format > DefaultSegmentInfosWriter.FORMAT_4_0) {
// pre-4.0 indexes write a byte if there is a single norms file // pre-4.0 indexes write a byte if there is a single norms file
byte b = input.readByte(); byte b = input.readByte();
assert 1 == b; assert 1 == b;
@ -177,7 +178,7 @@ public final class SegmentInfo {
// System.out.println(Thread.currentThread().getName() + ": si.read hasProx=" + hasProx + " seg=" + name); // System.out.println(Thread.currentThread().getName() + ": si.read hasProx=" + hasProx + " seg=" + name);
if (format <= SegmentInfos.FORMAT_4_0) if (format <= DefaultSegmentInfosWriter.FORMAT_4_0)
codecName = input.readString(); codecName = input.readString();
else else
codecName = "PreFlex"; codecName = "PreFlex";

View File

@ -53,20 +53,10 @@ public final class SegmentInfos extends Vector<SegmentInfo> {
* be removed, however the numbers should continue to decrease. * be removed, however the numbers should continue to decrease.
*/ */
/** Used for the segments.gen file only! */ /** Used for the segments.gen file only!
* Whenever you add a new format, make it 1 smaller (negative version logic)! */
public static final int FORMAT_SEGMENTS_GEN_CURRENT = -2; public static final int FORMAT_SEGMENTS_GEN_CURRENT = -2;
/** This format adds optional per-segment String
* diagnostics storage, and switches userData to Map */
public static final int FORMAT_DIAGNOSTICS = -9;
/** Each segment records whether its postings are written
* in the new flex format */
public static final int FORMAT_4_0 = -10;
/* This must always point to the most recent file format. */
public static final int CURRENT_FORMAT = FORMAT_4_0;
public int counter = 0; // used to name new segments public int counter = 0; // used to name new segments
/** /**
@ -556,9 +546,16 @@ public final class SegmentInfos extends Vector<SegmentInfo> {
genB = gen0; genB = gen0;
break; break;
} }
} else {
/* TODO: Investigate this!
throw new IndexFormatTooNewException("segments.gen version number invalid: " + version +
" (must be " + FORMAT_SEGMENTS_GEN_CURRENT + ")");
*/
} }
} catch (IOException err2) { } catch (IOException err2) {
// will retry // rethrow any format exception
if (err2 instanceof CorruptIndexException) throw err2;
// else will retry
} finally { } finally {
genInput.close(); genInput.close();
} }

View File

@ -35,7 +35,11 @@ class TermVectorsReader implements Cloneable {
static final int FORMAT_UTF8_LENGTH_IN_BYTES = 4; static final int FORMAT_UTF8_LENGTH_IN_BYTES = 4;
// NOTE: always change this if you switch to a new format! // NOTE: always change this if you switch to a new format!
// whenever you add a new format, make it 1 larger (positive version logic)!
static final int FORMAT_CURRENT = FORMAT_UTF8_LENGTH_IN_BYTES; static final int FORMAT_CURRENT = FORMAT_UTF8_LENGTH_IN_BYTES;
// when removing support for old versions, leave the last supported version here
static final int FORMAT_MINIMUM = FORMAT_UTF8_LENGTH_IN_BYTES;
//The size in bytes that the FORMAT_VERSION will take up at the beginning of each file //The size in bytes that the FORMAT_VERSION will take up at the beginning of each file
static final int FORMAT_SIZE = 4; static final int FORMAT_SIZE = 4;
@ -75,11 +79,13 @@ class TermVectorsReader implements Cloneable {
String idxName = IndexFileNames.segmentFileName(segment, "", IndexFileNames.VECTORS_INDEX_EXTENSION); String idxName = IndexFileNames.segmentFileName(segment, "", IndexFileNames.VECTORS_INDEX_EXTENSION);
if (d.fileExists(idxName)) { if (d.fileExists(idxName)) {
tvx = d.openInput(idxName, readBufferSize); tvx = d.openInput(idxName, readBufferSize);
format = checkValidFormat(tvx); format = checkValidFormat(tvx, idxName);
tvd = d.openInput(IndexFileNames.segmentFileName(segment, "", IndexFileNames.VECTORS_DOCUMENTS_EXTENSION), readBufferSize); String fn = IndexFileNames.segmentFileName(segment, "", IndexFileNames.VECTORS_DOCUMENTS_EXTENSION);
final int tvdFormat = checkValidFormat(tvd); tvd = d.openInput(fn, readBufferSize);
tvf = d.openInput(IndexFileNames.segmentFileName(segment, "", IndexFileNames.VECTORS_FIELDS_EXTENSION), readBufferSize); final int tvdFormat = checkValidFormat(tvd, fn);
final int tvfFormat = checkValidFormat(tvf); fn = IndexFileNames.segmentFileName(segment, "", IndexFileNames.VECTORS_FIELDS_EXTENSION);
tvf = d.openInput(fn, readBufferSize);
final int tvfFormat = checkValidFormat(tvf, fn);
assert format == tvdFormat; assert format == tvdFormat;
assert format == tvfFormat; assert format == tvfFormat;
@ -183,13 +189,13 @@ class TermVectorsReader implements Cloneable {
} }
} }
private int checkValidFormat(IndexInput in) throws CorruptIndexException, IOException private int checkValidFormat(IndexInput in, String fn) throws CorruptIndexException, IOException
{ {
int format = in.readInt(); int format = in.readInt();
if (format > FORMAT_CURRENT) { if (format < FORMAT_MINIMUM)
throw new CorruptIndexException("Incompatible format version: " + format + " expected " throw new IndexFormatTooOldException(fn, format, FORMAT_MINIMUM, FORMAT_CURRENT);
+ FORMAT_CURRENT + " or less"); if (format > FORMAT_CURRENT)
} throw new IndexFormatTooNewException(fn, format, FORMAT_MINIMUM, FORMAT_CURRENT);
return format; return format;
} }

View File

@ -20,6 +20,8 @@ package org.apache.lucene.index.codecs;
import java.io.IOException; import java.io.IOException;
import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexFormatTooOldException;
import org.apache.lucene.index.IndexFormatTooNewException;
import org.apache.lucene.index.SegmentInfo; import org.apache.lucene.index.SegmentInfo;
import org.apache.lucene.index.SegmentInfos; import org.apache.lucene.index.SegmentInfos;
import org.apache.lucene.store.ChecksumIndexInput; import org.apache.lucene.store.ChecksumIndexInput;
@ -41,8 +43,12 @@ public class DefaultSegmentInfosReader extends SegmentInfosReader {
int format = input.readInt(); int format = input.readInt();
// check that it is a format we can understand // check that it is a format we can understand
if (format < SegmentInfos.CURRENT_FORMAT) if (format > DefaultSegmentInfosWriter.FORMAT_MINIMUM)
throw new CorruptIndexException("Unknown (newer than us?) format version: " + format); throw new IndexFormatTooOldException(segmentsFileName, format,
DefaultSegmentInfosWriter.FORMAT_MINIMUM, DefaultSegmentInfosWriter.FORMAT_CURRENT);
if (format < DefaultSegmentInfosWriter.FORMAT_CURRENT)
throw new IndexFormatTooNewException(segmentsFileName, format,
DefaultSegmentInfosWriter.FORMAT_MINIMUM, DefaultSegmentInfosWriter.FORMAT_CURRENT);
infos.version = input.readLong(); // read version infos.version = input.readLong(); // read version
infos.counter = input.readInt(); // read counter infos.counter = input.readInt(); // read counter

View File

@ -31,11 +31,26 @@ import org.apache.lucene.store.IndexOutput;
*/ */
public class DefaultSegmentInfosWriter extends SegmentInfosWriter { public class DefaultSegmentInfosWriter extends SegmentInfosWriter {
/** This format adds optional per-segment String
* diagnostics storage, and switches userData to Map */
public static final int FORMAT_DIAGNOSTICS = -9;
/** Each segment records whether its postings are written
* in the new flex format */
public static final int FORMAT_4_0 = -10;
/** This must always point to the most recent file format.
* whenever you add a new format, make it 1 smaller (negative version logic)! */
public static final int FORMAT_CURRENT = FORMAT_4_0;
/** This must always point to the first supported file format. */
public static final int FORMAT_MINIMUM = FORMAT_DIAGNOSTICS;
@Override @Override
public IndexOutput writeInfos(Directory dir, String segmentFileName, SegmentInfos infos) public IndexOutput writeInfos(Directory dir, String segmentFileName, SegmentInfos infos)
throws IOException { throws IOException {
IndexOutput out = createOutput(dir, segmentFileName); IndexOutput out = createOutput(dir, segmentFileName);
out.writeInt(SegmentInfos.CURRENT_FORMAT); // write FORMAT out.writeInt(FORMAT_CURRENT); // write FORMAT
out.writeLong(++infos.version); // every write changes out.writeLong(++infos.version); // every write changes
// the index // the index
out.writeInt(infos.counter); // write counter out.writeInt(infos.counter); // write counter

View File

@ -37,7 +37,8 @@ public class SimpleIntBlockIndexInput extends FixedIntBlockIndexInput {
public SimpleIntBlockIndexInput(Directory dir, String fileName, int readBufferSize) throws IOException { public SimpleIntBlockIndexInput(Directory dir, String fileName, int readBufferSize) throws IOException {
IndexInput in = dir.openInput(fileName, readBufferSize); IndexInput in = dir.openInput(fileName, readBufferSize);
CodecUtil.checkHeader(in, SimpleIntBlockIndexOutput.CODEC, SimpleIntBlockIndexOutput.VERSION_START); CodecUtil.checkHeader(in, SimpleIntBlockIndexOutput.CODEC,
SimpleIntBlockIndexOutput.VERSION_START, SimpleIntBlockIndexOutput.VERSION_START);
init(in); init(in);
} }

View File

@ -22,6 +22,8 @@ import org.apache.lucene.store.IndexInput;
import org.apache.lucene.index.FieldInfos; import org.apache.lucene.index.FieldInfos;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexFormatTooOldException;
import org.apache.lucene.index.IndexFormatTooNewException;
/** /**
* @deprecated No longer used with flex indexing, except for * @deprecated No longer used with flex indexing, except for
@ -40,7 +42,11 @@ public final class SegmentTermEnum implements Cloneable {
public static final int FORMAT_VERSION_UTF8_LENGTH_IN_BYTES = -4; public static final int FORMAT_VERSION_UTF8_LENGTH_IN_BYTES = -4;
// NOTE: always change this if you switch to a new format! // NOTE: always change this if you switch to a new format!
// whenever you add a new format, make it 1 smaller (negative version logic)!
public static final int FORMAT_CURRENT = FORMAT_VERSION_UTF8_LENGTH_IN_BYTES; public static final int FORMAT_CURRENT = FORMAT_VERSION_UTF8_LENGTH_IN_BYTES;
// when removing support for old versions, levae the last supported version here
public static final int FORMAT_MINIMUM = FORMAT_VERSION_UTF8_LENGTH_IN_BYTES;
private TermBuffer termBuffer = new TermBuffer(); private TermBuffer termBuffer = new TermBuffer();
private TermBuffer prevBuffer = new TermBuffer(); private TermBuffer prevBuffer = new TermBuffer();
@ -78,8 +84,10 @@ public final class SegmentTermEnum implements Cloneable {
format = firstInt; format = firstInt;
// check that it is a format we can understand // check that it is a format we can understand
if (format < FORMAT_CURRENT) if (format > FORMAT_MINIMUM)
throw new CorruptIndexException("Unknown format version:" + format + " expected " + FORMAT_CURRENT + " or higher"); throw new IndexFormatTooOldException(null, format, FORMAT_MINIMUM, FORMAT_CURRENT);
if (format < FORMAT_CURRENT)
throw new IndexFormatTooNewException(null, format, FORMAT_MINIMUM, FORMAT_CURRENT);
size = input.readLong(); // read the size size = input.readLong(); // read the size

View File

@ -51,7 +51,8 @@ public class PulsingPostingsReaderImpl extends StandardPostingsReader {
@Override @Override
public void init(IndexInput termsIn) throws IOException { public void init(IndexInput termsIn) throws IOException {
CodecUtil.checkHeader(termsIn, PulsingPostingsWriterImpl.CODEC, PulsingPostingsWriterImpl.VERSION_START); CodecUtil.checkHeader(termsIn, PulsingPostingsWriterImpl.CODEC,
PulsingPostingsWriterImpl.VERSION_START, PulsingPostingsWriterImpl.VERSION_START);
maxPulsingDocFreq = termsIn.readVInt(); maxPulsingDocFreq = termsIn.readVInt();
wrappedPostingsReader.init(termsIn); wrappedPostingsReader.init(termsIn);
} }

View File

@ -95,7 +95,8 @@ public class SepPostingsReaderImpl extends StandardPostingsReader {
@Override @Override
public void init(IndexInput termsIn) throws IOException { public void init(IndexInput termsIn) throws IOException {
// Make sure we are talking to the matching past writer // Make sure we are talking to the matching past writer
CodecUtil.checkHeader(termsIn, SepPostingsWriterImpl.CODEC, SepPostingsWriterImpl.VERSION_START); CodecUtil.checkHeader(termsIn, SepPostingsWriterImpl.CODEC,
SepPostingsWriterImpl.VERSION_START, SepPostingsWriterImpl.VERSION_START);
skipInterval = termsIn.readInt(); skipInterval = termsIn.readInt();
maxSkipLevels = termsIn.readInt(); maxSkipLevels = termsIn.readInt();
} }

View File

@ -36,7 +36,8 @@ public class SingleIntIndexInput extends IntIndexInput {
public SingleIntIndexInput(Directory dir, String fileName, int readBufferSize) public SingleIntIndexInput(Directory dir, String fileName, int readBufferSize)
throws IOException { throws IOException {
in = dir.openInput(fileName, readBufferSize); in = dir.openInput(fileName, readBufferSize);
CodecUtil.checkHeader(in, SingleIntIndexOutput.CODEC, SingleIntIndexOutput.VERSION_START); CodecUtil.checkHeader(in, SingleIntIndexOutput.CODEC,
SingleIntIndexOutput.VERSION_START, SingleIntIndexOutput.VERSION_START);
} }
@Override @Override

View File

@ -146,7 +146,8 @@ public class SimpleStandardTermsIndexReader extends StandardTermsIndexReader {
} }
protected void readHeader(IndexInput input) throws IOException { protected void readHeader(IndexInput input) throws IOException {
CodecUtil.checkHeader(input, SimpleStandardTermsIndexWriter.CODEC_NAME, SimpleStandardTermsIndexWriter.VERSION_START); CodecUtil.checkHeader(input, SimpleStandardTermsIndexWriter.CODEC_NAME,
SimpleStandardTermsIndexWriter.VERSION_START, SimpleStandardTermsIndexWriter.VERSION_START);
dirOffset = input.readLong(); dirOffset = input.readLong();
} }

View File

@ -73,7 +73,8 @@ public class StandardPostingsReaderImpl extends StandardPostingsReader {
public void init(IndexInput termsIn) throws IOException { public void init(IndexInput termsIn) throws IOException {
// Make sure we are talking to the matching past writer // Make sure we are talking to the matching past writer
CodecUtil.checkHeader(termsIn, StandardPostingsWriterImpl.CODEC, StandardPostingsWriterImpl.VERSION_START); CodecUtil.checkHeader(termsIn, StandardPostingsWriterImpl.CODEC,
StandardPostingsWriterImpl.VERSION_START, StandardPostingsWriterImpl.VERSION_START);
skipInterval = termsIn.readInt(); skipInterval = termsIn.readInt();
maxSkipLevels = termsIn.readInt(); maxSkipLevels = termsIn.readInt();

View File

@ -153,7 +153,8 @@ public class StandardTermsDictReader extends FieldsProducer {
} }
protected void readHeader(IndexInput input) throws IOException { protected void readHeader(IndexInput input) throws IOException {
CodecUtil.checkHeader(in, StandardTermsDictWriter.CODEC_NAME, StandardTermsDictWriter.VERSION_CURRENT); CodecUtil.checkHeader(in, StandardTermsDictWriter.CODEC_NAME,
StandardTermsDictWriter.VERSION_START, StandardTermsDictWriter.VERSION_CURRENT);
dirOffset = in.readLong(); dirOffset = in.readLong();
} }

View File

@ -21,6 +21,8 @@ package org.apache.lucene.util;
import org.apache.lucene.store.IndexOutput; import org.apache.lucene.store.IndexOutput;
import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexInput;
import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexFormatTooNewException;
import org.apache.lucene.index.IndexFormatTooOldException;
import java.io.IOException; import java.io.IOException;
@ -48,7 +50,7 @@ public final class CodecUtil {
return 9+codec.length(); return 9+codec.length();
} }
public static int checkHeader(IndexInput in, String codec, int maxVersion) public static int checkHeader(IndexInput in, String codec, int minVersion, int maxVersion)
throws IOException { throws IOException {
// Safety to guard against reading a bogus string: // Safety to guard against reading a bogus string:
@ -63,8 +65,11 @@ public final class CodecUtil {
} }
final int actualVersion = in.readInt(); final int actualVersion = in.readInt();
if (actualVersion < minVersion) {
throw new IndexFormatTooOldException(null, actualVersion, minVersion, maxVersion);
}
if (actualVersion > maxVersion) { if (actualVersion > maxVersion) {
throw new CorruptIndexException("version " + actualVersion + " is too new (expected <= version " + maxVersion + ")"); throw new IndexFormatTooNewException(null, actualVersion, minVersion, maxVersion);
} }
return actualVersion; return actualVersion;

View File

@ -157,7 +157,7 @@ public class PackedInts {
* @lucene.internal * @lucene.internal
*/ */
public static Reader getReader(IndexInput in) throws IOException { public static Reader getReader(IndexInput in) throws IOException {
CodecUtil.checkHeader(in, CODEC_NAME, VERSION_START); CodecUtil.checkHeader(in, CODEC_NAME, VERSION_START, VERSION_START);
final int bitsPerValue = in.readVInt(); final int bitsPerValue = in.readVInt();
assert bitsPerValue > 0 && bitsPerValue <= 64: "bitsPerValue=" + bitsPerValue; assert bitsPerValue > 0 && bitsPerValue <= 64: "bitsPerValue=" + bitsPerValue;
final int valueCount = in.readVInt(); final int valueCount = in.readVInt();
@ -188,7 +188,7 @@ public class PackedInts {
* @lucene.internal * @lucene.internal
*/ */
public static ReaderIterator getReaderIterator(IndexInput in) throws IOException { public static ReaderIterator getReaderIterator(IndexInput in) throws IOException {
CodecUtil.checkHeader(in, CODEC_NAME, VERSION_START); CodecUtil.checkHeader(in, CODEC_NAME, VERSION_START, VERSION_START);
final int bitsPerValue = in.readVInt(); final int bitsPerValue = in.readVInt();
assert bitsPerValue > 0 && bitsPerValue <= 64: "bitsPerValue=" + bitsPerValue; assert bitsPerValue > 0 && bitsPerValue <= 64: "bitsPerValue=" + bitsPerValue;
final int valueCount = in.readVInt(); final int valueCount = in.readVInt();

View File

@ -23,6 +23,8 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.Arrays; import java.util.Arrays;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
@ -127,6 +129,74 @@ public class TestBackwardsCompatibility extends LuceneTestCase {
"31.nocfs", "31.nocfs",
}; };
final String[] unsupportedNames = {"19.cfs",
"19.nocfs",
"20.cfs",
"20.nocfs",
"21.cfs",
"21.nocfs",
"22.cfs",
"22.nocfs",
"23.cfs",
"23.nocfs",
"24.cfs",
"24.nocfs",
"29.cfs",
"29.nocfs",
};
/** This test checks that *only* IndexFormatTooOldExceptions are throws when you open and operate on too old indexes! */
public void testUnsupportedOldIndexes() throws Exception {
for(int i=0;i<unsupportedNames.length;i++) {
unzip(getDataFile("unsupported." + unsupportedNames[i] + ".zip"), unsupportedNames[i]);
String fullPath = fullDir(unsupportedNames[i]);
Directory dir = FSDirectory.open(new File(fullPath));
IndexReader reader = null;
IndexWriter writer = null;
try {
reader = IndexReader.open(dir);
MultiFields.getFields(reader).terms("content");
reader.document(0); // to catch also 2.9->3.0 stored field change
fail("IndexReader.open should not pass for "+unsupportedNames[i]);
} catch (IndexFormatTooOldException e) {
// pass
} finally {
if (reader != null) reader.close();
reader = null;
}
try {
writer = new IndexWriter(dir, new IndexWriterConfig(
TEST_VERSION_CURRENT, new MockAnalyzer())
.setMergeScheduler(new SerialMergeScheduler()) // no threads!
);
writer.optimize();
reader = writer.getReader();
reader.document(0); // to catch also 2.9->3.0 stored field change
fail("IndexWriter creation should not pass for "+unsupportedNames[i]);
} catch (IndexFormatTooOldException e) {
// pass
} finally {
if (reader != null) reader.close();
reader = null;
if (writer != null) writer.close();
writer = null;
}
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
CheckIndex checker = new CheckIndex(dir);
checker.setInfoStream(new PrintStream(bos));
CheckIndex.Status indexStatus = checker.checkIndex();
assertFalse(indexStatus.clean);
assertTrue(bos.toString().contains(IndexFormatTooOldException.class.getName()));
dir.close();
rmDir(unsupportedNames[i]);
}
}
public void testOptimizeOldIndex() throws Exception { public void testOptimizeOldIndex() throws Exception {
for(int i=0;i<oldNames.length;i++) { for(int i=0;i<oldNames.length;i++) {
unzip(getDataFile("index." + oldNames[i] + ".zip"), oldNames[i]); unzip(getDataFile("index." + oldNames[i] + ".zip"), oldNames[i]);