tablestg 0.2.0

Storage for database tables
Documentation
use crate::*;

/// Storage of variable length values (varval).
pub struct VarVal {
    pub t: Table,
}

impl VarVal {
    /// Store a new varval, returns id.
    pub fn store(&mut self, user_data: &[u8], ps: &mut PageSet) -> u64 {
        let mut todo: usize = user_data.len();
        let id = self.t.next_id;
        let mut done: usize = 0;

        while todo > 0 {
            let mut amount = self.t.record_size;
            if amount > todo {
                amount = todo
            };
            self.t.append(&user_data[done..done + amount], ps);
            done += amount;
            todo -= amount;
        }
        id
    }

    /// Get a stored varval with given id and len into buf.
    pub fn get(&mut self, mut id: u64, len: usize, user_data: &mut [u8], ps: &mut PageSet) {
        let mut done = 0;
        let mut todo = len;
        while todo > 0 {
            let mut amount = self.t.record_size;
            if amount > todo {
                amount = todo
            };
            self.t.read(id, &mut user_data[done..done + amount], ps);
            done += amount;
            todo -= amount;
            id += 1;
        }
    }

    /// Delete a stored varval with given id and len.
    pub fn delete(&mut self, id: u64, len: usize, ps: &mut PageSet) {
        let count = len.div_ceil(self.t.record_size);
        self.t.delete_range(id, count, ps);
    }

    /// Update a varval.
    ///
    /// Will re-use old id if number of chunks needed does not change.
    pub fn update(
        &mut self,
        old_id: u64,
        old_len: usize,
        user_data: &[u8],
        ps: &mut PageSet,
    ) -> u64 {
        let old_count = old_len.div_ceil(self.t.record_size);
        let new_count = user_data.len().div_ceil(self.t.record_size);
        if old_count == new_count {
            let mut done = 0;
            let mut todo = user_data.len();
            let mut id = old_id;
            while todo > 0 {
                let mut amount = self.t.record_size;
                if amount > todo {
                    amount = todo;
                }
                self.t.update(id, &user_data[done..done + amount], ps);
                done += amount;
                todo -= amount;
                id += 1;
            }
            old_id
        } else {
            self.t.delete_range(old_id, old_count, ps);
            self.store(user_data, ps)
        }
    }
}

#[cfg(test)]
pub fn test_varval(ps: &mut PageSet) {
    let rpp = 64;

    let t = Table {
        next_id: 0,
        root: ps.new_page(),
        len: 0,
        record_size: ((PAGE_SIZE - 8) / rpp) as usize,
        rpp,
    };

    let mut vv = VarVal { t };

    let mut ids = Vec::new();

    let d1 = b"Hello there George";
    let d2 = b"Tuesday is lovely, so is Wednesday";
    //let d2 = b"Tuesday is lovely! So is Wednesday. .............................................Saturday also.";
    for _ in 0..1_000_000 {
        let id = vv.store(d1, ps);
        ids.push(id);
        // println!("test varval stored {}", id);
        // println!("");
    }

    //println!("ids={:?}", ids);

    let mut buf = vec![0; d1.len()];
    for id in &ids {
        vv.get(*id, d1.len(), &mut buf, ps);
        // println!("buf={}", tos(&buf));
        assert_eq!(buf, d1);
    }

    let mut nids = Vec::new();
    for id in &ids {
        let nid = vv.update(*id, d1.len(), d2, ps);
        nids.push(nid);
    }

    let mut buf = vec![0; d2.len()];
    for id in &nids {
        vv.get(*id, d2.len(), &mut buf, ps);
        assert_eq!(buf, d2);
    }

    println!("t.len (page details)={}", vv.t.len);
}

/* Next: make test that stores customer records, Name, Email, Created in a table.
   Then scans them.
*/