#![doc(
html_logo_url = "https://raw.githubusercontent.com/spacejam/sled/master/art/tree_face_anti-transphobia.png"
)]
#![cfg_attr(test, deny(warnings))]
#![deny(
missing_docs,
future_incompatible,
nonstandard_style,
rust_2018_idioms,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unused_qualifications
)]
#![deny(
clippy::cast_lossless,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_precision_loss,
clippy::cast_sign_loss,
clippy::checked_conversions,
clippy::decimal_literal_representation,
clippy::doc_markdown,
clippy::empty_enum,
clippy::expl_impl_clone_on_copy,
clippy::explicit_into_iter_loop,
clippy::explicit_iter_loop,
clippy::fallible_impl_from,
clippy::filter_map,
clippy::filter_map_next,
clippy::find_map,
clippy::get_unwrap,
clippy::if_not_else,
clippy::inline_always,
clippy::invalid_upcast_comparisons,
clippy::items_after_statements,
clippy::map_flatten,
clippy::match_same_arms,
clippy::maybe_infinite_iter,
clippy::mem_forget,
clippy::multiple_inherent_impl,
clippy::mut_mut,
clippy::needless_borrow,
clippy::needless_continue,
clippy::needless_pass_by_value,
clippy::non_ascii_literal,
clippy::option_map_unwrap_or,
clippy::option_map_unwrap_or_else,
clippy::path_buf_push_overwrite,
clippy::print_stdout,
clippy::pub_enum_variant_names,
clippy::redundant_closure_for_method_calls,
clippy::replace_consts,
clippy::result_map_unwrap_or_else,
clippy::shadow_reuse,
clippy::shadow_same,
clippy::shadow_unrelated,
clippy::single_match_else,
clippy::string_add,
clippy::string_add_assign,
clippy::type_repetition_in_bounds,
clippy::unicode_not_nfc,
clippy::unseparated_literal_suffix,
clippy::used_underscore_binding,
clippy::wildcard_dependencies,
clippy::wrong_pub_self_convention,
)]
#![recursion_limit = "128"]
#[cfg(feature = "failpoints")]
use fail::fail_point;
macro_rules! maybe_fail {
($e:expr) => {
#[cfg(feature = "failpoints")]
fail_point!($e, |_| Err(Error::FailPoint));
};
}
macro_rules! once {
($args:block) => {
static E: AtomicBool = AtomicBool::new(false);
if !E.compare_and_swap(false, true, Relaxed) {
$args;
}
};
}
mod batch;
mod binary_search;
mod config;
mod context;
mod db;
mod dll;
mod fastlock;
mod histogram;
mod iter;
mod ivec;
mod lazy;
mod lru;
mod meta;
mod metrics;
mod node;
mod oneshot;
mod pagecache;
mod prefix;
mod result;
mod serialization;
mod stack;
mod subscription;
mod sys_limits;
mod transaction;
mod tree;
mod vecset;
#[cfg(not(any(windows, target_os = "linux", target_os = "macos")))]
mod threadpool {
use super::OneShot;
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
let (promise_filler, promise) = OneShot::pair();
let task = move || {
let result = (work)();
promise_filler.fill(result);
};
(task)();
return promise;
}
}
#[cfg(any(windows, target_os = "linux", target_os = "macos"))]
mod threadpool;
#[cfg(any(windows, target_os = "linux", target_os = "macos"))]
mod flusher;
#[cfg(feature = "event_log")]
pub mod event_log;
#[cfg(feature = "measure_allocs")]
mod measure_allocs;
#[cfg(feature = "measure_allocs")]
#[global_allocator]
static ALLOCATOR: measure_allocs::TrackingAllocator =
measure_allocs::TrackingAllocator;
const DEFAULT_TREE_ID: &[u8] = b"__sled__default";
#[doc(hidden)]
pub use {
self::{
config::RunningConfig,
lazy::Lazy,
pagecache::{
constants::{
MAX_SPACE_AMPLIFICATION, MINIMUM_ITEMS_PER_SEGMENT,
MSG_HEADER_LEN, SEG_HEADER_LEN,
},
DiskPtr, Log, LogKind, LogOffset, LogRead, Lsn, PageCache, PageId,
SegmentMode,
},
},
crossbeam_epoch::{pin, Atomic, Guard, Owned, Shared},
};
pub use self::{
batch::Batch,
config::Config,
db::Db,
iter::Iter,
ivec::IVec,
result::{Error, Result},
subscription::{Event, Subscriber},
transaction::{
abort, ConflictableTransactionError, ConflictableTransactionResult,
TransactionError, TransactionResult, Transactional, TransactionalTree,
},
tree::{CompareAndSwapError, CompareAndSwapResult, Tree},
};
use {
self::{
binary_search::binary_search_lub,
context::Context,
histogram::Histogram,
lru::Lru,
meta::Meta,
metrics::{clock, measure, Measure, M},
node::{Data, Node},
oneshot::{OneShot, OneShotFiller},
result::CasResult,
serialization::Serialize,
subscription::Subscriptions,
tree::TreeInner,
vecset::VecSet,
},
crossbeam_utils::{Backoff, CachePadded},
log::{debug, error, trace, warn},
pagecache::RecoveryGuard,
parking_lot::{Condvar, Mutex, RwLock},
std::{
collections::BTreeMap,
convert::TryFrom,
fmt::{self, Debug},
io::{Read, Write},
sync::{
atomic::{
AtomicBool, AtomicI64 as AtomicLsn, AtomicU64, AtomicUsize,
Ordering::{Acquire, Relaxed, Release, SeqCst},
},
Arc,
},
},
};
fn crc32(buf: &[u8]) -> u32 {
let mut hasher = crc32fast::Hasher::new();
hasher.update(buf);
hasher.finalize()
}
#[cfg(any(test, feature = "lock_free_delays"))]
mod debug_delay;
#[cfg(any(test, feature = "lock_free_delays"))]
use debug_delay::debug_delay;
#[cfg(not(any(test, feature = "lock_free_delays")))]
const fn debug_delay() {}
#[derive(Clone, Debug, PartialEq)]
pub enum Link {
Set(IVec, IVec),
Del(IVec),
ParentMergeIntention(PageId),
ParentMergeConfirm,
ChildMergeCap,
}
pub(crate) type FastMap8<K, V> = std::collections::HashMap<
K,
V,
std::hash::BuildHasherDefault<fxhash::FxHasher64>,
>;
pub(crate) type FastSet8<V> = std::collections::HashSet<
V,
std::hash::BuildHasherDefault<fxhash::FxHasher64>,
>;
pub type MergeOperator = fn(
key: &[u8],
last_value: Option<&[u8]>,
new_merge: &[u8],
) -> Option<Vec<u8>>;
fn is_sorted<T: PartialOrd>(xs: &[T]) -> bool {
xs.windows(2).all(|pair| pair[0] <= pair[1])
}