use crate::{util, Cell, Ordering, Rc, Record, SaveOp, SortedFile, DB};
pub const NFT: usize = 4;
pub const MINF: usize = 28;
fn total(len: usize, ft: usize) -> usize {
let bpf = 32 * ft + MINF;
let nf = (len + bpf - 1) / bpf;
nf * (bpf + 12)
}
pub fn fragment_type(len: usize) -> usize {
let mut best = usize::MAX;
let mut result = 0;
for ft in 0..NFT {
let t = total(len, ft);
if t < best {
best = t;
result = ft;
}
}
result
}
pub struct ByteStorage {
pub file: Rc<SortedFile>,
pub id_gen: Cell<u64>,
pub bpf: usize,
}
impl ByteStorage {
pub fn new(root_page: u64, ft: usize) -> Self {
let bpf = 32 * ft + MINF;
let file = Rc::new(SortedFile::new(9 + bpf, 8, root_page));
ByteStorage {
file,
id_gen: Cell::new(u64::MAX),
bpf,
}
}
pub fn get_id(&self, db: &DB) -> u64 {
let mut result = self.id_gen.get();
if result == u64::MAX {
result = 0;
let start = Fragment::new(u64::MAX, self.bpf);
if let Some((pp, off)) = self.file.clone().dsc(db, Box::new(start)).next() {
let p = pp.borrow();
result = 1 + util::getu64(&p.data, off);
}
self.id_gen.set(result);
}
result
}
pub fn save(&self, db: &DB, op: SaveOp) {
self.file.save(db, op);
}
pub fn encode(&self, db: &DB, bytes: &[u8]) -> u64 {
let result = self.get_id(db);
let mut r = Fragment::new(0, self.bpf);
let n = bytes.len();
let mut done = 0;
let mut _frags = 0;
loop {
r.id = self.id_gen.get();
self.id_gen.set(r.id + 1);
let mut len = n - done;
if len > self.bpf {
r.len = (self.bpf << 1) as u8;
len = self.bpf
} else {
r.len = 1 + ((len as u8) << 1);
}
r.bytes[..len].copy_from_slice(&bytes[done..(len + done)]);
done += len;
_frags += 1;
self.file.insert(db, &r);
if done == n {
break;
}
}
result
}
pub fn decode(&self, db: &DB, mut id: u64, inline: usize) -> Vec<u8> {
let mut result = vec![0_u8; inline]; let start = Fragment::new(id, self.bpf);
for (pp, off) in self.file.asc(db, Box::new(start)) {
let p = pp.borrow();
let xid = util::getu64(&p.data, off);
debug_assert!(xid == id);
id += 1;
let len = p.data[off + 8] as usize;
let off = off + 9;
result.extend_from_slice(&p.data[off..off + (len >> 1)]);
if len & 1 == 1 {
break;
}
}
result
}
pub fn delcode(&self, db: &DB, id: u64) {
let start = Fragment::new(id, self.bpf);
let mut n = 0;
for (pp, off) in self.file.asc(db, Box::new(start)) {
let p = pp.borrow();
let xid = util::getu64(&p.data, off);
debug_assert!(xid == id + n);
n += 1;
let len = &p.data[off + 8];
if len & 1 == 1 {
break;
}
}
let mut r = Fragment::new(0, self.bpf);
for xid in id..id + n {
r.id = xid;
self.file.remove(db, &r);
}
}
}
struct Fragment {
id: u64,
len: u8,
bytes: Vec<u8>,
}
impl Fragment {
pub fn new(id: u64, bpf: usize) -> Self {
Fragment {
id,
len: 0,
bytes: vec![0; bpf],
}
}
}
impl Record for Fragment {
fn compare(&self, _db: &DB, data: &[u8]) -> Ordering {
let val = util::getu64(data, 0);
self.id.cmp(&val)
}
fn save(&self, data: &mut [u8]) {
util::setu64(data, self.id);
data[8] = self.len;
let bpf = self.bytes.len();
data[9..9 + bpf].copy_from_slice(&self.bytes[..bpf]);
}
}