use super::key::{KeyValue, RefreshKey};
use super::state;
fn check_queue_backpressure(limit: usize) -> crate::TViewResult<()> {
let size = state::get_queue_size();
if size >= limit {
return Err(crate::TViewError::RefreshLimit {
limit: crate::error::Limit::Queue { size, max: limit },
});
}
Ok(())
}
pub fn enqueue_refresh_with_limit(
entity: &str,
key: KeyValue,
limit: usize,
) -> crate::TViewResult<()> {
check_queue_backpressure(limit)?;
state::queue_insert(RefreshKey::new(entity, key));
Ok(())
}
pub fn enqueue_refresh(entity: &str, key: KeyValue) {
if let Err(e) = enqueue_refresh_with_limit(entity, key.clone(), crate::config::max_queue_size())
{
e.raise();
}
super::patch::poison(RefreshKey::new(entity, key));
}
pub fn enqueue_refresh_patched(
entity: &str,
pk: i64,
fields: serde_json::Map<String, serde_json::Value>,
) {
if let Err(e) =
enqueue_refresh_with_limit(entity, KeyValue::Int(pk), crate::config::max_queue_size())
{
e.raise();
}
if super::patch::record(RefreshKey::pk(entity, pk), Vec::new(), fields) {
crate::metrics::metrics_api::record_direct_patch_captured(entity);
}
}
pub fn enqueue_refresh_all(entity: &str) {
let key = RefreshKey::all(entity);
if state::queue_contains(&key) {
return;
}
if let Err(e) = check_queue_backpressure(crate::config::max_queue_size()) {
e.raise();
}
state::queue_insert(key);
}
pub fn enqueue_refresh_bulk(entity: &str, keys: Vec<KeyValue>) {
if let Err(e) = check_queue_backpressure(crate::config::max_queue_size()) {
e.raise();
}
for key in &keys {
state::queue_insert(RefreshKey::new(entity, key.clone()));
}
for key in keys {
super::patch::poison(RefreshKey::new(entity, key));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_enqueue_and_drain() {
state::clear();
enqueue_refresh_with_limit("user", KeyValue::Int(1), usize::MAX).unwrap();
enqueue_refresh_with_limit("post", KeyValue::Int(2), usize::MAX).unwrap();
enqueue_refresh_with_limit("user", KeyValue::Int(1), usize::MAX).unwrap();
assert_eq!(state::drain().queue.len(), 2); assert_eq!(state::drain().queue.len(), 0); }
#[test]
fn test_clear_queue() {
state::clear();
enqueue_refresh_with_limit("user", KeyValue::Int(1), usize::MAX).unwrap();
enqueue_refresh_with_limit("post", KeyValue::Int(2), usize::MAX).unwrap();
state::clear();
assert_eq!(state::drain().queue.len(), 0);
}
#[test]
fn test_multi_entity_queue() {
state::clear();
crate::queue::enqueue_refresh("user", KeyValue::Int(1));
crate::queue::enqueue_refresh("post", KeyValue::Int(10));
crate::queue::enqueue_refresh("user", KeyValue::Int(1)); crate::queue::enqueue_refresh("post", KeyValue::Int(20));
crate::queue::enqueue_refresh("user", KeyValue::Int(2));
let queue = state::drain().queue;
assert_eq!(queue.len(), 4);
assert!(queue.contains(&RefreshKey::pk("user", 1)));
assert!(queue.contains(&RefreshKey::pk("post", 10)));
}
#[test]
fn test_enqueue_respects_max_queue_size() {
state::clear();
let limit = 2;
enqueue_refresh_with_limit("user", KeyValue::Int(1), limit)
.expect("first insert should succeed");
enqueue_refresh_with_limit("post", KeyValue::Int(2), limit)
.expect("second insert should succeed");
assert!(
enqueue_refresh_with_limit("user", KeyValue::Int(3), limit).is_err(),
"third insert should fail"
);
assert_eq!(state::drain().queue.len(), 2);
}
}