GithubHelp home page GithubHelp logo

maidsafe / lru_time_cache Goto Github PK

View Code? Open in Web Editor NEW
103.0 103.0 46.0 3.84 MB

LRU cache settable via size or time to live

License: BSD 3-Clause "New" or "Revised" License

Rust 99.49% Shell 0.51%

lru_time_cache's Introduction

lru_time_cache's People

Contributors

actions-user avatar afck avatar andresilva avatar calavera avatar canndrew avatar chandraprakash avatar dirvine avatar fizyk20 avatar frabrunelle avatar hitman401 avatar inetic avatar loggerhead avatar maidsafe-qa avatar maqi avatar nbaksalyar avatar octol avatar pierrechevalier83 avatar posborne avatar povilasb avatar s-coyle avatar tafia avatar thierry61 avatar ustulation avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lru_time_cache's Issues

License mismatch crates.io / Github

You seemed to have changed the license from GPL to BSD / MIT in this repo, but the version on crates.io shows still GPL 3.0.

Could you maybe push an update to crates.io to clarify the situation?

Enforce lint checks

Add following lint checks to lib.rs (crust is a good example to check)

#![forbid(bad_style, warnings)] 

#![deny(deprecated, improper_ctypes, missing_docs, non_shorthand_field_patterns,
overflowing_literals, plugin_as_library, private_no_mangle_fns, private_no_mangle_statics,
raw_pointer_derive, stable_features, unconditional_recursion, unknown_lints, unsafe_code,
unsigned_negation, unused, unused_allocation, unused_attributes, unused_comparisons,
unused_features, unused_parens, while_true)] 

#![warn(trivial_casts, trivial_numeric_casts, unused_extern_crates, unused_import_braces,
unused_qualifications, variant_size_differences)]

notify_iter docs state expired elements are removed before creating iterator

Describe the bug
notify_iter docs state: "Also removes expired elements before creating the iterator.", which appears to have been copy-pasted from the docs of fn iter.

This conflicts with the implementation, which removes elements as they are encountered during iteration.

I expect that it is the docs that are incorrect and not the implementation.

This created an issue for a project I work on where the cache grew without bound, because it was relying on that call to expire entries from the cache without iterating.

Consider an enum based constructor

In my particular use case I want to provide an api taking in an optional ttl and capacity and constructing an LRU cache based on them. Currently I'm using code similar to the following for that:

pub enum CacheLimit {
  Capacity(usize),
  TimeToLive(Duration),
  TimeToLiveAndCapacity(Duration, usize),
}

match options.cache_limit {
  CacheLimit::Capacity(capacity) => LruCache::with_capacity(capacity),
  CacheLimit::TimeToLive(ttl) => LruCache::with_expiry_duration(ttl),
  CacheLimit::TimeToLiveAndCapacity(ttl, capacity) => LruCache::with_expiry_duration_and_capacity(ttl, capacity),
}

This seems like something that could be added to the library for anyone else that would want to provide a similar API, maybe the method

impl LruCache {
  pub fn with_limit(limit: CacheLimit) -> LruCache;
}

Initial run of RustFmt

Initial run of RustFmt on libraries that are not being worked on at the moment.

I am tackling this issue myself as part of the code bounty program as suggested by Fraser and approved by David.

change `key: &Key` argument to use `Borrow` trait

For example, the following code is not support:

let cache: LruCache<String, String> = LruCache::with_capacity(1);
cache.contains_key("foo");

Consider change the method declaration from

fn contains_key(&self, key: &Key) -> bool 

to

fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool 
    where Key: Borrow<Q>, Q: Ord

iter_mut()

There should be LruCache::iter_mut() and LruCache::peek_iter_mut.
Currently mutable iteration requires using shared one, collecting the keys and using get_mut repeatedly.

Race Condition Leading to Panic on call to entry()

I am using lru_time_cache on an embedded Linux system with somewhat limited CPU resources which may exacerbate the problem, but reviewing the code the problem seems to be there regardless.

Here's the code for entry() at present:

    /// Gets the given key's corresponding entry in the map for in-place manipulation.
    pub fn entry(&mut self, key: Key) -> Entry<'_, Key, Value> {
        // We need to do it the ugly way below due to this issue:
        // https://github.com/rust-lang/rfcs/issues/811
        // match self.get_mut(&key) {
        //     Some(value) => Entry::Occupied(OccupiedEntry{value: value}),
        //     None => Entry::Vacant(VacantEntry{key: key, cache: self}),
        // }
        if self.contains_key(&key) {
            Entry::Occupied(OccupiedEntry {
                value: self.get_mut(&key).expect("key not found"),
            })
        } else {
            Entry::Vacant(VacantEntry { key, cache: self })
        }
    }

On a device running code making use of entry() I got a crash report of a crash due to a panic with message "key not found" from a call to entry() on the lru_time_cache for this code.

It seems possible that it could very well be the case that the contains_key could see an unexpired key when it is executed but that when we execute get_mut the new Instant would see that key as expired leading to a crash. The code is incorrect and has a race condition not involving concurrency.

I will try to get the core dump from this crash and update with more insights if applicable. The logic here could be valid if the operations were made into pure functions taking the Instant in rather than fetching it from the system at many different execution locations.

Poke method?

My lru_time_cache is behind a RwLock, so the get method needs to be in a write() lock. To avoid this I could get() a result drop it and then peek it, but a poke/peek method or something like that would be nicer.

private_no_mangle_fns/statics lints are removed in Rust 1.31

$ rustc -V
rustc 1.31.0 (abe02cefd 2018-12-04)
$ cargo build
   Compiling lru_time_cache v0.8.0 (/home/jistone/rust/lru_time_cache)
error: lint `private_no_mangle_fns` has been removed: `no longer an warning, #[no_mangle] functions always exported`
  --> src/lib.rs:59:5
   |
59 |     private_no_mangle_fns,
   |     ^^^^^^^^^^^^^^^^^^^^^
   |
note: lint level defined here
  --> src/lib.rs:50:5
   |
50 |     warnings
   |     ^^^^^^^^
   = note: #[forbid(renamed_and_removed_lints)] implied by #[forbid(warnings)]

error: lint `private_no_mangle_statics` has been removed: `no longer an warning, #[no_mangle] statics always exported`
  --> src/lib.rs:60:5
   |
60 |     private_no_mangle_statics,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

error: Could not compile `lru_time_cache`.

To learn more, run the command again with --verbose.

O(n) time complexity for most operations

Describe the bug
The LruCache is implemented with a BTreeMap and a VecDeque, which means that by accessing keys and calling the
update_key method, it will invoke a VecDeque::remove operation, which will cost O(n) time.

Expected behavior
Should be O(1).

Additional context
Some other libs that do the complexity right:

  • lru-cache & linked-hash-map: used a linked hash map, O(1).
  • hashlink: used a linked hash map, O(1).

sample

#![feature(test)]

extern crate test;
use test::Bencher;

use std::cell::RefCell;
use std::collections::HashMap;
use lru_cache::LruCache as LruCacheLruCache;
use lru_time_cache::LruCache;
use hashlink::LruCache as HashLinkLruCache;
use rand::prelude::*;

fn main() { }

const RANGE: usize = 32 * 1024;
const FIND_TIMES: usize = 10;

#[bench]
fn lru_time_cache_sum(b: &mut Bencher) {
    let mut lru = LruCache::with_capacity(RANGE);
    for i in 0..RANGE {
        lru.insert(i, i);
    }
    let lru = RefCell::new(lru);
    b.iter(|| {
        let res: usize = (0..FIND_TIMES)
            .map(|_| *lru
                .borrow_mut()
                .get(&thread_rng().gen_range(0, RANGE))
                .unwrap_or(&0))
            .sum();
        test::black_box(res);
    });
}

#[bench]
fn lru_cache_sum(b: &mut Bencher) {
    let mut lru = LruCacheLruCache::new(RANGE);
    for i in 0..RANGE {
        lru.insert(i, i);
    }
    let lru = RefCell::new(lru);
    b.iter(|| {
        let res: usize = (0..FIND_TIMES)
            .map(|_| *lru
                .borrow_mut()
                .get_mut(&thread_rng().gen_range(0, RANGE))
                .unwrap_or(&mut 0))
            .sum();
        test::black_box(res);
    });
}

#[bench]
fn hashlink_lru_cache_sum(b: &mut Bencher) {
    let mut lru = HashLinkLruCache::new(RANGE);
    for i in 0..RANGE {
        lru.insert(i, i);
    }
    let lru = RefCell::new(lru);
    b.iter(|| {
        let res: usize = (0..FIND_TIMES)
            .map(|_| *lru
                .borrow_mut()
                .get(&thread_rng().gen_range(0, RANGE))
                .unwrap_or(&0))
            .sum();
        test::black_box(res);
    });
}

#[bench]
fn hashmap_sum(b: &mut Bencher) {
    let mut map = HashMap::new();
    for i in 0..RANGE {
        map.insert(i, i);
    }
    b.iter(|| {
        let res: usize = (0..FIND_TIMES)
            .map(|_| *map
                .get(&thread_rng().gen_range(0, RANGE))
                .unwrap_or(&0))
            .sum();
        test::black_box(res);
    });
}

Lru time cache should have a more standard API

It's odd that LruTimeCache has a method to clone all it's elements out into a Vec. Standard library collections don't have methods like this. To clone a HashMap into a Vec you'd write:

my_hash_map.iter().map(|(k, v)| (k.clone(), v.clone())).collect()

Although if someone did this in practice (rather than just using the iterator) they'd probably be doing something wrong.

LruTimeCache's API should be changed to mirror that of HashMap as closely as is appropriate.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.