Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ jobs:
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y capnproto libcapnp-dev libclang-dev build-essential
sudo apt-get install -y capnproto libcapnp-dev libclang-dev build-essential pkg-config zlib1g-dev

- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: nightly
components: clippy
components: clippy, rustfmt
cache: true
cache-key: queueber-3
cache-key: queueber-4

- name: Build
run: cargo build --verbose
Expand All @@ -44,6 +44,9 @@ jobs:
- name: Run Clippy
run: cargo clippy --all-targets --all-features -- -D warnings

- name: Check formatting
run: cargo fmt --all -- --check

- name: "`map_err` is forbidden!"
run: |
! git grep -E '\.map_err\(' src/**/*.rs | grep -v 'Into::'
111 changes: 38 additions & 73 deletions src/dbkeys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ use std::backtrace::Backtrace;

use crate::errors::{Error, Result};

/// Key for items that are available to be polled: `b"available/" + id`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AvailableKey(Vec<u8>);
/// Key for items that are available to be polled: raw `id` bytes.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AvailableKey<'a>(&'a [u8]);

/// Key for items that are currently in progress: `b"in_progress/" + id`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InProgressKey(Vec<u8>);
/// Key for items that are currently in progress: raw `id` bytes.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct InProgressKey<'a>(&'a [u8]);

/// Visibility index key: `b"visibility_index/" + visible_ts_be + b"/" + id`.
/// Visibility index key: `visible_ts_be + b"/" + id`.
///
/// Notes:
/// - Timestamp is encoded as 8-byte big-endian to preserve lexicographic
Expand All @@ -21,83 +21,68 @@ pub struct InProgressKey(Vec<u8>);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VisibilityIndexKey(Vec<u8>);

/// Lease key: `b"leases/" + lease_bytes`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LeaseKey(Vec<u8>);
/// Lease key: raw `lease_bytes`.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct LeaseKey<'a>(&'a [u8]);

/// Lease expiry index key: `b"lease_expiry/" + expiry_ts_be + b"/" + lease_bytes`.
/// Lease expiry index key: `expiry_ts_be + b"/" + lease_bytes`.
///
/// Notes:
/// - Timestamp is encoded as 8-byte big-endian to preserve lexicographic ordering by time.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LeaseExpiryIndexKey(Vec<u8>);

impl AvailableKey {
pub const PREFIX: &'static [u8] = b"available/";

pub fn from_id(id: &[u8]) -> Self {
let mut key = Vec::with_capacity(Self::PREFIX.len() + id.len());
key.extend_from_slice(Self::PREFIX);
key.extend_from_slice(id);
Self(key)
impl<'a> AvailableKey<'a> {
pub fn from_id(id: &'a [u8]) -> Self {
Self(id)
}

/// Returns the underlying database key bytes.
pub fn as_bytes(&self) -> &[u8] {
&self.0
self.0
}

/// Returns the item id suffix contained in this key.
pub fn id_suffix(&self) -> &[u8] {
&self.0[Self::PREFIX.len()..]
self.0
}

/// Returns the item id suffix from a raw `available/` key without allocating.
/// Returns the item id from a raw key without allocating.
///
/// Panics in debug builds if the provided slice does not start with the
/// expected `available/` prefix.
/// With tightened encodings, the key is the id itself.
pub fn id_suffix_from_key_bytes(main_key_bytes: &[u8]) -> &[u8] {
debug_assert!(main_key_bytes.starts_with(Self::PREFIX));
&main_key_bytes[Self::PREFIX.len()..]
main_key_bytes
}
}

impl AsRef<[u8]> for AvailableKey {
impl AsRef<[u8]> for AvailableKey<'_> {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}

impl InProgressKey {
pub const PREFIX: &'static [u8] = b"in_progress/";

pub fn from_id(id: &[u8]) -> Self {
let mut key = Vec::with_capacity(Self::PREFIX.len() + id.len());
key.extend_from_slice(Self::PREFIX);
key.extend_from_slice(id);
Self(key)
impl<'a> InProgressKey<'a> {
pub fn from_id(id: &'a [u8]) -> Self {
Self(id)
}

pub fn as_bytes(&self) -> &[u8] {
&self.0
self.0
}
}

impl AsRef<[u8]> for InProgressKey {
impl AsRef<[u8]> for InProgressKey<'_> {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}

impl VisibilityIndexKey {
pub const PREFIX: &'static [u8] = b"visibility_index/";

/// Build a visibility index key from a visible-at timestamp (secs since epoch) and id.
/// Timestamp is encoded as big-endian to preserve lexicographic ordering.
pub fn from_visible_ts_and_id(visible_ts_secs: u64, id: &[u8]) -> Self {
let ts_be = visible_ts_secs.to_be_bytes();
let mut key = Vec::with_capacity(Self::PREFIX.len() + ts_be.len() + 1 + id.len());
key.extend_from_slice(Self::PREFIX);
let mut key = Vec::with_capacity(ts_be.len() + 1 + id.len());
key.extend_from_slice(&ts_be);
key.extend_from_slice(b"/");
key.extend_from_slice(id);
Expand All @@ -110,28 +95,22 @@ impl VisibilityIndexKey {

/// Parse the visible-at timestamp (secs since epoch) from a visibility index key.
pub fn parse_visible_ts_secs(idx_key: &[u8]) -> Result<u64> {
debug_assert_eq!(
&idx_key[..VisibilityIndexKey::PREFIX.len()],
VisibilityIndexKey::PREFIX
);

let ts_start = Self::PREFIX.len();
let ts_end = ts_start + 8;
let ts_end = 8;
if idx_key.len() < ts_end + 1 {
return Err(Error::AssertionFailed {
msg: format!("malformed key: {:?}", idx_key),
backtrace: Backtrace::capture(),
});
}
let mut ts_be = [0u8; 8];
ts_be.copy_from_slice(&idx_key[ts_start..ts_end]);
ts_be.copy_from_slice(&idx_key[..ts_end]);
Ok(u64::from_be_bytes(ts_be))
}

/// Split a visibility index key into (timestamp_secs, id_slice).
pub fn split_ts_and_id(idx_key: &[u8]) -> Result<(u64, &[u8])> {
let ts = Self::parse_visible_ts_secs(idx_key)?;
let id_start = Self::PREFIX.len() + 8 + 1; // prefix + ts + '/'
let id_start = 8 + 1; // ts + '/'
if id_start > idx_key.len() {
return Err(Error::AssertionFailed {
msg: format!("malformed key: {:?}", idx_key),
Expand All @@ -148,34 +127,26 @@ impl AsRef<[u8]> for VisibilityIndexKey {
}
}

impl LeaseKey {
pub const PREFIX: &'static [u8] = b"leases/";

pub fn from_lease_bytes(lease: &[u8]) -> Self {
let mut key = Vec::with_capacity(Self::PREFIX.len() + lease.len());
key.extend_from_slice(Self::PREFIX);
key.extend_from_slice(lease);
Self(key)
impl<'a> LeaseKey<'a> {
pub fn from_lease_bytes(lease: &'a [u8]) -> Self {
Self(lease)
}

pub fn as_bytes(&self) -> &[u8] {
&self.0
self.0
}
}

impl AsRef<[u8]> for LeaseKey {
impl AsRef<[u8]> for LeaseKey<'_> {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}

impl LeaseExpiryIndexKey {
pub const PREFIX: &'static [u8] = b"lease_expiry/";

pub fn from_expiry_ts_and_lease(expiry_ts_secs: u64, lease: &[u8]) -> Self {
let ts_be = expiry_ts_secs.to_be_bytes();
let mut key = Vec::with_capacity(Self::PREFIX.len() + ts_be.len() + 1 + lease.len());
key.extend_from_slice(Self::PREFIX);
let mut key = Vec::with_capacity(ts_be.len() + 1 + lease.len());
key.extend_from_slice(&ts_be);
key.extend_from_slice(b"/");
key.extend_from_slice(lease);
Expand All @@ -187,27 +158,21 @@ impl LeaseExpiryIndexKey {
}

pub fn parse_expiry_ts_secs(idx_key: &[u8]) -> Result<u64> {
let ts_start = Self::PREFIX.len();
let ts_end = ts_start + 8;
let ts_end = 8;
if idx_key.len() < ts_end + 1 {
return Err(Error::assertion_failed(&format!(
"malformed key: {:?}",
idx_key
)));
}
let mut ts_be = [0u8; 8];
ts_be.copy_from_slice(&idx_key[ts_start..ts_end]);
ts_be.copy_from_slice(&idx_key[..ts_end]);
Ok(u64::from_be_bytes(ts_be))
}

pub fn split_ts_and_lease(idx_key: &[u8]) -> Result<(u64, &[u8])> {
debug_assert_eq!(
&idx_key[..LeaseExpiryIndexKey::PREFIX.len()],
LeaseExpiryIndexKey::PREFIX
);

let ts = Self::parse_expiry_ts_secs(idx_key)?;
let lease_start = Self::PREFIX.len() + 8 + 1; // prefix + ts + '/'
let lease_start = 8 + 1; // ts + '/'
if lease_start > idx_key.len() {
return Err(Error::assertion_failed(&format!(
"malformed key: {:?}",
Expand Down
Loading