#[cfg(test)]
mod tests;
use crate::error::{Error, Result};
use crate::varint::{get_u32, get_u64, put_u32, put_u64};
const VERSION: u8 = 1;
const FLUSHED_SEQUENCE: u8 = 1;
const NEXT_FILE: u8 = 2;
const ADDED_TABLE: u8 = 3;
const REMOVED_TABLE: u8 = 4;
const ADDED_KEYSPACE: u8 = 5;
const DROPPED_KEYSPACE: u8 = 6;
const NEXT_KEYSPACE: u8 = 7;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct KeyspaceRecord {
pub id: u32,
pub name: String,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct TableMeta {
pub keyspace: u32,
pub level: u8,
pub id: u64,
pub size: u64,
pub smallest: Vec<u8>,
pub largest: Vec<u8>,
pub min_sequence: u64,
pub max_sequence: u64,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct TableRef {
pub keyspace: u32,
pub level: u8,
pub id: u64,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ManifestEdit {
pub flushed_sequence: Option<u64>,
pub next_file: Option<u64>,
pub added: Vec<TableMeta>,
pub removed: Vec<TableRef>,
pub added_keyspaces: Vec<KeyspaceRecord>,
pub dropped_keyspaces: Vec<u32>,
pub next_keyspace: Option<u32>,
}
impl ManifestEdit {
pub fn encode(&self, out: &mut Vec<u8>) {
out.push(VERSION);
if let Some(sequence) = self.flushed_sequence {
out.push(FLUSHED_SEQUENCE);
put_u64(out, sequence);
}
if let Some(file) = self.next_file {
out.push(NEXT_FILE);
put_u64(out, file);
}
for table in &self.added {
out.push(ADDED_TABLE);
put_u32(out, table.keyspace);
out.push(table.level);
for value in [table.id, table.size, table.min_sequence, table.max_sequence] {
put_u64(out, value);
}
put_key(out, &table.smallest);
put_key(out, &table.largest);
}
for table in &self.removed {
out.push(REMOVED_TABLE);
put_u32(out, table.keyspace);
out.push(table.level);
put_u64(out, table.id);
}
for keyspace in &self.added_keyspaces {
out.push(ADDED_KEYSPACE);
put_u32(out, keyspace.id);
put_key(out, keyspace.name.as_bytes());
}
for id in &self.dropped_keyspaces {
out.push(DROPPED_KEYSPACE);
put_u32(out, *id);
}
if let Some(id) = self.next_keyspace {
out.push(NEXT_KEYSPACE);
put_u32(out, id);
}
}
pub fn decode(bytes: &[u8]) -> Result<Self> {
let mut input = Input { bytes };
let version = input.byte("manifest edit version")?;
if version != VERSION {
return Err(Error::UnsupportedVersion {
what: "manifest edit",
version,
});
}
let mut edit = Self::default();
while !input.bytes.is_empty() {
match input.byte("manifest edit field")? {
FLUSHED_SEQUENCE => set_once(&mut edit.flushed_sequence, input.u64()?)?,
NEXT_FILE => set_once(&mut edit.next_file, input.u64()?)?,
ADDED_TABLE => edit.added.push(TableMeta {
keyspace: input.u32()?,
level: input.byte("manifest edit level")?,
id: input.u64()?,
size: input.u64()?,
min_sequence: input.u64()?,
max_sequence: input.u64()?,
smallest: input.key()?,
largest: input.key()?,
}),
REMOVED_TABLE => edit.removed.push(TableRef {
keyspace: input.u32()?,
level: input.byte("manifest edit level")?,
id: input.u64()?,
}),
ADDED_KEYSPACE => edit.added_keyspaces.push(KeyspaceRecord {
id: input.u32()?,
name: String::from_utf8(input.key()?).map_err(|_| Error::Malformed {
what: "manifest edit",
reason: "a keyspace name is not UTF-8",
})?,
}),
DROPPED_KEYSPACE => edit.dropped_keyspaces.push(input.u32()?),
NEXT_KEYSPACE => set_once(&mut edit.next_keyspace, input.u32()?)?,
_ => {
return Err(Error::Malformed {
what: "manifest edit",
reason: "unknown field tag",
});
}
}
}
Ok(edit)
}
}
fn put_key(out: &mut Vec<u8>, key: &[u8]) {
put_u32(out, u32::try_from(key.len()).unwrap_or(u32::MAX));
out.extend_from_slice(key);
}
fn set_once<T>(slot: &mut Option<T>, value: T) -> Result<()> {
if slot.replace(value).is_some() {
return Err(Error::Malformed {
what: "manifest edit",
reason: "a field given twice",
});
}
Ok(())
}
struct Input<'a> {
bytes: &'a [u8],
}
impl<'a> Input<'a> {
fn byte(&mut self, what: &'static str) -> Result<u8> {
let (&first, rest) = self.bytes.split_first().ok_or(Error::Truncated {
what,
needed: 1,
available: 0,
})?;
self.bytes = rest;
Ok(first)
}
fn u32(&mut self) -> Result<u32> {
let (value, used) = get_u32(self.bytes).ok_or_else(|| self.bad_varint(5))?;
self.advance(used);
Ok(value)
}
fn u64(&mut self) -> Result<u64> {
let (value, used) = get_u64(self.bytes).ok_or_else(|| self.bad_varint(10))?;
self.advance(used);
Ok(value)
}
fn key(&mut self) -> Result<Vec<u8>> {
let len = usize::try_from(self.u32()?).unwrap_or(usize::MAX);
let (key, rest) = self
.bytes
.split_at_checked(len)
.ok_or_else(|| Error::Truncated {
what: "manifest edit key",
needed: u64::try_from(len).unwrap_or(u64::MAX),
available: u64::try_from(self.bytes.len()).unwrap_or(u64::MAX),
})?;
self.bytes = rest;
Ok(key.to_vec())
}
fn advance(&mut self, used: usize) {
self.bytes = self.bytes.get(used..).unwrap_or_default();
}
fn bad_varint(&self, max_bytes: usize) -> Error {
if self.bytes.len() >= max_bytes {
return Error::Malformed {
what: "manifest edit integer",
reason: "longer than its type",
};
}
Error::Truncated {
what: "manifest edit integer",
needed: 1,
available: u64::try_from(self.bytes.len()).unwrap_or(u64::MAX),
}
}
}