use fusee_core::segment::{Batch, Chunk};
use fusee_core::wire::{
DecodeError, DecodeResult, Reader, put_bytes, put_u32, put_u64, put_varint,
};
pub mod req {
pub const HELLO: u8 = 1;
pub const SUBMIT: u8 = 2;
pub const STORE_APPEND: u8 = 3;
pub const STORE_READ: u8 = 4;
pub const CHECKPOINT: u8 = 5;
pub const LOAD_CHECKPOINT: u8 = 6;
pub const LOAD_STORE: u8 = 7;
pub const SEGMENTS: u8 = 8;
pub const READ_SEGMENT: u8 = 9;
pub const SYNC_RECOVERED: u8 = 10;
pub const DISCARD: u8 = 11;
pub const OPEN_LOG: u8 = 12;
pub const PING: u8 = 13;
pub const LIMIT: u8 = 14;
pub const CLIENT_HELLO: u8 = 15;
pub const CALL: u8 = 16;
pub const CALL_REPLY: u8 = 17;
pub const COMPACT_STORE: u8 = 18;
pub const VISIBILITY: u8 = 19;
pub const SEGMENT_EXTENT: u8 = 20;
pub const SEGMENT_RANGE: u8 = 21;
pub const QUORUM_PROBE: u8 = 22;
pub const STORE_APPEND_AT: u8 = 23;
pub const APPEND: u8 = 24;
pub const RECOVER_LOG: u8 = 25;
pub const RELAY: u8 = 26;
pub const RELAY_ACKS: u8 = 27;
pub const DRAIN: u8 = 28;
pub const IDLE: u8 = 29;
}
pub const PAGED_RECOVERY: u32 = 1;
pub const FIRST_SEGMENT_LIMIT: u32 = 2;
pub const STORE_OFFSETS: u32 = 4;
pub const LEASE_LIVENESS: u32 = 8;
pub const EXCLUSIVE_LOG: u32 = 16;
pub const SHARED_LOG: u32 = 32;
pub const SHARD_LEASES: u32 = 64;
pub const MESSAGE_RELAY: u32 = 128;
pub const SHARED_MEMORY: u32 = 256;
pub const INVOKED: u32 = 512;
pub const IDLE_BUSY: u8 = 1;
pub const IDLE_EXPIRED: u8 = 2;
pub const RECOVERY_PAGE: usize = 1 << 20;
pub mod resp {
pub const LEASE: u8 = 101;
pub const OK: u8 = 102;
pub const ERR: u8 = 103;
pub const FLUSHED: u8 = 104;
pub const CHECKPOINTED: u8 = 105;
pub const IO_FAILED: u8 = 106;
pub const CALL: u8 = 107;
pub const LIMITED: u8 = 108;
pub const QUORUM_READY: u8 = 109;
pub const STORE_APPENDED: u8 = 110;
pub const DURABLE: u8 = 111;
pub const GRANT: u8 = 112;
pub const MESSAGES: u8 = 113;
pub const MESSAGE_ACKS: u8 = 114;
}
pub const DURABLE_PINS: u8 = 1;
pub fn encode_section(out: &mut Vec<u8>, b: &Batch) {
put_varint(out, b.first_lsn);
put_varint(out, b.last_lsn);
put_varint(out, u64::from(b.records));
put_bytes(out, &b.section);
}
pub fn decode_section(r: &mut Reader<'_>) -> DecodeResult<Batch> {
let first_lsn = r.varint()?;
let last_lsn = r.varint()?;
let records = r.varint_u32()?;
let section = r.blob()?.to_vec();
if last_lsn < first_lsn || last_lsn - first_lsn + 1 != u64::from(records) {
return Err(DecodeError("section LSNs do not match its record count"));
}
Ok(Batch {
chunks: Vec::new(),
first_lsn,
last_lsn,
records,
bytes: section.len() as u64,
section,
})
}
pub fn encode_sections(out: &mut Vec<u8>, sections: &[fusee::wal::RawSection]) {
for (first, count, bytes) in sections {
put_varint(out, *first);
put_varint(out, u64::from(*count));
put_bytes(out, bytes);
}
}
pub fn decode_sections(
r: &mut Reader<'_>,
count: u32,
out: &mut Vec<fusee::wal::RawSection>,
) -> DecodeResult<()> {
for _ in 0..count {
let first = r.varint()?;
let n = r.varint_u32()?;
if n == 0 {
return Err(DecodeError("empty log section"));
}
out.push((first, n, r.blob()?.to_vec()));
}
Ok(())
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Head {
pub id: u64,
pub shard: u32,
pub epoch: u64,
}
pub fn head(out: &mut Vec<u8>, h: Head) {
put_u64(out, h.id);
put_u32(out, h.shard);
put_u64(out, h.epoch);
}
pub fn read_head(r: &mut Reader<'_>) -> DecodeResult<Head> {
Ok(Head {
id: r.u64()?,
shard: r.u32()?,
epoch: r.u64()?,
})
}
pub fn encode_batch(out: &mut Vec<u8>, b: &Batch) {
put_varint(out, b.first_lsn);
put_varint(out, b.last_lsn);
put_varint(out, u64::from(b.records));
put_varint(out, b.bytes);
put_varint(out, b.chunks.len() as u64);
for c in &b.chunks {
put_varint(out, c.segment);
put_varint(out, c.offset);
out.push(u8::from(c.starts_segment));
put_bytes(out, &c.bytes);
}
}
pub fn decode_batch(r: &mut Reader<'_>) -> DecodeResult<Batch> {
let first_lsn = r.varint()?;
let last_lsn = r.varint()?;
let records = r.varint_u32()?;
let bytes = r.varint()?;
let n = r.varint()?;
if n > 1 << 16 {
return Err(DecodeError("too many chunks"));
}
let mut chunks = Vec::with_capacity(n as usize);
for _ in 0..n {
chunks.push(Chunk {
segment: r.varint()?,
offset: r.varint()?,
starts_segment: r.u8()? != 0,
bytes: r.blob()?.to_vec(),
});
}
Ok(Batch {
chunks,
first_lsn,
last_lsn,
records,
bytes,
section: Vec::new(),
})
}