Skip to content

Commit

Permalink
plain, sharded: hide the Cache structs behind public modules
Browse files Browse the repository at this point in the history
We want to encourage people to use our `Cache`/`ReadOnlyCache`
wrappers.  Expose the plain and sharded caches only via their
modules, and not at the crate's toplevel.

TESTED=existing tests build.
  • Loading branch information
pkhuong committed Sep 12, 2021
1 parent ec0dfc7 commit b871478
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 41 deletions.
6 changes: 2 additions & 4 deletions src/lib.rs
@@ -1,16 +1,14 @@
mod cache_dir;
mod plain;
pub mod plain;
pub mod raw_cache;
mod readonly;
pub mod second_chance;
mod sharded;
pub mod sharded;
mod stack;
mod trigger;

pub use plain::PlainCache;
pub use readonly::ReadOnlyCache;
pub use readonly::ReadOnlyCacheBuilder;
pub use sharded::ShardedCache;
pub use stack::Cache;
pub use stack::CacheBuilder;
pub use stack::CacheHit;
Expand Down
31 changes: 21 additions & 10 deletions src/plain.rs
@@ -1,3 +1,14 @@
//! A `plain::Cache` stores all cached file in a single directory, and
//! periodically scans for evictions with a second chance strategy.
//! This implementation does not scale up to more than a few hundred
//! files per cache directory (a `sharded::Cache` can go higher),
//! but interoperates seamlessly with other file-based programs.
//!
//! This module is useful for lower level usage; in most cases, the
//! `Cache` is more convenient and just as efficient.
//!
//! The cache's contents will grow past its stated capacity, but
//! should rarely reach more than twice that capacity.
use std::borrow::Cow;
use std::fs::File;
use std::io::Result;
Expand All @@ -19,7 +30,7 @@ const MAINTENANCE_SCALE: usize = 3;
/// every `k / 3` (`k / 6` in the long run, given the way
/// `PeriodicTrigger` is implemented) insertions.
#[derive(Clone, Debug)]
pub struct PlainCache {
pub struct Cache {
// The cached files are siblings of this directory for temporary
// files.
temp_dir: PathBuf,
Expand All @@ -34,7 +45,7 @@ pub struct PlainCache {
capacity: usize,
}

impl CacheDir for PlainCache {
impl CacheDir for Cache {
#[inline]
fn temp_dir(&self) -> Cow<Path> {
Cow::from(&self.temp_dir)
Expand All @@ -56,14 +67,14 @@ impl CacheDir for PlainCache {
}
}

impl PlainCache {
impl Cache {
/// Returns a new cache for approximately `capacity` files in
/// `base_dir`.
pub fn new(base_dir: PathBuf, capacity: usize) -> PlainCache {
pub fn new(base_dir: PathBuf, capacity: usize) -> Cache {
let mut temp_dir = base_dir;

temp_dir.push(TEMP_SUBDIR);
PlainCache {
Cache {
temp_dir,
trigger: PeriodicTrigger::new((capacity / MAINTENANCE_SCALE) as u64),
capacity,
Expand Down Expand Up @@ -142,7 +153,7 @@ fn smoke_test() {

// Make sure the garbage file is old enough to be deleted.
std::thread::sleep(std::time::Duration::from_secs_f64(2.5));
let cache = PlainCache::new(temp.path("."), 10);
let cache = Cache::new(temp.path("."), 10);

for i in 0..20 {
let name = format!("{}", i);
Expand Down Expand Up @@ -188,7 +199,7 @@ fn test_set() {
use test_dir::{DirBuilder, TestDir};

let temp = TestDir::temp();
let cache = PlainCache::new(temp.path("."), 1);
let cache = Cache::new(temp.path("."), 1);

{
let tmp = NamedTempFile::new_in(cache.temp_dir().expect("temp_dir must succeed"))
Expand Down Expand Up @@ -241,7 +252,7 @@ fn test_put() {
use test_dir::{DirBuilder, TestDir};

let temp = TestDir::temp();
let cache = PlainCache::new(temp.path("."), 1);
let cache = Cache::new(temp.path("."), 1);

{
let tmp = NamedTempFile::new_in(cache.temp_dir().expect("temp_dir must succeed"))
Expand Down Expand Up @@ -293,7 +304,7 @@ fn test_touch() {
use test_dir::{DirBuilder, TestDir};

let temp = TestDir::temp();
let cache = PlainCache::new(temp.path("."), 5);
let cache = Cache::new(temp.path("."), 5);

for i in 0..15 {
let name = format!("{}", i);
Expand Down Expand Up @@ -331,7 +342,7 @@ fn test_recent_temp_file() {
// The garbage file must exist.
assert!(std::fs::metadata(temp.path(&format!("{}/garbage", TEMP_SUBDIR))).is_ok());

let cache = PlainCache::new(temp.path("."), 1);
let cache = Cache::new(temp.path("."), 1);

for i in 0..2 {
let tmp = NamedTempFile::new_in(cache.temp_dir().expect("temp_dir must succeed"))
Expand Down
8 changes: 4 additions & 4 deletions src/readonly.rs
Expand Up @@ -8,9 +8,9 @@ use std::io::Result;
use std::path::Path;
use std::sync::Arc;

use crate::plain::Cache as PlainCache;
use crate::sharded::Cache as ShardedCache;
use crate::Key;
use crate::PlainCache;
use crate::ShardedCache;

/// The `ReadSide` trait offers `get` and `touch`, as implemented by
/// both plain and sharded caches.
Expand Down Expand Up @@ -192,11 +192,11 @@ impl ReadOnlyCache {

#[cfg(test)]
mod test {
use crate::plain::Cache as PlainCache;
use crate::sharded::Cache as ShardedCache;
use crate::Key;
use crate::PlainCache;
use crate::ReadOnlyCache;
use crate::ReadOnlyCacheBuilder;
use crate::ShardedCache;

struct TestKey {
key: String,
Expand Down
41 changes: 22 additions & 19 deletions src/sharded.rs
@@ -1,10 +1,17 @@
//! A `ShardedCache` uses the same basic file-based second chance
//! strategy as a `PlainCache`. However, while the simple plain cache
//! is well suited to small caches (down to 2-3 files, and up maybe
//! one hundred), this sharded version can scale nearly arbitrarily
//! high: each shard should have fewer than one hundred or so files,
//! but there may be arbitrarily many shards (up to filesystem limits,
//! since each shard is a subdirectory).
//! A `sharded::Cache` uses the same basic file-based second chance
//! strategy as a `plain::Cache`. However, while the simple plain
//! cache is well suited to small caches (down to 2-3 files, and up
//! maybe one hundred), this sharded version can scale nearly
//! arbitrarily high: each shard should have fewer than one hundred or
//! so files, but there may be arbitrarily many shards (up to
//! filesystem limits, since each shard is a subdirectory).
//!
//! This module is useful for lower level usage; in most cases, the
//! `Cache` is more convenient and just as efficient.
//!
//! The cache's contents will grow past its stated capacity, but
//! should rarely reach more than twice that capacity, especially
//! when the shard capacity is less than 128 files.
use std::borrow::Cow;
use std::fs::File;
use std::io::Result;
Expand Down Expand Up @@ -32,7 +39,7 @@ const SECONDARY_RANDOM_MULTIPLIER: u64 = 0xa55e1e02718a6a47;
/// subdirectories. Each subdirectory is managed as an
/// independent second chance cache directory.
#[derive(Clone, Debug)]
pub struct ShardedCache {
pub struct Cache {
// The current load (number of files) estimate for each shard.
load_estimates: Arc<[AtomicU8]>,
// The parent directory for each shard (cache subdirectory).
Expand Down Expand Up @@ -111,14 +118,10 @@ impl CacheDir for Shard {
}
}

impl ShardedCache {
impl Cache {
/// Returns a new cache for approximately `total_capacity` files,
/// stores in `num_shards` subdirectories of `base_dir`.
pub fn new(
base_dir: PathBuf,
mut num_shards: usize,
mut total_capacity: usize,
) -> ShardedCache {
pub fn new(base_dir: PathBuf, mut num_shards: usize, mut total_capacity: usize) -> Cache {
// We assume at least two shards.
if num_shards < 2 {
num_shards = 2;
Expand All @@ -135,7 +138,7 @@ impl ShardedCache {
let trigger =
PeriodicTrigger::new(shard_capacity.min(total_capacity / MAINTENANCE_SCALE) as u64);

ShardedCache {
Cache {
load_estimates: load_estimates.into_boxed_slice().into(),
base_dir,
trigger,
Expand Down Expand Up @@ -383,7 +386,7 @@ fn smoke_test() {
const PAYLOAD_MULTIPLIER: usize = 113;

let temp = TestDir::temp();
let cache = ShardedCache::new(temp.path("."), 3, 9);
let cache = Cache::new(temp.path("."), 3, 9);

for i in 0..200 {
let name = format!("{}", i);
Expand Down Expand Up @@ -436,7 +439,7 @@ fn test_set() {
use test_dir::{DirBuilder, TestDir};

let temp = TestDir::temp();
let cache = ShardedCache::new(temp.path("."), 0, 0);
let cache = Cache::new(temp.path("."), 0, 0);

{
let tmp = NamedTempFile::new_in(cache.temp_dir(None).expect("temp_dir must succeed"))
Expand Down Expand Up @@ -489,7 +492,7 @@ fn test_put() {
use test_dir::{DirBuilder, TestDir};

let temp = TestDir::temp();
let cache = ShardedCache::new(temp.path("."), 0, 0);
let cache = Cache::new(temp.path("."), 0, 0);

{
let tmp = NamedTempFile::new_in(cache.temp_dir(None).expect("temp_dir must succeed"))
Expand Down Expand Up @@ -535,7 +538,7 @@ fn test_touch() {
const PAYLOAD_MULTIPLIER: usize = 113;

let temp = TestDir::temp();
let cache = ShardedCache::new(temp.path("."), 2, 600);
let cache = Cache::new(temp.path("."), 2, 600);

for i in 0..2000 {
// After the first write, we should find our file.
Expand Down
8 changes: 4 additions & 4 deletions src/stack.rs
Expand Up @@ -12,11 +12,11 @@ use std::path::Path;
use std::sync::Arc;
use tempfile::NamedTempFile;

use crate::plain::Cache as PlainCache;
use crate::sharded::Cache as ShardedCache;
use crate::Key;
use crate::PlainCache;
use crate::ReadOnlyCache;
use crate::ReadOnlyCacheBuilder;
use crate::ShardedCache;

/// The `FullCache` trait exposes both read and write operations as
/// implemented by sharded and plain caches.
Expand Down Expand Up @@ -428,13 +428,13 @@ impl Cache {
mod test {
use std::io::ErrorKind;

use crate::plain::Cache as PlainCache;
use crate::sharded::Cache as ShardedCache;
use crate::Cache;
use crate::CacheBuilder;
use crate::CacheHit;
use crate::CacheHitAction;
use crate::Key;
use crate::PlainCache;
use crate::ShardedCache;

struct TestKey {
key: String,
Expand Down

0 comments on commit b871478

Please sign in to comment.