mirror of
https://github.com/urbit/ares.git
synced 2024-11-22 15:08:54 +03:00
[ares] add simplest possible checkpoints
These checkpoints are just a jam file of your state, with the event number and a checksum. If you crash while writing the checkpoint, it will be corrupt. Obviously, these snapshots will be slow to write on a real ship as well.
This commit is contained in:
parent
51b4735711
commit
6d51c8c262
@ -1,9 +1,18 @@
|
||||
use crate::interpreter::{interpret, raw_slot};
|
||||
use crate::mem::NockStack;
|
||||
use crate::mug::{mug, mug_u32};
|
||||
use crate::newt::Newt;
|
||||
use crate::noun::{Cell, Noun, D};
|
||||
use crate::noun::{Cell, IndirectAtom, Noun, D};
|
||||
use crate::serialization::{cue, jam};
|
||||
use ares_macros::tas;
|
||||
use memmap::Mmap;
|
||||
use memmap::MmapMut;
|
||||
use std::fs::{create_dir_all, File, OpenOptions};
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::path::PathBuf;
|
||||
use std::ptr::copy_nonoverlapping;
|
||||
use std::ptr::write_bytes;
|
||||
|
||||
#[allow(dead_code)]
|
||||
const LOAD_AXIS: u64 = 4;
|
||||
@ -17,16 +26,26 @@ const WISH_AXIS: u64 = 10;
|
||||
* u3_lord_init in vere to point at this binary and start vere like normal.
|
||||
*/
|
||||
pub fn serf() -> io::Result<()> {
|
||||
let mut stack = NockStack::new(8 << 10 << 10, 0);
|
||||
let mut newt = Newt::new();
|
||||
newt.ripe(&mut stack, 0, 0);
|
||||
let pier_path_string = std::env::args()
|
||||
.nth(2)
|
||||
.ok_or(io::Error::new(io::ErrorKind::Other, "no pier path"))?;
|
||||
let mut pier_path = PathBuf::from(pier_path_string);
|
||||
pier_path.push(".urb");
|
||||
pier_path.push("chk");
|
||||
create_dir_all(&pier_path)?;
|
||||
pier_path.push("snapshot.jam");
|
||||
|
||||
let mut eve = 0;
|
||||
let mut cor = D(0);
|
||||
let ref mut stack = NockStack::new(8 << 10 << 10, 0);
|
||||
let ref mut newt = Newt::new();
|
||||
|
||||
let (mut eve, mut cor) = load(stack, &pier_path).unwrap_or((0, D(0)));
|
||||
let mug = mug_u32(stack, cor);
|
||||
|
||||
newt.ripe(stack, eve, mug as u64);
|
||||
|
||||
// Can't use for loop because it borrows newt
|
||||
loop {
|
||||
let writ = if let Some(writ) = newt.next(&mut stack) {
|
||||
let writ = if let Some(writ) = newt.next(stack) {
|
||||
writ
|
||||
} else {
|
||||
break;
|
||||
@ -35,47 +54,67 @@ pub fn serf() -> io::Result<()> {
|
||||
let tag = raw_slot(writ, 2).as_direct().unwrap();
|
||||
match tag.data() {
|
||||
tas!(b"live") => {
|
||||
newt.live(&mut stack);
|
||||
let inner = raw_slot(writ, 6);
|
||||
match inner.as_direct().unwrap().data() {
|
||||
tas!(b"cram") => eprintln!("cram"),
|
||||
tas!(b"exit") => eprintln!("exit"),
|
||||
tas!(b"save") => {
|
||||
// XX what is eve for?
|
||||
eprintln!("save");
|
||||
save(stack, &pier_path, eve, cor);
|
||||
}
|
||||
tas!(b"meld") => eprintln!("meld"),
|
||||
tas!(b"pack") => eprintln!("pack"),
|
||||
_ => eprintln!("unknown live"),
|
||||
}
|
||||
newt.live(stack);
|
||||
}
|
||||
tas!(b"peek") => {
|
||||
let sam = raw_slot(writ, 7);
|
||||
let res = slam(&mut stack, &mut newt, cor, PEEK_AXIS, sam);
|
||||
newt.peek_done(&mut stack, res);
|
||||
let res = slam(stack, newt, cor, PEEK_AXIS, sam);
|
||||
newt.peek_done(stack, res);
|
||||
}
|
||||
tas!(b"play") => {
|
||||
if eve == 0 {
|
||||
let run = if eve == 0 {
|
||||
// apply lifecycle to first batch
|
||||
let lit = raw_slot(writ, 7);
|
||||
let sub = Cell::new_tuple(&mut stack, &[D(0), D(3)]).as_noun();
|
||||
let lyf = Cell::new_tuple(&mut stack, &[D(2), sub, D(0), D(2)]).as_noun();
|
||||
let gat = interpret(&mut stack, &mut Some(&mut newt), lit, lyf);
|
||||
let sub = Cell::new_tuple(stack, &[D(0), D(3)]).as_noun();
|
||||
let lyf = Cell::new_tuple(stack, &[D(2), sub, D(0), D(2)]).as_noun();
|
||||
let gat = interpret(stack, &mut Some(newt), lit, lyf);
|
||||
cor = raw_slot(gat, 7);
|
||||
false
|
||||
} else {
|
||||
panic!("partial replay not implemented");
|
||||
}
|
||||
eve = raw_slot(writ, 6).as_direct().unwrap().data();
|
||||
true
|
||||
};
|
||||
|
||||
// do we need to assert something here?
|
||||
// eve = raw_slot(writ, 6).as_direct().unwrap().data();
|
||||
|
||||
let mut lit = raw_slot(writ, 7);
|
||||
loop {
|
||||
if let Ok(cell) = lit.as_cell() {
|
||||
if run {
|
||||
let ovo = cell.head();
|
||||
let res = slam(stack, newt, cor, POKE_AXIS, ovo).as_cell().unwrap();
|
||||
cor = res.tail();
|
||||
}
|
||||
eve += 1;
|
||||
lit = cell.tail();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
newt.play_done(&mut stack, 0);
|
||||
newt.play_done(stack, 0);
|
||||
}
|
||||
tas!(b"work") => {
|
||||
let ovo = raw_slot(writ, 7);
|
||||
let res = slam(&mut stack, &mut newt, cor, POKE_AXIS, ovo)
|
||||
.as_cell()
|
||||
.unwrap();
|
||||
let res = slam(stack, newt, cor, POKE_AXIS, ovo).as_cell().unwrap();
|
||||
let fec = res.head();
|
||||
cor = res.tail();
|
||||
|
||||
eve += 1;
|
||||
|
||||
newt.work_done(&mut stack, eve - 1, 0, fec);
|
||||
newt.work_done(stack, eve, 0, fec);
|
||||
}
|
||||
_ => panic!("got message with unknown tag {:?}", tag),
|
||||
};
|
||||
@ -91,3 +130,58 @@ pub fn slam(stack: &mut NockStack, newt: &mut Newt, cor: Noun, axis: u64, ovo: N
|
||||
let sub = Cell::new_tuple(stack, &[cor, ovo]).as_noun();
|
||||
interpret(stack, &mut Some(newt), sub, fol)
|
||||
}
|
||||
|
||||
fn save(stack: &mut NockStack, snap_path: &PathBuf, eve: u64, cor: Noun) {
|
||||
let state = Cell::new(stack, D(eve), cor).as_noun();
|
||||
let mugged = mug(stack, state).as_noun();
|
||||
let snapshot = Cell::new(stack, mugged, state).as_noun();
|
||||
|
||||
let jammed = jam(stack, snapshot);
|
||||
let f_out = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(snap_path)
|
||||
.unwrap();
|
||||
|
||||
f_out.set_len((jammed.size() << 3) as u64).unwrap();
|
||||
unsafe {
|
||||
let mut out_map = MmapMut::map_mut(&f_out).unwrap();
|
||||
copy_nonoverlapping(
|
||||
jammed.data_pointer() as *mut u8,
|
||||
out_map.as_mut_ptr(),
|
||||
jammed.size() << 3,
|
||||
);
|
||||
out_map.flush().unwrap();
|
||||
};
|
||||
}
|
||||
|
||||
fn load(stack: &mut NockStack, snap_path: &PathBuf) -> io::Result<(u64, Noun)> {
|
||||
let f_in = File::open(snap_path)?;
|
||||
|
||||
let in_len = f_in.metadata().unwrap().len();
|
||||
let jammed = unsafe {
|
||||
let in_map = Mmap::map(&f_in).unwrap();
|
||||
let word_len = (in_len + 7) >> 3;
|
||||
let (mut atom, dest) = IndirectAtom::new_raw_mut(stack, word_len as usize);
|
||||
write_bytes(dest.add(word_len as usize - 1), 0, 8);
|
||||
copy_nonoverlapping(in_map.as_ptr(), dest as *mut u8, in_len as usize);
|
||||
mem::drop(in_map);
|
||||
atom.normalize_as_atom()
|
||||
};
|
||||
|
||||
let snapshot = cue(stack, jammed).as_cell().unwrap();
|
||||
let state = snapshot.tail().as_cell().unwrap();
|
||||
assert!(
|
||||
unsafe {
|
||||
mug(stack, state.as_noun())
|
||||
.as_noun()
|
||||
.raw_equals(snapshot.head())
|
||||
},
|
||||
"snapshot is corrupt"
|
||||
);
|
||||
let eve = state.head().as_direct().unwrap().data();
|
||||
let cor = state.tail();
|
||||
|
||||
Ok((eve, cor))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user