LINUX.ORG.RU

История изменений

Исправление derlafff, (текущая версия) :

Писал похожий по сути код. Уверен, в нем есть куча проблем и в целом неадеквата, но он хотя бы конпелируется.

use async_lock::Mutex;
use std::collections::HashMap;
use std::hash::Hash;
use std::sync::Arc;
use std::time::{Duration, Instant};

pub(crate) struct Cache<K: Eq + Hash, V: Default> {
    lru: Mutex<HashMap<K, Entry<V>>>,
    ttl: Duration,
    max_size: usize,
}

struct Entry<T: Default> {
    used: Instant,
    value: Arc<T>,
}

impl<K: Eq + Hash, V: Default> Cache<K, V> {
    pub fn new(max_size: usize, ttl: Duration) -> Self {
        let lru = Mutex::new(HashMap::with_capacity(max_size));
        Cache { lru, max_size, ttl }
    }

    pub async fn get(&self, key: K) -> Arc<V> {
        let mut g = self.lru.lock().await;

        let entry = g.entry(key).or_insert_with(|| Entry {
            used: Instant::now(),
            value: Arc::new(V::default()),
        });

        // TODO: avoid double-setting this field?
        entry.used = Instant::now();

        entry.value.clone()
    }

    pub async fn clean(&self) {
        // удолил: для этого топика не важно.
        // если интересно, смотрите в истории
    }
}

Исправление derlafff, :

Писал похожий по сути код. Уверен, в нем есть куча проблем и в целом неадеквата, но он хотя бы конпелируется.

use async_lock::Mutex;
use std::collections::HashMap;
use std::hash::Hash;
use std::sync::Arc;
use std::time::{Duration, Instant};

// Cache does two things:
// stores items in a cache
// makes sure two parallel requests are never executed
pub(crate) struct Cache<K: Eq + Hash, V: Default> {
    lru: Mutex<HashMap<K, Entry<V>>>,
    ttl: Duration,
    max_size: usize,
}

struct Entry<T: Default> {
    used: Instant,
    value: Arc<T>,
}

impl<K: Eq + Hash, V: Default> Cache<K, V> {
    pub fn new(max_size: usize, ttl: Duration) -> Self {
        let lru = Mutex::new(HashMap::with_capacity(max_size));
        Cache { lru, max_size, ttl }
    }

    pub async fn get(&self, key: K) -> Arc<V> {
        let mut g = self.lru.lock().await;
        // get or default ASAP - we are blocking everyone else
        let entry = g.entry(key).or_insert_with(|| Entry {
            used: Instant::now(),
            value: Arc::new(V::default()),
        });

        // TODO: avoid double-setting this field?
        entry.used = Instant::now();

        entry.value.clone()
    }

    pub async fn clean(&self) {
        // удолил: для этого топика не важно.
        // если интересно, смотрите в истории
    }
}

Исправление derlafff, :

Писал похожий по сути код. Уверен, в нем есть куча проблем и в целом неадеквата, но он хотя бы конпелируется.

use async_lock::Mutex;
use std::collections::HashMap;
use std::hash::Hash;
use std::sync::Arc;
use std::time::{Duration, Instant};

// Cache does two things:
// stores items in a cache
// makes sure two parallel requests are never executed
pub(crate) struct Cache<K: Eq + Hash, V: Default> {
    lru: Mutex<HashMap<K, Entry<V>>>,
    ttl: Duration,
    max_size: usize,
}

struct Entry<T: Default> {
    used: Instant,
    value: Arc<T>,
}

impl<K: Eq + Hash, V: Default> Cache<K, V> {
    pub fn new(max_size: usize, ttl: Duration) -> Self {
        let lru = Mutex::new(HashMap::with_capacity(max_size));
        Cache { lru, max_size, ttl }
    }

    pub async fn get(&self, key: K) -> Arc<V> {
        let mut g = self.lru.lock().await;
        // get or default ASAP - we are blocking everyone else
        let entry = g.entry(key).or_insert_with(|| Entry {
            used: Instant::now(),
            value: Arc::new(V::default()),
        });

        // TODO: avoid double-setting this field?
        entry.used = Instant::now();

        entry.value.clone()
    }

    pub async fn clean(&self) {
        let mut g = self.lru.lock().await;

        // check if we need to do anything at all
        if g.len() <= self.max_size {
            return;
        }

        // at this point it should be safe to substract unsigned ints
        let mut to_remove = self.max_size - g.len();

        // remove all entries which exceed ttl
        g.retain(|_k, v| {
            if to_remove == 0 || v.used.elapsed() < self.ttl {
                false
            } else {
                to_remove -= 1;
                true
            }
        });

        // TODO: implement max_size
    }
}

Исходная версия derlafff, :

Писал похожий по сути код. Уверен, в нем есть куча проблем и в целом неадеквата, но он хотя бы конпелируется.

use async_lock::Mutex;
use std::collections::HashMap;
use std::hash::Hash;
use std::sync::Arc;
use std::time::{Duration, Instant};

// Cache does two things:
// stores items in a cache
// makes sure two parallel requests are never executed
pub(crate) struct Cache<K: Eq + Hash, V: Default> {
    lru: Mutex<HashMap<K, Entry<V>>>,
    ttl: Duration,
    max_size: usize,
}

struct Entry<T: Default> {
    used: Instant,
    value: Arc<T>,
}

impl<K: Eq + Hash, V: Default> Cache<K, V> {
    pub fn new(max_size: usize, ttl: Duration) -> Self {
        let lru = Mutex::new(HashMap::with_capacity(max_size));
        Cache { lru, max_size, ttl }
    }

    pub async fn get(&self, key: K) -> Arc<V> {
        let mut g = self.lru.lock().await;
        // get or default ASAP - we are blocking everyone else
        let entry = g.entry(key).or_insert_with(|| Entry {
            used: Instant::now(),
            value: Arc::new(V::default()),
        });

        // TODO: avoid double-setting this field?
        entry.used = Instant::now();

        entry.value.clone()
    }

    pub async fn clean(&self) {
        let mut g = self.lru.lock().await;

        // check if we need to do anything at all
        if g.len() <= self.max_size {
            return;
        }

        // at this point it should be safe to substract unsigned ints
        let mut to_remove = self.max_size - g.len();

        // remove all entries which exceed ttl
        g.retain(|_k, v| {
            if to_remove == 0 || v.used.elapsed() < self.ttl {
                false
            } else {
                to_remove -= 1;
                true
            }
        });

        // TODO: implement max_size
    }
}