use std::path::{Path, PathBuf};
use super::BitmapIndex;
use super::packs::Packs;
use super::revindex::{self, Order, OrderTable, Positions, RevIndex};
use super::writer;
use knot_git::GitError;
use knot_git::Repo;
const MIDX_ALLOC_LIMIT_BYTES: usize = 16 * 1024 * 1024;
fn midx_path(objects_dir: &Path) -> PathBuf {
objects_dir.join("pack").join("multi-pack-index")
}
fn sidecar(objects_dir: &Path, checksum: &gix::hash::ObjectId, ext: &str) -> PathBuf {
objects_dir
.join("pack")
.join(format!("multi-pack-index-{}.{ext}", checksum.to_hex()))
}
pub(super) fn write(repo: &Repo, previous: Option<&BitmapIndex>) -> Result<bool, GitError> {
let kind = repo.object_format().kind();
let objects_dir = repo.objects_dir();
let file = match gix_pack::multi_index::File::at(
midx_path(&objects_dir),
Some(MIDX_ALLOC_LIMIT_BYTES),
) {
Ok(file) => file,
Err(_) => return Ok(false),
};
let checksum = file.checksum();
let packs = Packs::of_midx(&file, kind)?;
let order = OrderTable::from_file(file);
if order.len() == 0 {
return Ok(false);
}
let _boost = knot_resource::saturate();
let previous = previous.and_then(|index| writer::Previous::new(index, kind, &order));
let categories = writer::categories_in_bit_order(&packs, &order, previous.as_ref())?;
let types = writer::type_index_bits(&categories)?;
let selected = writer::selected_entries(repo, &order, &packs, &categories, previous.as_ref())?;
if selected.is_empty() {
return Ok(false);
}
let bytes = writer::assemble(kind, &checksum, &types, &selected)?;
revindex::write(
&sidecar(&objects_dir, &checksum, "rev"),
&order,
kind,
&checksum,
)?;
writer::install(&sidecar(&objects_dir, &checksum, "bitmap"), &bytes)?;
Ok(true)
}
pub(super) fn open(repo: &Repo) -> Result<Option<BitmapIndex>, GitError> {
let kind = repo.object_format().kind();
let objects_dir = repo.objects_dir();
let file = match gix_pack::multi_index::File::at(
midx_path(&objects_dir),
Some(MIDX_ALLOC_LIMIT_BYTES),
) {
Ok(file) => file,
Err(_) => return Ok(None),
};
let checksum = file.checksum();
let Some(bytes) = super::map_file(&sidecar(&objects_dir, &checksum, "bitmap")) else {
return Ok(None);
};
let rev_path = sidecar(&objects_dir, &checksum, "rev");
Ok(
RevIndex::open(&rev_path, Positions::Midx(file), kind, &checksum)?
.map(|rev| BitmapIndex { rev, bytes }),
)
}