use std::io;
use crate::codecs::codec_footers::{
FOOTER_LENGTH, retrieve_checksum, retrieve_checksum_with_length, verify_checksum,
};
use crate::codecs::codec_headers;
use crate::codecs::codec_headers::check_index_header;
use crate::index::index_file_names;
use crate::store::{Directory, FileBacking, IndexInput};
#[derive(Clone, Copy)]
pub(crate) enum FooterValidation {
VerifyFullCrc,
RetrieveStructure,
}
pub(crate) struct FileMetadata {
pub extension: &'static str,
pub codec_name: &'static str,
pub version_min: i32,
pub version_max: i32,
pub footer: FooterValidation,
}
#[derive(Clone, Copy)]
pub(crate) enum IndexFile {
NormsMeta,
NormsData,
DocValuesMeta,
DocValuesData,
StoredFieldsMeta,
StoredFieldsData,
StoredFieldsIndex,
TermVectorsMeta,
TermVectorsData,
TermVectorsIndex,
PointsMeta,
PointsData,
PointsIndex,
PostingsMeta,
PostingsData,
PostingsPositions,
TermsMeta,
TermsData,
TermsIndex,
FieldInfos,
SegmentInfo,
CompoundEntries,
CompoundData,
}
impl IndexFile {
pub(crate) fn metadata(self) -> FileMetadata {
use FooterValidation::*;
match self {
IndexFile::NormsMeta => FileMetadata {
extension: "nvm",
codec_name: "Lucene90NormsMetadata",
version_min: 0,
version_max: 0,
footer: VerifyFullCrc,
},
IndexFile::NormsData => FileMetadata {
extension: "nvd",
codec_name: "Lucene90NormsData",
version_min: 0,
version_max: 0,
footer: RetrieveStructure,
},
IndexFile::DocValuesMeta => FileMetadata {
extension: "dvm",
codec_name: "Lucene90DocValuesMetadata",
version_min: 0,
version_max: 0,
footer: VerifyFullCrc,
},
IndexFile::DocValuesData => FileMetadata {
extension: "dvd",
codec_name: "Lucene90DocValuesData",
version_min: 0,
version_max: 0,
footer: RetrieveStructure,
},
IndexFile::StoredFieldsMeta => FileMetadata {
extension: "fdm",
codec_name: "Lucene90FieldsIndexMeta",
version_min: 1,
version_max: 1,
footer: VerifyFullCrc,
},
IndexFile::StoredFieldsData => FileMetadata {
extension: "fdt",
codec_name: "Lucene90StoredFieldsFastData",
version_min: 1,
version_max: 1,
footer: RetrieveStructure,
},
IndexFile::StoredFieldsIndex => FileMetadata {
extension: "fdx",
codec_name: "Lucene90FieldsIndexIdx",
version_min: 0,
version_max: 0,
footer: RetrieveStructure,
},
IndexFile::TermVectorsMeta => FileMetadata {
extension: "tvm",
codec_name: "Lucene90TermVectorsIndexMeta",
version_min: 0,
version_max: 0,
footer: VerifyFullCrc,
},
IndexFile::TermVectorsData => FileMetadata {
extension: "tvd",
codec_name: "Lucene90TermVectorsData",
version_min: 0,
version_max: 0,
footer: RetrieveStructure,
},
IndexFile::TermVectorsIndex => FileMetadata {
extension: "tvx",
codec_name: "Lucene90TermVectorsIndexIdx",
version_min: 0,
version_max: 0,
footer: RetrieveStructure,
},
IndexFile::PointsMeta => FileMetadata {
extension: "kdm",
codec_name: "Lucene90PointsFormatMeta",
version_min: 1,
version_max: 1,
footer: VerifyFullCrc,
},
IndexFile::PointsData => FileMetadata {
extension: "kdd",
codec_name: "Lucene90PointsFormatData",
version_min: 1,
version_max: 1,
footer: RetrieveStructure,
},
IndexFile::PointsIndex => FileMetadata {
extension: "kdi",
codec_name: "Lucene90PointsFormatIndex",
version_min: 1,
version_max: 1,
footer: RetrieveStructure,
},
IndexFile::PostingsMeta => FileMetadata {
extension: "psm",
codec_name: "Lucene103PostingsWriterMeta",
version_min: 0,
version_max: 0,
footer: VerifyFullCrc,
},
IndexFile::PostingsData => FileMetadata {
extension: "doc",
codec_name: "Lucene103PostingsWriterDoc",
version_min: 0,
version_max: 0,
footer: RetrieveStructure,
},
IndexFile::PostingsPositions => FileMetadata {
extension: "pos",
codec_name: "Lucene103PostingsWriterPos",
version_min: 0,
version_max: 0,
footer: RetrieveStructure,
},
IndexFile::TermsMeta => FileMetadata {
extension: "tmd",
codec_name: "BlockTreeTermsMeta",
version_min: 0,
version_max: 0,
footer: VerifyFullCrc,
},
IndexFile::TermsData => FileMetadata {
extension: "tim",
codec_name: "BlockTreeTermsDict",
version_min: 0,
version_max: 0,
footer: RetrieveStructure,
},
IndexFile::TermsIndex => FileMetadata {
extension: "tip",
codec_name: "BlockTreeTermsIndex",
version_min: 0,
version_max: 0,
footer: RetrieveStructure,
},
IndexFile::FieldInfos => FileMetadata {
extension: "fnm",
codec_name: "Lucene94FieldInfos",
version_min: 2,
version_max: 2,
footer: VerifyFullCrc,
},
IndexFile::SegmentInfo => FileMetadata {
extension: "si",
codec_name: "Lucene90SegmentInfo",
version_min: 0,
version_max: 0,
footer: VerifyFullCrc,
},
IndexFile::CompoundEntries => FileMetadata {
extension: "cfe",
codec_name: "Lucene90CompoundEntries",
version_min: 0,
version_max: 0,
footer: VerifyFullCrc,
},
IndexFile::CompoundData => FileMetadata {
extension: "cfs",
codec_name: "Lucene90CompoundData",
version_min: 0,
version_max: 0,
footer: RetrieveStructure,
},
}
}
}
pub(crate) struct CodecFileHandle {
kind: IndexFile,
backing: FileBacking,
header_len: usize,
version: i32,
}
impl CodecFileHandle {
pub(crate) fn open(
directory: &dyn Directory,
kind: IndexFile,
segment_name: &str,
segment_id: &[u8; codec_headers::ID_LENGTH],
segment_suffix: &str,
) -> io::Result<Self> {
let meta = kind.metadata();
let file_name =
index_file_names::segment_file_name(segment_name, segment_suffix, meta.extension);
let backing = directory.open_file(&file_name)?;
match meta.footer {
FooterValidation::VerifyFullCrc => verify_checksum(backing.as_bytes())?,
FooterValidation::RetrieveStructure => {
retrieve_checksum(backing.as_bytes())?;
}
}
let header_input_bytes: &[u8] = match meta.footer {
FooterValidation::VerifyFullCrc => {
&backing.as_bytes()[..backing.as_bytes().len() - FOOTER_LENGTH]
}
FooterValidation::RetrieveStructure => backing.as_bytes(),
};
let mut header_input = IndexInput::new(&file_name, header_input_bytes);
let version = check_index_header(
&mut header_input,
meta.codec_name,
meta.version_min,
meta.version_max,
segment_id,
segment_suffix,
)?;
let header_len = codec_headers::index_header_length(meta.codec_name, segment_suffix);
Ok(Self {
kind,
backing,
header_len,
version,
})
}
pub(crate) fn version(&self) -> i32 {
self.version
}
pub(crate) fn body(&self) -> IndexInput<'_> {
let bytes = self.backing.as_bytes();
let end = match self.kind.metadata().footer {
FooterValidation::VerifyFullCrc => bytes.len() - FOOTER_LENGTH,
FooterValidation::RetrieveStructure => bytes.len(),
};
IndexInput::new(self.kind.metadata().extension, &bytes[self.header_len..end])
}
pub(crate) fn verify_length(&self, expected: i64) -> io::Result<()> {
match self.kind.metadata().footer {
FooterValidation::VerifyFullCrc => Ok(()),
FooterValidation::RetrieveStructure => {
retrieve_checksum_with_length(self.backing.as_bytes(), expected)?;
Ok(())
}
}
}
pub(crate) fn into_backing(self) -> FileBacking {
self.backing
}
}