From b5555dddd13e46d880ae1f71312aea6dda5d1bb3 Mon Sep 17 00:00:00 2001 From: Tatsuya Kawano Date: Thu, 3 Feb 2022 18:06:48 +0800 Subject: [PATCH 1/3] Embed `CacheRegion` value into a `TagNonNull` pointer - Add tagptr crate to the dependencies. - Remove `region: CacheRegion` field from `DeqNode`. - Change the pointer type used in `access_order_q_node` field of `DeqNodes` from `NonNull>` to `TagNonNull, 2>`, and embed `CacheRegion` value into the 2-bit tag space in the `TagNonNull` pointer. - Update the methods in `Deques` to handle the `TagNonNull` pointers. --- .vscode/settings.json | 1 + Cargo.toml | 1 + src/common.rs | 35 ++++++++++++++ src/common/deque.rs | 54 ++++++++++----------- src/sync.rs | 3 +- src/sync/base_cache.rs | 11 +++-- src/sync/deques.rs | 103 +++++++++++++++++++---------------------- src/unsync.rs | 3 +- src/unsync/cache.rs | 3 +- src/unsync/deques.rs | 81 +++++++++++++++++--------------- 10 files changed, 166 insertions(+), 129 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 74aab354..d10b8d53 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -38,6 +38,7 @@ "semver", "smallvec", "structs", + "tagptr", "Tatsuya", "thiserror", "toolchain", diff --git a/Cargo.toml b/Cargo.toml index fdbd57e7..c6b757e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ parking_lot = "0.12" quanta = "0.9.3" scheduled-thread-pool = "0.2" smallvec = "1.8" +tagptr = "0.2" thiserror = "1.0" triomphe = "0.1" uuid = { version = "0.8", features = ["v4"] } diff --git a/src/common.rs b/src/common.rs index e370a31f..ffb0b62d 100644 --- a/src/common.rs +++ b/src/common.rs @@ -17,6 +17,41 @@ pub(crate) mod atomic_time; pub(crate) mod time; +// Note: `CacheRegion` cannot have more than four enum variants. This is because +// `crate::{sync,unsync}::DeqNodes` uses a `tagptr::TagNonNull, 2>` +// pointer, where the 2-bit tag is `CacheRegion`. +#[derive(Clone, Copy, Debug, Eq)] +pub(crate) enum CacheRegion { + Window = 0, + MainProbation = 1, + MainProtected = 2, + Other = 3, +} + +impl From for CacheRegion { + fn from(n: usize) -> Self { + match n { + 0 => Self::Window, + 1 => Self::MainProbation, + 2 => Self::MainProtected, + 3 => Self::Other, + _ => panic!("No such CacheRegion variant for {}", n), + } + } +} + +impl PartialEq for CacheRegion { + fn eq(&self, other: &Self) -> bool { + core::mem::discriminant(self) == core::mem::discriminant(other) + } +} + +impl PartialEq for CacheRegion { + fn eq(&self, other: &usize) -> bool { + *self as usize == *other + } +} + // Ensures the value fits in a range of `128u32..=u32::MAX`. pub(crate) fn sketch_capacity(max_capacity: u64) -> u32 { max_capacity.try_into().unwrap_or(u32::MAX).max(128) diff --git a/src/common/deque.rs b/src/common/deque.rs index e3269e64..321c7672 100644 --- a/src/common/deque.rs +++ b/src/common/deque.rs @@ -14,17 +14,15 @@ use std::{marker::PhantomData, ptr::NonNull}; -#[derive(Clone, Debug, Eq, PartialEq)] -pub(crate) enum CacheRegion { - Window, - MainProbation, - MainProtected, - WriteOrder, -} +use super::CacheRegion; +// `crate::{sync,unsync}::DeqNodes` uses a `tagptr::TagNonNull, 2>` +// pointer. To reserve the space for the 2-bit tag, use 4 bytes as the *minimum* +// alignment. +// https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers +#[repr(align(4))] #[derive(PartialEq, Eq)] pub(crate) struct DeqNode { - pub(crate) region: CacheRegion, next: Option>>, prev: Option>>, pub(crate) element: T, @@ -33,7 +31,6 @@ pub(crate) struct DeqNode { impl std::fmt::Debug for DeqNode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("DeqNode") - .field("region", &self.region) .field("next", &self.next) .field("prev", &self.prev) .finish() @@ -41,12 +38,11 @@ impl std::fmt::Debug for DeqNode { } impl DeqNode { - pub(crate) fn new(region: CacheRegion, element: T) -> Self { + pub(crate) fn new(element: T) -> Self { #[cfg(feature = "unstable-debug-counters")] crate::sync::debug_counters::InternalGlobalDebugCounters::deq_node_created(); Self { - region, next: None, prev: None, element, @@ -113,8 +109,8 @@ impl Deque { } } - pub(crate) fn region(&self) -> &CacheRegion { - &self.region + pub(crate) fn region(&self) -> CacheRegion { + self.region } pub(crate) fn len(&self) -> usize { @@ -122,7 +118,7 @@ impl Deque { } pub(crate) fn contains(&self, node: &DeqNode) -> bool { - self.region == node.region && (node.prev.is_some() || self.is_head(node)) + node.prev.is_some() || self.is_head(node) } pub(crate) fn peek_front(&self) -> Option<&DeqNode> { @@ -229,8 +225,6 @@ impl Deque { /// /// Panics: pub(crate) unsafe fn unlink(&mut self, mut node: NonNull>) { - assert_eq!(self.region, node.as_ref().region); - if self.is_at_cursor(node.as_ref()) { self.advance_cursor(); } @@ -348,7 +342,7 @@ mod tests { assert!(deque.peek_back().is_none()); // push_back(node1) - let node1 = DeqNode::new(MainProbation, "a".to_string()); + let node1 = DeqNode::new("a".to_string()); assert!(!deque.contains(&node1)); let node1 = Box::new(node1); let node1_ptr = deque.push_back(node1); @@ -384,7 +378,7 @@ mod tests { assert!(tail_a.next.is_none()); // push_back(node2) - let node2 = DeqNode::new(MainProbation, "b".to_string()); + let node2 = DeqNode::new("b".to_string()); assert!(!deque.contains(&node2)); let node2_ptr = deque.push_back(Box::new(node2)); assert_eq!(deque.len(), 2); @@ -459,7 +453,7 @@ mod tests { assert!(tail_c.next.is_none()); // push_back(node3) - let node3 = DeqNode::new(MainProbation, "c".to_string()); + let node3 = DeqNode::new("c".to_string()); assert!(!deque.contains(&node3)); let node3_ptr = deque.push_back(Box::new(node3)); assert_eq!(deque.len(), 3); @@ -601,11 +595,11 @@ mod tests { let mut deque: Deque = Deque::new(MainProbation); assert!((&mut deque).next().is_none()); - let node1 = DeqNode::new(MainProbation, "a".into()); + let node1 = DeqNode::new("a".into()); deque.push_back(Box::new(node1)); - let node2 = DeqNode::new(MainProbation, "b".into()); + let node2 = DeqNode::new("b".into()); let node2_ptr = deque.push_back(Box::new(node2)); - let node3 = DeqNode::new(MainProbation, "c".into()); + let node3 = DeqNode::new("c".into()); let node3_ptr = deque.push_back(Box::new(node3)); // ------------------------------------------------------- @@ -653,7 +647,7 @@ mod tests { // ------------------------------------------------------- // Try pop_front during iteration. - let node3 = DeqNode::new(MainProbation, "c".into()); + let node3 = DeqNode::new("c".into()); deque.push_back(Box::new(node3)); assert_eq!((&mut deque).next(), Some(&"a".into())); @@ -675,11 +669,11 @@ mod tests { fn next_node() { let mut deque: Deque = Deque::new(MainProbation); - let node1 = DeqNode::new(MainProbation, "a".into()); + let node1 = DeqNode::new("a".into()); deque.push_back(Box::new(node1)); - let node2 = DeqNode::new(MainProbation, "b".into()); + let node2 = DeqNode::new("b".into()); let node2_ptr = deque.push_back(Box::new(node2)); - let node3 = DeqNode::new(MainProbation, "c".into()); + let node3 = DeqNode::new("c".into()); let node3_ptr = deque.push_back(Box::new(node3)); // ------------------------------------------------------- @@ -731,10 +725,10 @@ mod tests { let mut deque: Deque = Deque::new(MainProbation); let dropped = Rc::new(RefCell::new(Vec::default())); - let node1 = DeqNode::new(MainProbation, X(1, Rc::clone(&dropped))); - let node2 = DeqNode::new(MainProbation, X(2, Rc::clone(&dropped))); - let node3 = DeqNode::new(MainProbation, X(3, Rc::clone(&dropped))); - let node4 = DeqNode::new(MainProbation, X(4, Rc::clone(&dropped))); + let node1 = DeqNode::new(X(1, Rc::clone(&dropped))); + let node2 = DeqNode::new(X(2, Rc::clone(&dropped))); + let node3 = DeqNode::new(X(3, Rc::clone(&dropped))); + let node4 = DeqNode::new(X(4, Rc::clone(&dropped))); deque.push_back(Box::new(node1)); deque.push_back(Box::new(node2)); deque.push_back(Box::new(node3)); diff --git a/src/sync.rs b/src/sync.rs index 3e098b7c..f84de252 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -4,6 +4,7 @@ use crate::common::{deque::DeqNode, time::Instant}; use parking_lot::Mutex; use std::{ptr::NonNull, sync::Arc}; +use tagptr::TagNonNull; use triomphe::Arc as TrioArc; pub(crate) mod base_cache; @@ -172,7 +173,7 @@ impl AccessTime for DeqNode> { } // DeqNode for an access order queue. -type KeyDeqNodeAo = NonNull>>; +type KeyDeqNodeAo = TagNonNull>, 2>; // DeqNode for the write order queue. type KeyDeqNodeWo = NonNull>>; diff --git a/src/sync/base_cache.rs b/src/sync/base_cache.rs index 3cae12da..486c6ce7 100644 --- a/src/sync/base_cache.rs +++ b/src/sync/base_cache.rs @@ -14,9 +14,10 @@ use crate::{ common::{ self, atomic_time::AtomicInstant, - deque::{CacheRegion, DeqNode, Deque}, + deque::{DeqNode, Deque}, frequency_sketch::FrequencySketch, time::{CheckedTimeOps, Clock, Instant}, + CacheRegion, }, PredicateError, }; @@ -1097,10 +1098,12 @@ where if entry.is_admitted() { entry.set_is_admitted(false); counters.saturating_sub(1, entry.policy_weight()); + // The following two unlink_* functions will unset the deq nodes. deqs.unlink_ao(&entry); Deques::unlink_wo(&mut deqs.write_order, &entry); + } else { + entry.unset_q_nodes(); } - entry.unset_q_nodes(); } fn handle_remove_with_deques( @@ -1113,10 +1116,12 @@ where if entry.is_admitted() { entry.set_is_admitted(false); counters.saturating_sub(1, entry.policy_weight()); + // The following two unlink_* functions will unset the deq nodes. Deques::unlink_ao_from_deque(ao_deq_name, ao_deq, &entry); Deques::unlink_wo(wo_deq, &entry); + } else { + entry.unset_q_nodes(); } - entry.unset_q_nodes(); } fn evict_expired( diff --git a/src/sync/deques.rs b/src/sync/deques.rs index 3c8a6749..3fdd74db 100644 --- a/src/sync/deques.rs +++ b/src/sync/deques.rs @@ -1,7 +1,11 @@ use super::{KeyDate, KeyHashDate, ValueEntry}; -use crate::common::deque::{CacheRegion, DeqNode, Deque}; +use crate::common::{ + deque::{DeqNode, Deque}, + CacheRegion, +}; use std::ptr::NonNull; +use tagptr::TagNonNull; use triomphe::Arc as TrioArc; pub(crate) struct Deques { pub(crate) window: Deque>, // Not used yet. @@ -24,7 +28,7 @@ impl Default for Deques { window: Deque::new(CacheRegion::Window), probation: Deque::new(CacheRegion::MainProbation), protected: Deque::new(CacheRegion::MainProtected), - write_order: Deque::new(CacheRegion::WriteOrder), + write_order: Deque::new(CacheRegion::Other), } } } @@ -36,36 +40,38 @@ impl Deques { khd: KeyHashDate, entry: &TrioArc>, ) { - use CacheRegion::*; - let node = Box::new(DeqNode::new(region, khd)); - let node = match node.as_ref().region { - Window => self.window.push_back(node), - MainProbation => self.probation.push_back(node), - MainProtected => self.protected.push_back(node), - WriteOrder => unreachable!(), + let node = Box::new(DeqNode::new(khd)); + let node = match region { + CacheRegion::Window => self.window.push_back(node), + CacheRegion::MainProbation => self.probation.push_back(node), + CacheRegion::MainProtected => self.protected.push_back(node), + _ => unreachable!(), }; - entry.set_access_order_q_node(Some(node)); + let tagged_node = TagNonNull::compose(node, region as usize); + entry.set_access_order_q_node(Some(tagged_node)); } pub(crate) fn push_back_wo(&mut self, kd: KeyDate, entry: &TrioArc>) { - let node = Box::new(DeqNode::new(CacheRegion::WriteOrder, kd)); + let node = Box::new(DeqNode::new(kd)); let node = self.write_order.push_back(node); entry.set_write_order_q_node(Some(node)); } pub(crate) fn move_to_back_ao(&mut self, entry: &TrioArc>) { - use CacheRegion::*; - if let Some(node) = entry.access_order_q_node() { + if let Some(tagged_node) = entry.access_order_q_node() { + let (node, tag) = tagged_node.decompose(); let p = unsafe { node.as_ref() }; - match &p.region { - Window if self.window.contains(p) => unsafe { self.window.move_to_back(node) }, - MainProbation if self.probation.contains(p) => unsafe { - self.probation.move_to_back(node) - }, - MainProtected if self.protected.contains(p) => unsafe { - self.protected.move_to_back(node) - }, - _ => {} + match tag.into() { + CacheRegion::Window if self.window.contains(p) => { + unsafe { self.window.move_to_back(node) }; + } + CacheRegion::MainProbation if self.probation.contains(p) => { + unsafe { self.probation.move_to_back(node) }; + } + CacheRegion::MainProtected if self.protected.contains(p) => { + unsafe { self.protected.move_to_back(node) }; + } + _ => unreachable!(), } } } @@ -75,9 +81,10 @@ impl Deques { deq: &mut Deque>, entry: &TrioArc>, ) { - if let Some(node) = entry.access_order_q_node() { + if let Some(tagged_node) = entry.access_order_q_node() { + let (node, tag) = tagged_node.decompose(); let p = unsafe { node.as_ref() }; - if &p.region == deq.region() { + if deq.region() == tag { if deq.contains(p) { unsafe { deq.move_to_back(node) }; } @@ -91,10 +98,8 @@ impl Deques { } pub(crate) fn move_to_back_wo(&mut self, entry: &TrioArc>) { - use CacheRegion::*; if let Some(node) = entry.write_order_q_node() { let p = unsafe { node.as_ref() }; - debug_assert_eq!(&p.region, &WriteOrder); if self.write_order.contains(p) { unsafe { self.write_order.move_to_back(node) }; } @@ -107,15 +112,8 @@ impl Deques { ) { if let Some(node) = entry.write_order_q_node() { let p = unsafe { node.as_ref() }; - if &p.region == deq.region() { - if deq.contains(p) { - unsafe { deq.move_to_back(node) }; - } - } else { - panic!( - "move_to_back_wo_in_deque - node is not a member of write_order deque. {:?}", - p, - ) + if deq.contains(p) { + unsafe { deq.move_to_back(node) }; } } } @@ -142,16 +140,17 @@ impl Deques { } } - pub(crate) fn unlink_node_ao(&mut self, node: NonNull>>) { - use CacheRegion::*; + pub(crate) fn unlink_node_ao(&mut self, tagged_node: TagNonNull>, 2>) { unsafe { - match node.as_ref().region { - Window => Self::unlink_node_ao_from_deque("window", &mut self.window, node), - MainProbation => { - Self::unlink_node_ao_from_deque("probation", &mut self.probation, node) + match tagged_node.decompose_tag().into() { + CacheRegion::Window => { + Self::unlink_node_ao_from_deque("window", &mut self.window, tagged_node) + } + CacheRegion::MainProbation => { + Self::unlink_node_ao_from_deque("probation", &mut self.probation, tagged_node) } - MainProtected => { - Self::unlink_node_ao_from_deque("protected", &mut self.protected, node) + CacheRegion::MainProtected => { + Self::unlink_node_ao_from_deque("protected", &mut self.protected, tagged_node) } _ => unreachable!(), } @@ -161,10 +160,11 @@ impl Deques { unsafe fn unlink_node_ao_from_deque( deq_name: &str, deq: &mut Deque>, - node: NonNull>>, + tagged_node: TagNonNull>, 2>, ) { + let (node, tag) = tagged_node.decompose(); let p = node.as_ref(); - if &p.region == deq.region() { + if deq.region() == tag { if deq.contains(p) { // https://github.com/moka-rs/moka/issues/64 deq.unlink_and_drop(node); @@ -180,16 +180,9 @@ impl Deques { pub(crate) fn unlink_node_wo(deq: &mut Deque>, node: NonNull>>) { unsafe { let p = node.as_ref(); - if &p.region == deq.region() { - if deq.contains(p) { - // https://github.com/moka-rs/moka/issues/64 - deq.unlink_and_drop(node); - } - } else { - panic!( - "unlink_node - node is not a member of write_order deque. {:?}", - p - ) + if deq.contains(p) { + // https://github.com/moka-rs/moka/issues/64 + deq.unlink_and_drop(node); } } } diff --git a/src/unsync.rs b/src/unsync.rs index e1052fa0..a803c583 100644 --- a/src/unsync.rs +++ b/src/unsync.rs @@ -5,6 +5,7 @@ mod cache; mod deques; use std::{ptr::NonNull, rc::Rc}; +use tagptr::TagNonNull; pub use builder::CacheBuilder; pub use cache::Cache; @@ -48,7 +49,7 @@ impl KeyHashDate { } // DeqNode for an access order queue. -type KeyDeqNodeAo = NonNull>>; +type KeyDeqNodeAo = TagNonNull>, 2>; // DeqNode for the write order queue. type KeyDeqNodeWo = NonNull>>; diff --git a/src/unsync/cache.rs b/src/unsync/cache.rs index c31cf29a..f1966ee8 100644 --- a/src/unsync/cache.rs +++ b/src/unsync/cache.rs @@ -1,9 +1,10 @@ use super::{deques::Deques, AccessTime, CacheBuilder, KeyDate, KeyHashDate, ValueEntry, Weigher}; use crate::common::{ self, - deque::{CacheRegion, DeqNode, Deque}, + deque::{DeqNode, Deque}, frequency_sketch::FrequencySketch, time::{CheckedTimeOps, Clock, Instant}, + CacheRegion, }; use smallvec::SmallVec; diff --git a/src/unsync/deques.rs b/src/unsync/deques.rs index 844a74b4..8f928358 100644 --- a/src/unsync/deques.rs +++ b/src/unsync/deques.rs @@ -1,7 +1,11 @@ use super::{KeyDate, KeyHashDate, ValueEntry}; -use crate::common::deque::{CacheRegion, DeqNode, Deque}; +use crate::common::{ + deque::{DeqNode, Deque}, + CacheRegion, +}; use std::ptr::NonNull; +use tagptr::TagNonNull; pub(crate) struct Deques { pub(crate) window: Deque>, // Not used yet. @@ -16,7 +20,7 @@ impl Default for Deques { window: Deque::new(CacheRegion::Window), probation: Deque::new(CacheRegion::MainProbation), protected: Deque::new(CacheRegion::MainProtected), - write_order: Deque::new(CacheRegion::WriteOrder), + write_order: Deque::new(CacheRegion::Other), } } } @@ -26,7 +30,7 @@ impl Deques { self.window = Deque::new(CacheRegion::Window); self.probation = Deque::new(CacheRegion::MainProbation); self.protected = Deque::new(CacheRegion::MainProtected); - self.write_order = Deque::new(CacheRegion::WriteOrder); + self.write_order = Deque::new(CacheRegion::Other); } pub(crate) fn push_back_ao( @@ -35,44 +39,45 @@ impl Deques { kh: KeyHashDate, entry: &mut ValueEntry, ) { - use CacheRegion::*; - let node = Box::new(DeqNode::new(region, kh)); - let node = match node.as_ref().region { - Window => self.window.push_back(node), - MainProbation => self.probation.push_back(node), - MainProtected => self.protected.push_back(node), - WriteOrder => unreachable!(), + let node = Box::new(DeqNode::new(kh)); + let node = match region { + CacheRegion::Window => self.window.push_back(node), + CacheRegion::MainProbation => self.probation.push_back(node), + CacheRegion::MainProtected => self.protected.push_back(node), + CacheRegion::Other => unreachable!(), }; - entry.set_access_order_q_node(Some(node)); + let tagged_node = TagNonNull::compose(node, region as usize); + entry.set_access_order_q_node(Some(tagged_node)); } pub(crate) fn push_back_wo(&mut self, kh: KeyDate, entry: &mut ValueEntry) { - let node = Box::new(DeqNode::new(CacheRegion::WriteOrder, kh)); + let node = Box::new(DeqNode::new(kh)); let node = self.write_order.push_back(node); entry.set_write_order_q_node(Some(node)); } pub(crate) fn move_to_back_ao(&mut self, entry: &ValueEntry) { - use CacheRegion::*; - let node = entry.access_order_q_node().unwrap(); - let p = unsafe { node.as_ref() }; - match &p.region { - Window if self.window.contains(p) => unsafe { self.window.move_to_back(node) }, - MainProbation if self.probation.contains(p) => unsafe { - self.probation.move_to_back(node) - }, - MainProtected if self.protected.contains(p) => unsafe { - self.protected.move_to_back(node) - }, - _ => {} + if let Some(tagged_node) = entry.access_order_q_node() { + let (node, tag) = tagged_node.decompose(); + let p = unsafe { node.as_ref() }; + match tag.into() { + CacheRegion::Window if self.window.contains(p) => { + unsafe { self.window.move_to_back(node) }; + } + CacheRegion::MainProbation if self.probation.contains(p) => { + unsafe { self.probation.move_to_back(node) }; + } + CacheRegion::MainProtected if self.protected.contains(p) => { + unsafe { self.protected.move_to_back(node) }; + } + _ => unreachable!(), + } } } pub(crate) fn move_to_back_wo(&mut self, entry: &ValueEntry) { - use CacheRegion::*; let node = entry.write_order_q_node().unwrap(); let p = unsafe { node.as_ref() }; - debug_assert_eq!(&p.region, &WriteOrder); if self.write_order.contains(p) { unsafe { self.write_order.move_to_back(node) }; } @@ -100,16 +105,17 @@ impl Deques { } } - pub(crate) fn unlink_node_ao(&mut self, node: NonNull>>) { - use CacheRegion::*; + pub(crate) fn unlink_node_ao(&mut self, tagged_node: TagNonNull>, 2>) { unsafe { - match node.as_ref().region { - Window => Self::unlink_node_ao_from_deque("window", &mut self.window, node), - MainProbation => { - Self::unlink_node_ao_from_deque("probation", &mut self.probation, node) + match tagged_node.decompose_tag().into() { + CacheRegion::Window => { + Self::unlink_node_ao_from_deque("window", &mut self.window, tagged_node) + } + CacheRegion::MainProbation => { + Self::unlink_node_ao_from_deque("probation", &mut self.probation, tagged_node) } - MainProtected => { - Self::unlink_node_ao_from_deque("protected", &mut self.protected, node) + CacheRegion::MainProtected => { + Self::unlink_node_ao_from_deque("protected", &mut self.protected, tagged_node) } _ => unreachable!(), } @@ -119,9 +125,10 @@ impl Deques { unsafe fn unlink_node_ao_from_deque( deq_name: &str, deq: &mut Deque>, - node: NonNull>>, + tagged_node: TagNonNull>, 2>, ) { - if deq.contains(node.as_ref()) { + let (node, tag) = tagged_node.decompose(); + if deq.region() == tag && deq.contains(node.as_ref()) { // https://github.com/moka-rs/moka/issues/64 deq.unlink_and_drop(node); } else { @@ -134,10 +141,8 @@ impl Deques { } pub(crate) fn unlink_node_wo(deq: &mut Deque>, node: NonNull>>) { - use CacheRegion::*; unsafe { let p = node.as_ref(); - debug_assert_eq!(&p.region, &WriteOrder); if deq.contains(p) { // https://github.com/moka-rs/moka/issues/64 deq.unlink_and_drop(node); From 0676a131cf2e561e1aaae6671277d67375bc6ae1 Mon Sep 17 00:00:00 2001 From: Tatsuya Kawano Date: Thu, 3 Feb 2022 18:18:31 +0800 Subject: [PATCH 2/3] Raise the MSRV to 1.51.0 tagptr 0.2.0 requires const generics. --- .github/workflows/CI.yml | 4 +--- README.md | 7 ++++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index ffe5bc53..39f08606 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -23,9 +23,7 @@ jobs: rust: - stable - beta - # - 1.46.0 # MSRV (future) - # - 1.45.2 # MSRV (no features) - - 1.49.0 # Temporary MSRV + - 1.51.0 # MSRV (for both no features and "future") steps: - name: Checkout Moka diff --git a/README.md b/README.md index 0f84e01c..aa6479f8 100644 --- a/README.md +++ b/README.md @@ -386,9 +386,9 @@ This crate's minimum supported Rust versions (MSRV) are the followings: | Feature | Enabled by default? | MSRV | |:-----------|:-------------------:|:-----------:| -| no feature | | Rust 1.45.2 | -| `atomic64` | yes | Rust 1.45.2 | -| `future` | | Rust 1.46.0 | +| no feature | | Rust 1.51.0 | +| `atomic64` | yes | Rust 1.51.0 | +| `future` | | Rust 1.51.0 | If only the default features are enabled, MSRV will be updated conservatively. When using other features, like `future`, MSRV might be updated more frequently, up to the @@ -396,6 +396,7 @@ latest stable. In both cases, increasing MSRV is _not_ considered a semver-break change.