use super::branch::{Branch, BranchId, BranchStatus};
use satellite_lockfree::ConcurrentSkiplist;
use std::sync::atomic::{AtomicU64, Ordering};
pub struct BranchManager {
next_id: AtomicU64,
branches: ConcurrentSkiplist<BranchId, Branch>,
active_count: AtomicU64,
failed_count: AtomicU64,
}
impl BranchManager {
pub fn new() -> Self {
let manager = Self {
next_id: AtomicU64::new(1),
branches: ConcurrentSkiplist::new(),
active_count: AtomicU64::new(1),
failed_count: AtomicU64::new(0),
};
let root = Branch::new_root();
manager.branches.insert(0, root);
manager
}
pub fn fork(&self, parent_id: BranchId, num_children: usize) -> Vec<BranchId> {
let parent_depth = self
.branches
.get(&parent_id)
.map(|b| b.depth())
.unwrap_or(0);
let mut child_ids = Vec::with_capacity(num_children);
for _ in 0..num_children {
let id = self.next_id.fetch_add(1, Ordering::Relaxed);
let child = Branch::new_child(id, parent_id, parent_depth);
self.branches.insert(id, child);
child_ids.push(id);
self.active_count.fetch_add(1, Ordering::Relaxed);
}
if let Some(parent) = self.branches.get(&parent_id) {
for _ in 0..num_children {
parent.inc_refcount();
}
}
child_ids
}
pub fn mark_failed(&self, branch_id: BranchId) {
if let Some(branch) = self.branches.get(&branch_id) {
if branch.status() == BranchStatus::Active {
branch.set_status(BranchStatus::Failed);
self.active_count.fetch_sub(1, Ordering::Relaxed);
self.failed_count.fetch_add(1, Ordering::Relaxed);
if let Some(parent_id) = branch.parent_id() {
if let Some(parent) = self.branches.get(&parent_id) {
let new_count = parent.dec_refcount();
if new_count == 0 && parent.is_active() {
self.mark_failed(parent_id);
}
}
}
}
}
}
pub fn mark_solved(&self, branch_id: BranchId) {
if let Some(branch) = self.branches.get(&branch_id) {
branch.set_status(BranchStatus::Solved);
self.active_count.fetch_sub(1, Ordering::Relaxed);
}
}
pub fn is_failed(&self, branch_id: BranchId) -> bool {
self.branches
.get(&branch_id)
.map(|b| b.is_failed())
.unwrap_or(true)
}
pub fn active_count(&self) -> u64 {
self.active_count.load(Ordering::Relaxed)
}
pub fn failed_count(&self) -> u64 {
self.failed_count.load(Ordering::Relaxed)
}
pub fn total_count(&self) -> u64 {
self.next_id.load(Ordering::Relaxed)
}
}
impl Default for BranchManager {
fn default() -> Self {
Self::new()
}
}