corundum 0.4.1

Persistent Programming Library
Documentation
use corundum::Root;
use corundum::default::*;
use corundum::open_flags::*;

type P = Allocator;

struct Consumer {
    buf: PMutex<u64>,
    volume: Parc<PMutex<u64>>
}

#[derive(Root)]
struct Root {
    volume: Parc<PMutex<u64>>,
    consumers: PRefCell<PVec<Parc<Consumer>>>
}

fn main() {
    use std::env;
    use std::vec::Vec as StdVec;

    let mut args: StdVec<String> = env::args().collect();

    if args.len() < 2 {
        println!("usage: {} file-name [OPTIONS]", args[0]);
        println!("OPTIONS:");
        println!("  -i <num>   Initial value (default: 1000000)");
        println!("  -t <num>   Number of threads (default: 4)");
        println!("  -r         Reset");
        return;  
    }

    let root = P::open::<Root>(&args[1], O_CFNE | O_4GB).unwrap();
    let mut resetting = false;
    let mut init_val = 1000000;
    let mut t = root.consumers.borrow().len();

    args.remove(0);
    args.remove(0);
    while !args.is_empty() {
        if args[0] == "-i" && args.len() > 1 {
            args.remove(0);
            init_val = args[0].parse::<u64>().expect("Error: Expected a number");
        } else if args[0] == "-t" && args.len() > 1 {
            args.remove(0);
            t = args[0].parse::<usize>().expect("Error: Expected a number");
            assert!(t>0);
        } else if args[0] == "-r" {
            resetting = true;
        } else {
            panic!("Bad option `{}`", args[0]);
        }
        args.remove(0);
    }

    if resetting || root.consumers.borrow().is_empty() {
        println!("Initializing the consumers to pour {} gallons of oil into {} barrels", init_val, t);
        let r = root.clone();
        P::transaction(move |j| {
            let mut volume = r.volume.lock(j);
            let mut consumers = r.consumers.borrow_mut(j);
            *volume = init_val;
            if t == 0 { t = 4 };
            let quota = init_val / t as u64;
            consumers.clear();
            for _ in 0..t-1 {
                consumers.push(Parc::new(Consumer{
                    buf: PMutex::new(quota),
                    volume: r.volume.pclone(j)
                }, j), j);
                init_val -= quota;
            }
            consumers.push(Parc::new(Consumer{
                buf: PMutex::new(init_val),
                volume: r.volume.pclone(j)
            }, j), j);
        }).unwrap();
    }

    let mut threads = vec![];
    for c in &*root.consumers.borrow() {
        let v = c.demote();
        threads.push(std::thread::spawn(move || {
            loop {
                let v = v.clone();
                let mut b = P::transaction(|j| {
                    if let Some(c) = v.promote(j) {
                        let mut b = c.buf.lock(j);
                        let mut vol = c.volume.lock(j);
                        if *b > 100 {
                            *b -= 100;
                            *vol -= 100;
                            100
                        } else {
                            let r = *b;
                            *vol -= r;
                            *b = 0;
                            r
                        }
                    } else {
                        0
                    }
                }).unwrap();
    
                if b == 0 { break }

                P::transaction(move |j| {
                    if let Some(c) = v.promote(j) {
                        while b > 0 {
                            let vol = c.volume.lock(j);
                            b -= 1;
                            eprint!("\r\x1b[?25lRemaining: {:<12} \x1b[?25h", *vol + b);
                        }
                    }
                }).unwrap();
            }
        }));
    }

    for t in threads {
        t.join().unwrap();
    }
}