// Stract is an open source web search engine.
// Copyright (C) 2024 Stract ApS
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see
use std::{
collections::BinaryHeap,
io::{BufWriter, Write},
ops::RangeBounds,
path::{Path, PathBuf},
};
use file_store::Peekable;
use super::{
blob_id_index::{BlobIdIndex, BlobIdIndexWriter},
blob_index::{BlobIndex, BlobIndexWriter},
blob_store::{BlobStore, BlobStoreWriter},
Serialized, SerializedRef,
};
use crate::Result;
pub struct Writers
where
W: Write,
{
pub id_index: BlobIdIndexWriter,
pub blob_index: BlobIndexWriter,
pub store: BlobStoreWriter,
pub bloom: W,
}
pub struct SegmentWriter
where
W: Write,
{
writers: Writers,
bloom: bloom::BytesBloomFilter>,
}
impl SegmentWriter
where
W: Write,
{
pub fn new(num_items: usize, writers: Writers) -> Self {
let bloom = bloom::BytesBloomFilter::new(num_items as u64, 0.01);
Self { writers, bloom }
}
}
impl SegmentWriter
where
W: Write,
{
fn insert(&mut self, key: SerializedRef<'_, K>, value: SerializedRef<'_, V>) -> Result<()> {
let ptr = self.writers.store.write(key, value)?;
let id = self.writers.blob_index.write(&ptr)?;
self.writers.id_index.insert(key.as_bytes(), &id)?;
self.bloom.insert_raw(key.as_bytes());
Ok(())
}
fn finish(self) -> Result<()> {
self.writers.id_index.finish()?;
self.writers.blob_index.finish()?;
self.writers.store.finish()?;
let mut wrt = BufWriter::new(self.writers.bloom);
bincode::encode_into_std_write(self.bloom, &mut wrt, common::bincode_config())?;
wrt.flush()?;
Ok(())
}
pub fn write_sorted_it<'a, I>(mut self, it: I) -> Result<()>
where
I: Iterator, SerializedRef<'a, V>)>,
{
for (key, value) in it {
self.insert(key, value)?;
}
self.finish()
}
}
pub struct Segment {
id_index: BlobIdIndex,
blob_index: BlobIndex,
store: BlobStore,
bloom: bloom::BytesBloomFilter>,
folder: PathBuf,
uuid: uuid::Uuid,
}
impl Segment {
pub fn open>(uuid: uuid::Uuid, folder: P) -> Result {
let id_index = BlobIdIndex::open(folder.as_ref().join(BlobIdIndex::::file_name(uuid)))?;
let blob_index = BlobIndex::open(folder.as_ref().join(BlobIndex::file_name(uuid)))?;
let store = BlobStore::open(folder.as_ref().join(BlobStore::::file_name(uuid)))?;
let mut bloom = std::fs::OpenOptions::new()
.read(true)
.open(folder.as_ref().join(Segment::::bloom_file_name(uuid)))?;
let bloom = bincode::decode_from_std_read(&mut bloom, common::bincode_config())?;
Ok(Self {
uuid,
id_index,
blob_index,
store,
bloom,
folder: folder.as_ref().to_path_buf(),
})
}
pub fn bloom_file_name(uuid: uuid::Uuid) -> String {
format!("{}.blm", uuid)
}
pub fn merge>(
segments: Vec>,
folder: P,
) -> Result