This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / knot2 / crates / knot-git / src / bitmap / midx.rs
3.3 kB 110 lines
1use std::path::{Path, PathBuf}; 2 3use knot_types::Oid; 4 5use crate::objects::{Haves, Wants}; 6 7use super::reader; 8use super::revindex::{Order, OrderTable}; 9use super::writer; 10use crate::error::GitError; 11use crate::repo::Repo; 12 13// hashtag easter egg 14const RIDX_SIGNATURE: u32 = 0x5249_4458; 15const MIDX_ALLOC_LIMIT_BYTES: usize = 16 * 1024 * 1024; 16 17fn midx_path(objects_dir: &Path) -> PathBuf { 18 objects_dir.join("pack").join("multi-pack-index") 19} 20 21fn sidecar(objects_dir: &Path, checksum: &gix_hash::ObjectId, ext: &str) -> PathBuf { 22 objects_dir 23 .join("pack") 24 .join(format!("multi-pack-index-{}.{ext}", checksum.to_hex())) 25} 26 27pub(super) fn write(repo: &Repo) -> Result<bool, GitError> { 28 let kind = repo.object_format().kind(); 29 let objects_dir = repo.objects_dir(); 30 let file = match gix_pack::multi_index::File::at( 31 midx_path(&objects_dir), 32 Some(MIDX_ALLOC_LIMIT_BYTES), 33 ) { 34 Ok(file) => file, 35 Err(_) => return Ok(false), 36 }; 37 let order = OrderTable::from_file(&file); 38 if order.len() == 0 { 39 return Ok(false); 40 } 41 42 let _boost = knot_resource::saturate(); 43 let types = writer::type_index_bits(repo, &order)?; 44 let selected = writer::selected_entries(repo, &order)?; 45 if selected.is_empty() { 46 return Ok(false); 47 } 48 49 let checksum = file.checksum(); 50 let bytes = writer::assemble(kind, &checksum, &types, &selected)?; 51 52 write_rev( 53 &sidecar(&objects_dir, &checksum, "rev"), 54 &order, 55 kind, 56 &checksum, 57 )?; 58 writer::install(&sidecar(&objects_dir, &checksum, "bitmap"), &bytes)?; 59 Ok(true) 60} 61 62fn write_rev( 63 path: &Path, 64 order: &OrderTable, 65 kind: gix::hash::Kind, 66 checksum: &gix_hash::ObjectId, 67) -> Result<(), GitError> { 68 let hash_id: u32 = match kind { 69 gix::hash::Kind::Sha256 => 2, 70 _ => 1, 71 }; 72 let mut out = Vec::new(); 73 out.extend_from_slice(&RIDX_SIGNATURE.to_be_bytes()); 74 out.extend_from_slice(&1u32.to_be_bytes()); 75 out.extend_from_slice(&hash_id.to_be_bytes()); 76 order 77 .index_positions_in_bit_order() 78 .iter() 79 .for_each(|position| out.extend_from_slice(&position.get().to_be_bytes())); 80 out.extend_from_slice(checksum.as_slice()); 81 let mut hasher = gix_hash::hasher(kind); 82 hasher.update(&out); 83 let digest = hasher 84 .try_finalize() 85 .map_err(|error| GitError::Backend(format!("midx revindex checksum: {error}")))?; 86 out.extend_from_slice(digest.as_slice()); 87 writer::install(path, &out) 88} 89 90pub(super) fn reachable( 91 repo: &Repo, 92 wants: Wants<'_>, 93 haves: Haves<'_>, 94) -> Result<Option<Vec<Oid>>, GitError> { 95 let kind = repo.object_format().kind(); 96 let objects_dir = repo.objects_dir(); 97 let file = match gix_pack::multi_index::File::at( 98 midx_path(&objects_dir), 99 Some(MIDX_ALLOC_LIMIT_BYTES), 100 ) { 101 Ok(file) => file, 102 Err(_) => return Ok(None), 103 }; 104 let Ok(bytes) = std::fs::read(sidecar(&objects_dir, &file.checksum(), "bitmap")) else { 105 return Ok(None); 106 }; 107 let order = OrderTable::from_file(&file); 108 let maps = reader::parse(&bytes, kind, order.len())?; 109 super::resolve(repo, &order, &maps, wants, haves) 110}