use crate::*;
use pstd::veca;
use std::hash::Hasher;
const SCHEMA: usize = 0;
const TABLE: usize = 1;
const OBJ_ID: usize = 0;
const _OBJ_SCHEMA: usize = 1;
const OBJ_NAME: usize = 2;
const OBJ_INNER: usize = 3;
pub fn make_obj_dt() -> DataType {
use pstd::veca;
let objenum = DataType::Enum(veca![
(LString::from("Schema"), DataType::Empty),
(LString::from("Table"), table_dt()),
]);
DataType::Struct(veca![
(LString::from("Id"), DataType::Int),
(LString::from("Schema"), DataType::Int),
(LString::from("Name"), DataType::String),
(LString::from("Inner"), objenum),
])
}
pub struct IdKey<'a> {
pub rid: i64,
pub dt: &'a DataType,
}
impl <'a> IdKey<'a> {
pub fn insert(&self, r: &Value, main: &mut HashMapInfo, ps: &mut PageSet ) {
let addr = VarValAddr::new(self.dt, r, ps);
let mut hm = HashMap::restore(*main, ps);
hm.insert(self, addr);
if hm.root_changed() {
*main = hm.save();
}
}
}
impl<'a> Hash for IdKey<'a> {
fn hash<H: Hasher>(&self, h: &mut H) {
self.rid.hash(h);
}
}
impl<'a> Key<VarValAddr> for IdKey<'a> {
fn ok(&self, addr: VarValAddr, ps: &mut PageSet) -> Option<(VarValAddr, Value)> {
let v = addr.get(self.dt, ps);
let rid = v.list()[0].int();
if rid == self.rid {
return Some((addr, v));
}
None
}
}
pub fn get_obj(rid: i64, ps: &mut PageSet) -> Option<(VarValAddr, Value)> {
let dt = ps.obj_dt.clone();
let key = IdKey { rid, dt: &dt };
HashMap::restore(ps.obj_map, ps).get(&key)
}
#[derive(Hash)]
pub struct ObjNameKey<'a> {
name: &'a str,
}
impl<'a> Key<i64> for ObjNameKey<'a> {
fn ok(&self, addr: i64, ps: &mut PageSet) -> Option<(i64, Value)> {
let (_, v) = get_obj(addr, ps).unwrap();
let name = v.list()[OBJ_NAME].string();
if self.name == name {
return Some((addr, v));
}
None
}
}
pub fn list_obj_all(ps: &mut PageSet) {
let mut hm = HashMap::<VarValAddr>::restore(ps.obj_map, ps);
let mut x = hm.all_addr();
x.sort();
let dt = ps.obj_dt.clone();
for addr in x {
let r = addr.get(&dt, ps);
println!("list_obj_all addr={:?} r={:?}", addr, r);
}
}
fn create_obj_inner(rid: i64, r: Value, ps: &mut PageSet) {
let dt = ps.obj_dt.clone();
let addr = VarValAddr::new(&dt, &r, ps);
let key = IdKey { rid, dt: &dt };
let mut hm = HashMap::restore(ps.obj_map, ps);
hm.insert(&key, addr);
if hm.root_changed() {
ps.obj_map = hm.save();
}
}
fn index_obj_by_name(id: i64, name: &str, ps: &mut PageSet) {
let key = ObjNameKey { name };
let mut hm = HashMap::restore(ps.obj_by_name, ps);
hm.insert(&key, id);
if hm.root_changed() {
ps.obj_by_name = hm.save();
}
}
pub fn create_obj(rid: i64, name: &str, inner: Value, ps: &mut PageSet) {
let r = Value::List(veca![
Value::Int(rid), Value::Int(0), Value::String(LString::from(name)),
inner
]);
create_obj_inner(rid, r, ps);
index_obj_by_name(rid, name, ps);
}
pub fn get_obj_from_name(name: &str, ps: &mut PageSet) -> Option<(i64, Value)> {
let key = ObjNameKey { name };
let mut hm = HashMap::restore(ps.obj_by_name, ps);
if let Some(x) = hm.get(&key) {
return Some(x);
}
None
}
pub fn save_obj(addr: VarValAddr, obj: Value, ps: &mut PageSet) {
let dt = ps.obj_dt.clone();
let addr2 = addr.update(&dt, &obj, ps);
if addr2 != addr {
let rid = obj.list()[OBJ_ID].int();
let key = IdKey { rid, dt: &dt };
let mut hm = HashMap::restore(ps.obj_map, ps);
hm.remove(&key);
hm.insert(&key, addr2);
if hm.root_changed() {
ps.obj_map = hm.save();
}
}
}
pub fn create_schema(name: &str, ps: &mut PageSet) -> Option<(i64, Value)> {
let obj = get_obj_from_name(name, ps);
if obj.is_some() {
obj
} else {
let rid = ps.next_obj_id;
ps.next_obj_id = rid + 1;
let inner = Value::Enum(SCHEMA, LBox::new(Value::Empty));
create_obj(rid, name, inner, ps);
None
}
}
fn table_dt() -> DataType {
DataType::Struct(veca![
(LString::from("NextId"), DataType::Int),
(LString::from("Root"), DataType::Int),
(LString::from("Buckets"), DataType::Int),
(LString::from("IRoot"), DataType::Int),
(LString::from("IBuckets"), DataType::Int),
])
}
fn set_table_datatype(rid: i64, tdt: DataType, ps: &mut PageSet) {
let dt = DataType::Tuple(veca![DataType::Int, DataType::DataType]);
let v = Value::List(veca![Value::Int(rid), Value::DataType(tdt)]);
let addr = VarValAddr::new(&dt, &v, ps);
println!("xxxxx addr={:?} v={:?}", addr, &v);
let key = IdKey { rid, dt: &dt };
let mut hm = HashMap::restore(ps.table_datatype_map, ps);
hm.insert(&key, addr);
if hm.root_changed() {
ps.table_datatype_map = hm.save();
}
}
pub fn get_table_datatype(rid: i64, ps: &mut PageSet) -> DataType {
let dt = DataType::Tuple(veca![DataType::Int, DataType::DataType]);
let key = IdKey { rid, dt: &dt };
let mut hm = HashMap::restore(ps.table_datatype_map, ps);
let mut av = hm.get(&key).unwrap();
let dt = av.1.list_mut()[1].datatype_mut();
std::mem::take(dt)
}
pub fn create_table(name: &str, dt: DataType, ps: &mut PageSet) -> Option<(i64, Value)> {
let obj = get_obj_from_name(name, ps);
if obj.is_some() {
obj
} else {
let rid = ps.next_obj_id;
ps.next_obj_id = rid + 1;
let hm = HashMap::<VarValAddr>::new(ps, 1);
let i = hm.save();
let hm = HashMap::<VarValAddr>::new(ps, 1);
let x = hm.save();
let tableinfo = Value::List(veca![
Value::Int(0), Value::Int(i.root as i64),
Value::Int(i.buckets as i64), Value::Int(x.root as i64),
Value::Int(x.buckets as i64),
]);
let inner = Value::Enum(TABLE, LBox::new(tableinfo));
create_obj(rid, name, inner, ps);
set_table_datatype(rid, dt, ps);
None
}
}
#[derive(Debug)]
pub struct TabInfo {
pub alloc: i64,
pub main: HashMapInfo,
pub index: HashMapInfo,
}
pub fn decode_table(obj: Value) -> TabInfo {
let (tag, tableinfo) = &obj.list()[OBJ_INNER].en();
assert!(**tag == TABLE);
let list = tableinfo.list();
let alloc = list[0].int();
let root = list[1].int() as u64;
let buckets = list[2].int() as u64;
let iroot = list[3].int() as u64;
let ibuckets = list[4].int() as u64;
TabInfo {
alloc,
main: HashMapInfo{ root, buckets },
index: HashMapInfo{ root:iroot, buckets:ibuckets },
}
}
pub fn save_table(rid: i64, info: TabInfo, ps: &mut PageSet) {
let (addr, mut obj) = get_obj(rid, ps).unwrap();
let inner = &mut obj.list_mut()[OBJ_INNER];
let (tag, tableinfo) = inner.en_mut();
assert!(*tag == TABLE);
let list = tableinfo.list_mut();
list[0] = Value::Int(info.alloc);
list[1] = Value::Int(info.main.root as i64);
list[2] = Value::Int(info.main.buckets as i64);
list[3] = Value::Int(info.index.root as i64);
list[4] = Value::Int(info.index.buckets as i64);
save_obj(addr, obj, ps);
}