summaryrefslogtreecommitdiff
path: root/ext/kv/interface.rs
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2023-10-31 12:13:57 +0100
committerGitHub <noreply@github.com>2023-10-31 11:13:57 +0000
commit2d9298f5f5550c21ba218ff7095aa9afe80c7e02 (patch)
tree6daee1cc6007745097e176c7367b697e58632baf /ext/kv/interface.rs
parent092555c611ebab87ad570b4dcb73d54288dccdd9 (diff)
chore: update ext/kv to use denokv_* crates (#20986)
This commit updates the ext/kv module to use the denokv_* crates for the protocol and the sqlite backend. This also fixes a couple of bugs in the sqlite backend, and updates versionstamps to be updated less linearly.
Diffstat (limited to 'ext/kv/interface.rs')
-rw-r--r--ext/kv/interface.rs315
1 files changed, 1 insertions, 314 deletions
diff --git a/ext/kv/interface.rs b/ext/kv/interface.rs
index 1acf3ce16..d7aa68368 100644
--- a/ext/kv/interface.rs
+++ b/ext/kv/interface.rs
@@ -1,16 +1,12 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use std::cell::RefCell;
-use std::cmp::Ordering;
-use std::num::NonZeroU32;
use std::rc::Rc;
use async_trait::async_trait;
use deno_core::error::AnyError;
use deno_core::OpState;
-use num_bigint::BigInt;
-
-use crate::codec::canonicalize_f64;
+use denokv_proto::Database;
#[async_trait(?Send)]
pub trait DatabaseHandler {
@@ -22,312 +18,3 @@ pub trait DatabaseHandler {
path: Option<String>,
) -> Result<Self::DB, AnyError>;
}
-
-#[async_trait(?Send)]
-pub trait Database {
- type QMH: QueueMessageHandle + 'static;
-
- async fn snapshot_read(
- &self,
- state: Rc<RefCell<OpState>>,
- requests: Vec<ReadRange>,
- options: SnapshotReadOptions,
- ) -> Result<Vec<ReadRangeOutput>, AnyError>;
-
- async fn atomic_write(
- &self,
- state: Rc<RefCell<OpState>>,
- write: AtomicWrite,
- ) -> Result<Option<CommitResult>, AnyError>;
-
- async fn dequeue_next_message(
- &self,
- state: Rc<RefCell<OpState>>,
- ) -> Result<Option<Self::QMH>, AnyError>;
-
- fn close(&self);
-}
-
-#[async_trait(?Send)]
-pub trait QueueMessageHandle {
- async fn take_payload(&mut self) -> Result<Vec<u8>, AnyError>;
- async fn finish(&self, success: bool) -> Result<(), AnyError>;
-}
-
-/// Options for a snapshot read.
-pub struct SnapshotReadOptions {
- pub consistency: Consistency,
-}
-
-/// The consistency of a read.
-#[derive(Eq, PartialEq, Copy, Clone, Debug)]
-pub enum Consistency {
- Strong,
- Eventual,
-}
-
-/// A key is for a KV pair. It is a vector of KeyParts.
-///
-/// The ordering of the keys is defined by the ordering of the KeyParts. The
-/// first KeyPart is the most significant, and the last KeyPart is the least
-/// significant.
-#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
-pub struct Key(pub Vec<KeyPart>);
-
-/// A key part is single item in a key. It can be a boolean, a double float, a
-/// variable precision signed integer, a UTF-8 string, or an arbitrary byte
-/// array.
-///
-/// The ordering of a KeyPart is dependent on the type of the KeyPart.
-///
-/// Between different types, the ordering is as follows: arbitrary byte array <
-/// UTF-8 string < variable precision signed integer < double float < false < true.
-///
-/// Within a type, the ordering is as follows:
-/// - For a **boolean**, false is less than true.
-/// - For a **double float**, the ordering must follow -NaN < -Infinity < -100.0 < -1.0 < -0.5 < -0.0 < 0.0 < 0.5 < 1.0 < 100.0 < Infinity < NaN.
-/// - For a **variable precision signed integer**, the ordering must follow mathematical ordering.
-/// - For a **UTF-8 string**, the ordering must follow the UTF-8 byte ordering.
-/// - For an **arbitrary byte array**, the ordering must follow the byte ordering.
-///
-/// This means that the key part `1.0` is less than the key part `2.0`, but is
-/// greater than the key part `0n`, because `1.0` is a double float and `0n`
-/// is a variable precision signed integer, and the ordering types obviously has
-/// precedence over the ordering within a type.
-#[derive(Clone, Debug)]
-pub enum KeyPart {
- Bytes(Vec<u8>),
- String(String),
- Int(BigInt),
- Float(f64),
- False,
- True,
-}
-
-impl KeyPart {
- fn tag_ordering(&self) -> u8 {
- match self {
- KeyPart::Bytes(_) => 0,
- KeyPart::String(_) => 1,
- KeyPart::Int(_) => 2,
- KeyPart::Float(_) => 3,
- KeyPart::False => 4,
- KeyPart::True => 5,
- }
- }
-}
-
-impl Eq for KeyPart {}
-
-impl PartialEq for KeyPart {
- fn eq(&self, other: &Self) -> bool {
- self.cmp(other) == Ordering::Equal
- }
-}
-
-impl Ord for KeyPart {
- fn cmp(&self, other: &Self) -> Ordering {
- match (self, other) {
- (KeyPart::Bytes(b1), KeyPart::Bytes(b2)) => b1.cmp(b2),
- (KeyPart::String(s1), KeyPart::String(s2)) => {
- s1.as_bytes().cmp(s2.as_bytes())
- }
- (KeyPart::Int(i1), KeyPart::Int(i2)) => i1.cmp(i2),
- (KeyPart::Float(f1), KeyPart::Float(f2)) => {
- canonicalize_f64(*f1).total_cmp(&canonicalize_f64(*f2))
- }
- _ => self.tag_ordering().cmp(&other.tag_ordering()),
- }
- }
-}
-
-impl PartialOrd for KeyPart {
- fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
- Some(self.cmp(other))
- }
-}
-
-/// A request to read a range of keys from the database. If `end` is `None`,
-/// then the range is from `start` shall also be used as the end of the range.
-///
-/// The range is inclusive of the start and exclusive of the end. The start may
-/// not be greater than the end.
-///
-/// The range is limited to `limit` number of entries.
-pub struct ReadRange {
- pub start: Vec<u8>,
- pub end: Vec<u8>,
- pub limit: NonZeroU32,
- pub reverse: bool,
-}
-
-/// A response to a `ReadRange` request.
-pub struct ReadRangeOutput {
- pub entries: Vec<KvEntry>,
-}
-
-/// A versionstamp is a 10 byte array that is used to represent the version of
-/// a key in the database.
-type Versionstamp = [u8; 10];
-
-/// A key-value entry with a versionstamp.
-pub struct KvEntry {
- pub key: Vec<u8>,
- pub value: Value,
- pub versionstamp: Versionstamp,
-}
-
-/// A serialized value for a KV pair as stored in the database. All values
-/// **can** be serialized into the V8 representation, but not all values are.
-///
-/// The V8 representation is an opaque byte array that is only meaningful to
-/// the V8 engine. It is guaranteed to be backwards compatible. Because this
-/// representation is opaque, it is not possible to inspect or modify the value
-/// without deserializing it.
-///
-/// The inability to inspect or modify the value without deserializing it means
-/// that these values can not be quickly modified when performing atomic
-/// read-modify-write operations on the database (because the database may not
-/// have the ability to deserialize the V8 value into a modifiable value).
-///
-/// Because of this constraint, there are more specialized representations for
-/// certain types of values that can be used in atomic read-modify-write
-/// operations. These specialized representations are:
-///
-/// - **Bytes**: an arbitrary byte array.
-/// - **U64**: a 64-bit unsigned integer.
-pub enum Value {
- V8(Vec<u8>),
- Bytes(Vec<u8>),
- U64(u64),
-}
-
-/// A request to perform an atomic check-modify-write operation on the database.
-///
-/// The operation is performed atomically, meaning that the operation will
-/// either succeed or fail. If the operation fails, then the database will be
-/// left in the same state as before the operation was attempted. If the
-/// operation succeeds, then the database will be left in a new state.
-///
-/// The operation is performed by first checking the database for the current
-/// state of the keys, defined by the `checks` field. If the current state of
-/// the keys does not match the expected state, then the operation fails. If
-/// the current state of the keys matches the expected state, then the
-/// mutations are applied to the database.
-///
-/// All checks and mutations are performed atomically.
-///
-/// The mutations are performed in the order that they are specified in the
-/// `mutations` field. The order of checks is not specified, and is also not
-/// important because this ordering is un-observable.
-pub struct AtomicWrite {
- pub checks: Vec<KvCheck>,
- pub mutations: Vec<KvMutation>,
- pub enqueues: Vec<Enqueue>,
-}
-
-/// A request to perform a check on a key in the database. The check is not
-/// performed on the value of the key, but rather on the versionstamp of the
-/// key.
-pub struct KvCheck {
- pub key: Vec<u8>,
- pub versionstamp: Option<Versionstamp>,
-}
-
-/// A request to perform a mutation on a key in the database. The mutation is
-/// performed on the value of the key.
-///
-/// The type of mutation is specified by the `kind` field. The action performed
-/// by each mutation kind is specified in the docs for [MutationKind].
-pub struct KvMutation {
- pub key: Vec<u8>,
- pub kind: MutationKind,
- pub expire_at: Option<u64>,
-}
-
-/// A request to enqueue a message to the database. This message is delivered
-/// to a listener of the queue at least once.
-///
-/// ## Retry
-///
-/// When the delivery of a message fails, it is retried for a finite number
-/// of times. Each retry happens after a backoff period. The backoff periods
-/// are specified by the `backoff_schedule` field in milliseconds. If
-/// unspecified, the default backoff schedule of the platform (CLI or Deploy)
-/// is used.
-///
-/// If all retry attempts failed, the message is written to the KV under all
-/// keys specified in `keys_if_undelivered`.
-pub struct Enqueue {
- pub payload: Vec<u8>,
- pub delay_ms: u64,
- pub keys_if_undelivered: Vec<Vec<u8>>,
- pub backoff_schedule: Option<Vec<u32>>,
-}
-
-/// The type of mutation to perform on a key in the database.
-///
-/// ## Set
-///
-/// The set mutation sets the value of the key to the specified value. It
-/// discards the previous value of the key, if any.
-///
-/// This operand supports all [Value] types.
-///
-/// ## Delete
-///
-/// The delete mutation deletes the value of the key.
-///
-/// ## Sum
-///
-/// The sum mutation adds the specified value to the existing value of the key.
-///
-/// This operand supports only value types [Value::U64]. The existing value in
-/// the database must match the type of the value specified in the mutation. If
-/// the key does not exist in the database, then the value specified in the
-/// mutation is used as the new value of the key.
-///
-/// ## Min
-///
-/// The min mutation sets the value of the key to the minimum of the existing
-/// value of the key and the specified value.
-///
-/// This operand supports only value types [Value::U64]. The existing value in
-/// the database must match the type of the value specified in the mutation. If
-/// the key does not exist in the database, then the value specified in the
-/// mutation is used as the new value of the key.
-///
-/// ## Max
-///
-/// The max mutation sets the value of the key to the maximum of the existing
-/// value of the key and the specified value.
-///
-/// This operand supports only value types [Value::U64]. The existing value in
-/// the database must match the type of the value specified in the mutation. If
-/// the key does not exist in the database, then the value specified in the
-/// mutation is used as the new value of the key.
-pub enum MutationKind {
- Set(Value),
- Delete,
- Sum(Value),
- Min(Value),
- Max(Value),
-}
-
-impl MutationKind {
- pub fn value(&self) -> Option<&Value> {
- match self {
- MutationKind::Set(value) => Some(value),
- MutationKind::Sum(value) => Some(value),
- MutationKind::Min(value) => Some(value),
- MutationKind::Max(value) => Some(value),
- MutationKind::Delete => None,
- }
- }
-}
-
-/// The result of a successful commit of an atomic write operation.
-pub struct CommitResult {
- /// The new versionstamp of the data that was committed.
- pub versionstamp: Versionstamp,
-}