Skip to content

Commit

Permalink
feat: migrate geo cache to arc mutex cache
Browse files Browse the repository at this point in the history
  • Loading branch information
RouHim committed Sep 15, 2022
1 parent 095c6ea commit 3ab035b
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 102 deletions.
71 changes: 0 additions & 71 deletions src/geo_location_cache.rs

This file was deleted.

76 changes: 76 additions & 0 deletions src/in_memory_cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use std::sync::{Arc, Mutex};

use evmap::{ReadHandle, WriteHandle};

/// Holds the cache reader and writer
/// Writer is stored as an arc mutex for protected shared writing
#[derive(Clone)]
pub struct InMemoryCache {
kv_reader: ReadHandle<String, String>,
kv_writer: Arc<Mutex<WriteHandle<String, String>>>,
}

/// Initializes a thread safe in memory cache
pub fn new() -> InMemoryCache {
let (kv_reader, kv_writer) = evmap::new::<String, String>();
InMemoryCache {
kv_reader,
kv_writer: Arc::new(Mutex::new(kv_writer)),
}
}

impl InMemoryCache {
/// Checks if the cache contains the given key
/// Returns true if the key is present, false otherwise
/// # Arguments
/// * `key` - The key to check
///
/// # Example
/// ```
/// use in_memory_cache::InMemoryCache;
/// let mut in_memory_cache = InMemoryCache::init();
/// let key = "key".to_string();
/// in_memory_cache.insert(key.clone(), "value".to_string());
/// assert_eq!(in_memory_cache.contains_key(key.as_str()), true);
/// ```
///
pub fn contains_key(&self, key: &str) -> bool {
self.kv_reader.contains_key(key)
}

/// Returns the value for the given key
/// Returns `None` if the key is not in the cache
/// # Arguments
/// * `key` - The key to get the value for
/// # Example
/// ```
/// use in_memory_cache::InMemoryCache;
/// let mut in_memory_cache = InMemoryCache::init();
/// let key = "key".to_string();
/// in_memory_cache.insert(key.clone(), "value".to_string());
/// assert_eq!(in_memory_cache.get(key.as_str()), Some("value".to_string()));
/// ```
pub fn get(&self, key: &str) -> Option<String> {
self.kv_reader.get_one(key).map(|t| t.to_string())
}

/// Inserts the given key and value into the cache
/// Refreshes the cache after the insert
/// # Arguments
/// * `key` - The key to insert
/// * `value` - The value to insert
/// # Example
/// ```
/// use in_memory_cache::InMemoryCache;
/// let mut in_memory_cache = InMemoryCache::init();
/// let key = "key".to_string();
/// let value = "value".to_string();
/// in_memory_cache.insert(key.clone(), value.clone());
/// assert_eq!(in_memory_cache.get(key.as_str()), Some(value));
/// ```
pub fn insert(&self, key: String, value: String) {
let mut kv_writer = self.kv_writer.lock().unwrap();
kv_writer.insert(key, value);
kv_writer.refresh();
}
}
6 changes: 2 additions & 4 deletions src/integration_test_resources_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ use rand::Rng;

use crate::geo_location::GeoLocation;
use crate::resource_reader::{RemoteResource, ResourceReader};
use crate::{
geo_location_cache, resource_endpoint, resource_processor, resource_reader, scheduler,
};
use crate::{in_memory_cache, resource_endpoint, resource_processor, resource_reader, scheduler};

const TEST_JPEG_EXIF_URL: &str =
"https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/gps/DSCN0010.jpg";
Expand Down Expand Up @@ -279,7 +277,7 @@ fn build_app(
> {
scheduler::init();
scheduler::fetch_resources(resource_reader.clone(), kv_writer_mutex.clone());
let geo_location_cache = Arc::new(Mutex::new(geo_location_cache::init()));
let geo_location_cache = in_memory_cache::new();
App::new()
.app_data(web::Data::new(kv_reader))
.app_data(web::Data::new(resource_reader))
Expand Down
6 changes: 3 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use actix_web::{middleware, web, App, HttpResponse, HttpServer};
mod config_endpoint;
mod exif_reader;
mod geo_location;
mod geo_location_cache;
mod image_processor;
mod in_memory_cache;
mod resource_endpoint;
mod resource_processor;
mod resource_reader;
Expand Down Expand Up @@ -52,14 +52,14 @@ async fn main() -> std::io::Result<()> {
scheduler::fetch_resources(resource_reader.clone(), kv_writer_mutex.clone());

// Initialize geo location cache
let geo_location_cache = Arc::new(Mutex::new(geo_location_cache::init()));
let geo_location_cache = in_memory_cache::new();

// Run the actual web server and hold the main thread here
println!("Launching webserver 🚀");
let http_server_result = HttpServer::new(move || {
App::new()
.app_data(web::Data::new(kv_reader.clone()))
.app_data(web::Data::new(resource_reader.clone()))
.app_data(web::Data::new(kv_reader.clone()))
.app_data(web::Data::new(kv_writer_mutex.clone()))
.app_data(web::Data::new(geo_location_cache.clone()))
.wrap(middleware::Logger::default()) // enable logger
Expand Down
11 changes: 3 additions & 8 deletions src/resource_endpoint.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
use std::sync::{Arc, Mutex};

use actix_web::get;
use actix_web::web;
use actix_web::HttpResponse;
use evmap::ReadHandle;

use crate::geo_location_cache::GeoLocationCache;
use crate::in_memory_cache::InMemoryCache;
use crate::resource_reader::{RemoteResource, ResourceReader};
use crate::{image_processor, resource_processor};

Expand Down Expand Up @@ -124,18 +122,15 @@ pub async fn get_resource_metadata_by_id(
pub async fn get_resource_metadata_description_by_id(
resources_id: web::Path<String>,
kv_reader: web::Data<ReadHandle<String, String>>,
geo_location_cache_mutex: web::Data<Arc<Mutex<GeoLocationCache>>>,
geo_location_cache: web::Data<InMemoryCache>,
) -> HttpResponse {
let resource = kv_reader
.get_one(resources_id.as_str())
.map(|value| value.to_string())
.and_then(|resource_json_string| serde_json::from_str(resource_json_string.as_str()).ok());

let display_value = resource.map(|resource| {
resource_processor::build_display_value(
resource,
geo_location_cache_mutex.get_ref().clone(),
)
resource_processor::build_display_value(resource, geo_location_cache.as_ref())
});

if let Some(display_value) = display_value {
Expand Down
25 changes: 9 additions & 16 deletions src/resource_processor.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use std::env;
use std::sync::{Arc, Mutex};

use evmap::ReadHandle;
use rand::prelude::SliceRandom;
use rand::Rng;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};

use crate::geo_location;
use crate::geo_location_cache::GeoLocationCache;
use crate::in_memory_cache::InMemoryCache;
use crate::resource_reader::RemoteResource;

pub fn md5(string: &str) -> String {
Expand Down Expand Up @@ -50,7 +49,7 @@ pub fn get_all(kv_reader: &ReadHandle<String, String>) -> Vec<String> {
/// The display value contains the date and location of a resource
pub async fn build_display_value(
resource: RemoteResource,
geo_location_cache_mutex: Arc<Mutex<GeoLocationCache>>,
geo_location_cache: &InMemoryCache,
) -> String {
let mut display_value: String = String::new();

Expand All @@ -68,7 +67,7 @@ pub async fn build_display_value(
};

// Append city name
let city_name = get_city_name(resource, geo_location_cache_mutex.clone()).await;
let city_name = get_city_name(resource, geo_location_cache).await;
if let Some(city_name) = city_name {
display_value.push_str(", ");
display_value.push_str(city_name.as_str());
Expand All @@ -82,29 +81,23 @@ pub async fn build_display_value(
/// If not, the city name is taken from the geo location service
async fn get_city_name(
resource: RemoteResource,
geo_location_cache_mutex: Arc<Mutex<GeoLocationCache>>,
geo_location_cache: &InMemoryCache,
) -> Option<String> {
let resource_location = resource.location?;
let resource_location_string = resource_location.to_string();

// First check cache
if geo_location_cache_mutex
.lock()
.unwrap()
.contains_key(resource_location_string.as_str())
{
geo_location_cache_mutex
.lock()
.unwrap()
.get(resource_location_string.as_str())
if geo_location_cache.contains_key(resource_location_string.as_str()) {
println!("Cache hit for {}", resource_location_string.as_str());
geo_location_cache.get(resource_location_string.as_str())
} else {
println!("Cache miss for {}", resource_location_string.as_str());
// Get city name
let city_name = geo_location::resolve_city_name(resource_location).await;

if let Some(city_name) = &city_name {
// Write to cache
let mut kv_writer = geo_location_cache_mutex.lock().unwrap();
kv_writer.insert(resource_location_string, city_name.clone());
geo_location_cache.insert(resource_location_string, city_name.clone());
}

city_name
Expand Down

0 comments on commit 3ab035b

Please sign in to comment.