aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEdward Wang <[email protected]>2024-08-02 16:41:20 -0700
committerEdward Wang <[email protected]>2024-08-05 19:42:51 +0000
commitf9ac1082ad3e43f3c2c5e5760e0c71bdd1026cd4 (patch)
treee194fff39a2b6fab7f584cd3daca3c249a2cae1e
parent9a887b0584c5412c44268c1507e6a78df9bfd23c (diff)
downloadpingora-f9ac1082ad3e43f3c2c5e5760e0c71bdd1026cd4.tar.gz
pingora-f9ac1082ad3e43f3c2c5e5760e0c71bdd1026cd4.zip
Set stale-updating as an explicit CachePhase
This cache phase indicates when we are serving a stale cache hit, but there is another request currently updating the asset.
-rw-r--r--.bleep2
-rw-r--r--pingora-cache/src/lib.rs19
-rw-r--r--pingora-proxy/src/proxy_cache.rs5
-rw-r--r--pingora-proxy/tests/test_upstream.rs8
-rw-r--r--pingora-proxy/tests/utils/server_utils.rs3
5 files changed, 29 insertions, 8 deletions
diff --git a/.bleep b/.bleep
index 1198c86..195905d 100644
--- a/.bleep
+++ b/.bleep
@@ -1 +1 @@
-f6e596e897d73c69369ae85edf58cec64b106969 \ No newline at end of file
+a626a70391421eb80e6cdc6c3ceb4d16f38367e8 \ No newline at end of file
diff --git a/pingora-cache/src/lib.rs b/pingora-cache/src/lib.rs
index a999f7e..d1346e5 100644
--- a/pingora-cache/src/lib.rs
+++ b/pingora-cache/src/lib.rs
@@ -77,6 +77,8 @@ pub enum CachePhase {
Miss,
/// A staled (expired) asset is found
Stale,
+ /// A staled (expired) asset was found, but another request is revalidating it
+ StaleUpdating,
/// A staled (expired) asset was found, so a fresh one was fetched
Expired,
/// A staled (expired) asset was found, and it was revalidated to be fresh
@@ -96,6 +98,7 @@ impl CachePhase {
CachePhase::Hit => "hit",
CachePhase::Miss => "miss",
CachePhase::Stale => "stale",
+ CachePhase::StaleUpdating => "stale-updating",
CachePhase::Expired => "expired",
CachePhase::Revalidated => "revalidated",
CachePhase::RevalidatedNoCache(_) => "revalidated-nocache",
@@ -260,7 +263,7 @@ impl HttpCache {
use CachePhase::*;
match self.phase {
Disabled(_) | Bypass | Miss | Expired | Revalidated | RevalidatedNoCache(_) => true,
- Hit | Stale => false,
+ Hit | Stale | StaleUpdating => false,
Uninit | CacheKey => false, // invalid states for this call, treat them as false to keep it simple
}
}
@@ -509,6 +512,7 @@ impl HttpCache {
match self.phase {
CachePhase::Hit
| CachePhase::Stale
+ | CachePhase::StaleUpdating
| CachePhase::Revalidated
| CachePhase::RevalidatedNoCache(_) => self.inner_mut().body_reader.as_mut().unwrap(),
_ => panic!("wrong phase {:?}", self.phase),
@@ -544,6 +548,7 @@ impl HttpCache {
| CachePhase::Miss
| CachePhase::Expired
| CachePhase::Stale
+ | CachePhase::StaleUpdating
| CachePhase::Revalidated
| CachePhase::RevalidatedNoCache(_) => {
let inner = self.inner_mut();
@@ -786,6 +791,14 @@ impl HttpCache {
// TODO: remove this asset from cache once finished?
}
+ /// Mark this asset as stale, but being updated separately from this request.
+ pub fn set_stale_updating(&mut self) {
+ match self.phase {
+ CachePhase::Stale => self.phase = CachePhase::StaleUpdating,
+ _ => panic!("wrong phase {:?}", self.phase),
+ }
+ }
+
/// Update the variance of the [CacheMeta].
///
/// Note that this process may change the lookup `key`, and eventually (when the asset is
@@ -854,6 +867,7 @@ impl HttpCache {
match self.phase {
// TODO: allow in Bypass phase?
CachePhase::Stale
+ | CachePhase::StaleUpdating
| CachePhase::Expired
| CachePhase::Hit
| CachePhase::Revalidated
@@ -882,6 +896,7 @@ impl HttpCache {
match self.phase {
CachePhase::Miss
| CachePhase::Stale
+ | CachePhase::StaleUpdating
| CachePhase::Expired
| CachePhase::Hit
| CachePhase::Revalidated
@@ -1006,7 +1021,7 @@ impl HttpCache {
/// Whether this request's cache hit is staled
fn has_staled_asset(&self) -> bool {
- self.phase == CachePhase::Stale
+ matches!(self.phase, CachePhase::Stale | CachePhase::StaleUpdating)
}
/// Whether this asset is staled and stale if error is allowed
diff --git a/pingora-proxy/src/proxy_cache.rs b/pingora-proxy/src/proxy_cache.rs
index 5e90b18..77b7384 100644
--- a/pingora-proxy/src/proxy_cache.rs
+++ b/pingora-proxy/src/proxy_cache.rs
@@ -165,7 +165,9 @@ impl<SV> HttpProxy<SV> {
} else {
break None;
}
- } // else continue to serve stale
+ }
+ // else continue to serve stale
+ session.cache.set_stale_updating();
} else if session.cache.is_cache_lock_writer() {
// stale while revalidate logic for the writer
let will_serve_stale = session.cache.can_serve_stale_updating()
@@ -182,6 +184,7 @@ impl<SV> HttpProxy<SV> {
new_app.process_subrequest(subrequest, sub_req_ctx).await;
});
// continue to serve stale for this request
+ session.cache.set_stale_updating();
} else {
// return to fetch from upstream
break None;
diff --git a/pingora-proxy/tests/test_upstream.rs b/pingora-proxy/tests/test_upstream.rs
index 2600832..c2499f5 100644
--- a/pingora-proxy/tests/test_upstream.rs
+++ b/pingora-proxy/tests/test_upstream.rs
@@ -1373,7 +1373,7 @@ mod test_cache {
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
let headers = res.headers();
- assert_eq!(headers["x-cache-status"], "stale");
+ assert_eq!(headers["x-cache-status"], "stale-updating");
assert_eq!(res.text().await.unwrap(), "hello world");
});
// sleep just a little to make sure the req above gets the cache lock
@@ -1387,7 +1387,7 @@ mod test_cache {
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
let headers = res.headers();
- assert_eq!(headers["x-cache-status"], "stale");
+ assert_eq!(headers["x-cache-status"], "stale-updating");
assert_eq!(res.text().await.unwrap(), "hello world");
});
let task3 = tokio::spawn(async move {
@@ -1399,7 +1399,7 @@ mod test_cache {
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
let headers = res.headers();
- assert_eq!(headers["x-cache-status"], "stale");
+ assert_eq!(headers["x-cache-status"], "stale-updating");
assert_eq!(res.text().await.unwrap(), "hello world");
});
@@ -1436,7 +1436,7 @@ mod test_cache {
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
let headers = res.headers();
- assert_eq!(headers["x-cache-status"], "stale");
+ assert_eq!(headers["x-cache-status"], "stale-updating");
assert_eq!(res.text().await.unwrap(), "hello world");
// wait for the background request to finish
diff --git a/pingora-proxy/tests/utils/server_utils.rs b/pingora-proxy/tests/utils/server_utils.rs
index ec1a962..4f03f21 100644
--- a/pingora-proxy/tests/utils/server_utils.rs
+++ b/pingora-proxy/tests/utils/server_utils.rs
@@ -473,6 +473,9 @@ impl ProxyHttp for ExampleProxyCache {
CachePhase::Hit => upstream_response.insert_header("x-cache-status", "hit")?,
CachePhase::Miss => upstream_response.insert_header("x-cache-status", "miss")?,
CachePhase::Stale => upstream_response.insert_header("x-cache-status", "stale")?,
+ CachePhase::StaleUpdating => {
+ upstream_response.insert_header("x-cache-status", "stale-updating")?
+ }
CachePhase::Expired => {
upstream_response.insert_header("x-cache-status", "expired")?
}