refactor: Shift KmerIndex ownership to Arc for thread-safe sharing

Replaces lifetime-bound references with runtime reference counting across multiple crates. This enables safe concurrent access across parallel workers without explicit cloning or manual lifetime management. Introduces the `query` and `utils` CLI commands in obikmer2, along with supporting modules for batch processing, sparse indexing, sliding-window findere logic, and output formatting. Updates dependency manifests and aligns test suites with the new ownership model.
This commit is contained in:
Eric Coissac committed 2026-08-28 19:32:45 +02:00
1 parent 10a0909687
commit bd7729b095
31 files changed
+1689 -178

No files matched your search

+13 -12
View File
@@ -1,5 +1,6 @@
use std::fs;
use std::path::Path;
use std::sync::Arc;
use rayon::prelude::*;
@@ -88,22 +89,22 @@ fn layer_bytes(layer: &KmerLayer) -> LayerBytes {
/// once up front — this is diagnostic tooling, not a hot path, so trading
/// that eager open for not having to hand-reconstruct every layer's file
/// paths is the right tradeoff here.
pub struct BitsPerKmer<'a> {
index: &'a KmerIndex,
pub struct BitsPerKmer {
index: Arc<KmerIndex>,
}
impl<'a> BitsPerKmer<'a> {
pub fn new(index: &'a KmerIndex) -> Self {
impl BitsPerKmer {
pub fn new(index: Arc<KmerIndex>) -> Self {
Self { index }
}
}
impl Algorithm for BitsPerKmer<'_> {
impl Algorithm for BitsPerKmer {
type Output = IndexBitsPerKmer;
fn run(&mut self) -> obikalgorithm::Result<IndexBitsPerKmer> {
let n_genomes = self.index.meta().genomes()?.len().max(1);
let cache = IndexCache::new(self.index, None);
let cache = IndexCache::new(Arc::clone(&self.index), None);
let layers: Vec<&KmerLayer> = cache.iter().collect();
let (n_kmers, mphf_b, evidence_b, matrix_b) = layers
@@ -148,23 +149,23 @@ impl Algorithm for BitsPerKmer<'_> {
/// genome has a non-zero value (presence = 1, count > 0) — via
/// `KmerLayer::col_weights` (`obicompactvec::ColumnWeights`), one call per
/// layer instead of hand-opening each layer's matrix and summing rows.
pub struct GenomeKmerCounts<'a> {
index: &'a KmerIndex,
pub struct GenomeKmerCounts {
index: Arc<KmerIndex>,
}
impl<'a> GenomeKmerCounts<'a> {
pub fn new(index: &'a KmerIndex) -> Self {
impl GenomeKmerCounts {
pub fn new(index: Arc<KmerIndex>) -> Self {
Self { index }
}
}
impl Algorithm for GenomeKmerCounts<'_> {
impl Algorithm for GenomeKmerCounts {
/// `(total_distinct_kmers, per_genome_kmer_counts)`.
type Output = (usize, Vec<u64>);
fn run(&mut self) -> obikalgorithm::Result<(usize, Vec<u64>)> {
let n_genomes = self.index.meta().genomes()?.len();
let cache = IndexCache::new(self.index, None);
let cache = IndexCache::new(Arc::clone(&self.index), None);
let layers: Vec<&KmerLayer> = cache.iter().collect();
let total_kmers: usize = layers.iter().map(|l| l.n()).sum();