Files
modrinth/packages/xredis/src/key.rs
T
François-Xavier Talbot b4d681e713 feat(labrinth): Redis Cluster (#6771)
* chore(labrinth): bump to redis 1.4.1

* feat(labrinth): redis cluster

* chore: cleanup

* feat(labrinth): cache locking

* fix(labrinth): clippy

* chore(labrinth): cleanup env, remove postcard support

* chore(ci): fix test env for labrinth

* chore(labrinth): bump all key versions

* chore(labrinth): improve redis key identities handling

* chore(labrinth): simplify deadline handling

* chore(labrinth): remove unused lease tracking

* chore(labrinth): remove distributed cache locking for now

* chore(labrinth): improve redis backend init error

* feat(labrinth): expose redis read replica strategy

* chore(ci): remove other connection mode tests

* chore: split xredis crate

* feat(xredis): primaries routing

* chore: tombi fmt

* chore: clippy

* chore: update query cache
2026-07-23 11:35:02 +02:00

76 lines
2.0 KiB
Rust

use std::fmt::Display;
use std::sync::Arc;
use crate::RedisTopology;
#[derive(Debug, Clone)]
pub struct KeyBuilder {
meta_namespace: Arc<str>,
mode: RedisTopology,
}
impl KeyBuilder {
pub fn new(
meta_namespace: impl Into<Arc<str>>,
mode: RedisTopology,
) -> Self {
Self {
meta_namespace: meta_namespace.into(),
mode,
}
}
/// Build a key with the given namespace and logical key. The logical key is used as the key's slot tag.
pub fn entity(&self, namespace: &str, logical_key: impl Display) -> String {
let logical_key = logical_key.to_string();
self.with_slot(namespace, &logical_key, &logical_key)
}
/// Build a metadata key with the given namespace and logical key. The slot tag is fixed to `_metadata`.
pub fn metadata(
&self,
namespace: &str,
logical_key: impl Display,
) -> String {
self.with_slot(namespace, logical_key, "_metadata")
}
/// Build a key with the given namespace, logical key, and slot tag.
pub fn with_slot(
&self,
namespace: &str,
logical_key: impl Display,
slot_tag: impl Display,
) -> String {
match self.mode {
RedisTopology::Standalone => {
format!("{}_{}:{}", self.meta_namespace, namespace, logical_key)
}
RedisTopology::Cluster => format!(
"{}_{}:{{{}}}:{}",
self.meta_namespace,
namespace,
escape_slot_tag(&slot_tag.to_string()),
logical_key
),
}
}
}
fn escape_slot_tag(value: &str) -> String {
if value.is_empty() {
return "%00".to_string();
}
let mut escaped = String::with_capacity(value.len());
for character in value.chars() {
match character {
'%' => escaped.push_str("%25"),
'{' => escaped.push_str("%7B"),
'}' => escaped.push_str("%7D"),
_ => escaped.push(character),
}
}
escaped
}