Skip to content

Commit 9230855

Browse files
committed
Delegate fetch
1 parent 70709ef commit 9230855

2 files changed

Lines changed: 85 additions & 6 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

thoth-oai-server/src/service.rs

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::sync::Arc;
1+
use std::{
2+
collections::{HashMap, VecDeque},
3+
sync::{Arc, Mutex},
4+
};
25

36
use oai_pmh::core::MetadataPrefix;
47
use quick_xml::{events::Event, Reader, Writer};
@@ -18,13 +21,49 @@ pub(crate) const PAGE_LIMIT: i64 = 50;
1821
const OAI_DC_SPEC: &str = "dublin_core::thoth";
1922
const OAI_OPENAIRE_SPEC: &str = "openaire::thoth";
2023
const MARCXML_SPEC: &str = "marc21xml::thoth";
24+
const DELEGATED_RECORD_CACHE_LIMIT: usize = 2048;
25+
type DelegatedRecordCacheKey = (Uuid, &'static str);
26+
27+
#[derive(Default)]
28+
struct DelegatedRecordCache {
29+
entries: HashMap<DelegatedRecordCacheKey, String>,
30+
insertion_order: VecDeque<DelegatedRecordCacheKey>,
31+
}
32+
33+
impl DelegatedRecordCache {
34+
fn get(&self, key: &DelegatedRecordCacheKey) -> Option<String> {
35+
self.entries.get(key).cloned()
36+
}
37+
38+
fn insert(&mut self, key: DelegatedRecordCacheKey, value: String) {
39+
match self.entries.entry(key) {
40+
std::collections::hash_map::Entry::Occupied(mut entry) => {
41+
entry.insert(value);
42+
return;
43+
}
44+
std::collections::hash_map::Entry::Vacant(entry) => {
45+
self.insertion_order.push_back(*entry.key());
46+
entry.insert(value);
47+
}
48+
}
49+
50+
while self.entries.len() > DELEGATED_RECORD_CACHE_LIMIT {
51+
if let Some(oldest_key) = self.insertion_order.pop_front() {
52+
self.entries.remove(&oldest_key);
53+
} else {
54+
break;
55+
}
56+
}
57+
}
58+
}
2159

2260
#[derive(Clone)]
2361
pub(crate) struct OaiService {
2462
public_url: String,
2563
export_url: String,
2664
thoth_client: Arc<ThothClient>,
2765
export_client: Client,
66+
delegated_record_cache: Arc<Mutex<DelegatedRecordCache>>,
2867
}
2968

3069
#[derive(Debug, Clone)]
@@ -41,6 +80,7 @@ impl OaiService {
4180
export_url,
4281
thoth_client: Arc::new(ThothClient::new(gql_endpoint)),
4382
export_client: Client::new(),
83+
delegated_record_cache: Arc::new(Mutex::new(DelegatedRecordCache::default())),
4484
}
4585
}
4686

@@ -104,17 +144,35 @@ impl OaiService {
104144
}
105145

106146
pub(crate) async fn get_marcxml_record(&self, work_id: Uuid) -> ThothResult<String> {
107-
self.get_delegated_record(work_id, MARCXML_SPEC, b"record", "MARCXML")
147+
self.get_delegated_record(
148+
work_id,
149+
MetadataPrefix::MarcXml,
150+
MARCXML_SPEC,
151+
b"record",
152+
"MARCXML",
153+
)
108154
.await
109155
}
110156

111157
pub(crate) async fn get_oai_dc_record(&self, work_id: Uuid) -> ThothResult<String> {
112-
self.get_delegated_record(work_id, OAI_DC_SPEC, b"dc", "Dublin Core")
158+
self.get_delegated_record(
159+
work_id,
160+
MetadataPrefix::OaiDc,
161+
OAI_DC_SPEC,
162+
b"dc",
163+
"Dublin Core",
164+
)
113165
.await
114166
}
115167

116168
pub(crate) async fn get_oai_openaire_record(&self, work_id: Uuid) -> ThothResult<String> {
117-
self.get_delegated_record(work_id, OAI_OPENAIRE_SPEC, b"resource", "OpenAIRE")
169+
self.get_delegated_record(
170+
work_id,
171+
MetadataPrefix::OaiOpenaire,
172+
OAI_OPENAIRE_SPEC,
173+
b"resource",
174+
"OpenAIRE",
175+
)
118176
.await
119177
}
120178

@@ -139,10 +197,16 @@ impl OaiService {
139197
async fn get_delegated_record(
140198
&self,
141199
work_id: Uuid,
200+
metadata_prefix: MetadataPrefix,
142201
specification: &str,
143202
element_local_name: &[u8],
144203
format_name: &str,
145204
) -> ThothResult<String> {
205+
let cache_key = (work_id, metadata_prefix.as_str());
206+
if let Some(record) = self.get_cached_delegated_record(&cache_key) {
207+
return Ok(record);
208+
}
209+
146210
let response = self
147211
.export_client
148212
.get(format!(
@@ -168,7 +232,22 @@ impl OaiService {
168232
)));
169233
}
170234

171-
Self::extract_xml_element(&body, element_local_name, format_name)
235+
let record = Self::extract_xml_element(&body, element_local_name, format_name)?;
236+
self.cache_delegated_record(cache_key, record.clone());
237+
Ok(record)
238+
}
239+
240+
fn get_cached_delegated_record(&self, key: &DelegatedRecordCacheKey) -> Option<String> {
241+
self.delegated_record_cache
242+
.lock()
243+
.ok()
244+
.and_then(|cache| cache.get(key))
245+
}
246+
247+
fn cache_delegated_record(&self, key: DelegatedRecordCacheKey, value: String) {
248+
if let Ok(mut cache) = self.delegated_record_cache.lock() {
249+
cache.insert(key, value);
250+
}
172251
}
173252

174253
pub(crate) fn oai_identifier(work_id: Uuid) -> String {

0 commit comments

Comments
 (0)