replace BTreeMap by BTreeSet and remove id form Entry (#123)

This commit is contained in:
Mahdi
2023-05-16 19:41:54 +03:30
committed by GitHub
parent e1840ec9ef
commit df98a941ac
2 changed files with 12 additions and 27 deletions

View File

@@ -113,7 +113,6 @@ impl Client {
pub async fn ping(&mut self, msg: Option<Bytes>) -> crate::Result<Bytes> {
let frame = Ping::new(msg).into_frame();
debug!(request = ?frame);
self.connection.write_frame(&frame).await?;
match self.read_response().await? {

View File

@@ -2,7 +2,7 @@ use tokio::sync::{broadcast, Notify};
use tokio::time::{self, Duration, Instant};
use bytes::Bytes;
use std::collections::{BTreeMap, HashMap};
use std::collections::{BTreeSet, HashMap};
use std::sync::{Arc, Mutex};
use tracing::debug;
@@ -69,19 +69,15 @@ struct State {
/// Tracks key TTLs.
///
/// A `BTreeMap` is used to maintain expirations sorted by when they expire.
/// A `BTreeSet` is used to maintain expirations sorted by when they expire.
/// This allows the background task to iterate this map to find the value
/// expiring next.
///
/// While highly unlikely, it is possible for more than one expiration to be
/// created for the same instant. Because of this, the `Instant` is
/// insufficient for the key. A unique expiration identifier (`u64`) is used
/// to break these ties.
expirations: BTreeMap<(Instant, u64), String>,
/// Identifier to use for the next expiration. Each expiration is associated
/// with a unique identifier. See above for why.
next_id: u64,
/// insufficient for the key. A unique key (`String`) is used to
/// break these ties.
expirations: BTreeSet<(Instant, String)>,
/// True when the Db instance is shutting down. This happens when all `Db`
/// values drop. Setting this to `true` signals to the background task to
@@ -92,9 +88,6 @@ struct State {
/// Entry in the key-value store
#[derive(Debug)]
struct Entry {
/// Uniquely identifies this entry.
id: u64,
/// Stored data
data: Bytes,
@@ -132,8 +125,7 @@ impl Db {
state: Mutex::new(State {
entries: HashMap::new(),
pub_sub: HashMap::new(),
expirations: BTreeMap::new(),
next_id: 0,
expirations: BTreeSet::new(),
shutdown: false,
}),
background_task: Notify::new(),
@@ -166,11 +158,6 @@ impl Db {
pub(crate) fn set(&self, key: String, value: Bytes, expire: Option<Duration>) {
let mut state = self.shared.state.lock().unwrap();
// Get and increment the next insertion ID. Guarded by the lock, this
// ensures a unique identifier is associated with each `set` operation.
let id = state.next_id;
state.next_id += 1;
// If this `set` becomes the key that expires **next**, the background
// task needs to be notified so it can update its state.
//
@@ -191,15 +178,14 @@ impl Db {
.unwrap_or(true);
// Track the expiration.
state.expirations.insert((when, id), key.clone());
state.expirations.insert((when, key.clone()));
when
});
// Insert the entry into the `HashMap`.
let prev = state.entries.insert(
key,
key.clone(),
Entry {
id,
data: value,
expires_at,
},
@@ -211,7 +197,7 @@ impl Db {
if let Some(prev) = prev {
if let Some(when) = prev.expires_at {
// clear expiration
state.expirations.remove(&(when, prev.id));
state.expirations.remove(&(when, key));
}
}
@@ -315,7 +301,7 @@ impl Shared {
// Find all keys scheduled to expire **before** now.
let now = Instant::now();
while let Some((&(when, id), key)) = state.expirations.iter().next() {
while let Some(&(when, ref key)) = state.expirations.iter().next() {
if when > now {
// Done purging, `when` is the instant at which the next key
// expires. The worker task will wait until this instant.
@@ -324,7 +310,7 @@ impl Shared {
// The key expired, remove it
state.entries.remove(key);
state.expirations.remove(&(when, id));
state.expirations.remove(&(when, key.clone()));
}
None
@@ -342,7 +328,7 @@ impl Shared {
impl State {
fn next_expiration(&self) -> Option<Instant> {
self.expirations
.keys()
.iter()
.next()
.map(|expiration| expiration.0)
}