Skip to main content

opendal_service_foyer/
config.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use serde::Deserialize;
19use serde::Serialize;
20
21use super::backend::FoyerBuilder;
22use opendal_core::{Configurator, OperatorUri, Result};
23
24/// Config for Foyer services support.
25#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
26#[serde(default)]
27#[non_exhaustive]
28pub struct FoyerConfig {
29    /// Name for this cache instance.
30    pub name: Option<String>,
31    /// Root path of this backend.
32    pub root: Option<String>,
33    /// Memory capacity in bytes for the cache.
34    pub memory: Option<usize>,
35    /// Disk cache directory path.
36    ///
37    /// If set, enables hybrid cache with disk storage. Data will be persisted to
38    /// this directory when memory cache is full.
39    pub disk_path: Option<String>,
40    /// Disk cache total capacity in bytes.
41    /// Only used when `disk_path` is set.
42    pub disk_capacity: Option<usize>,
43    /// Individual cache file size in bytes.
44    ///
45    /// Default is 1 MiB.
46    /// Only used when `disk_path` is set.
47    pub disk_file_size: Option<usize>,
48    /// Recovery mode when starting the cache.
49    ///
50    /// Valid values: "none" (default), "quiet", "strict".
51    /// - "none": Don't recover from disk
52    /// - "quiet": Recover and skip errors
53    /// - "strict": Recover and panic on errors
54    pub recover_mode: Option<String>,
55    /// Number of shards for concurrent access.
56    ///
57    /// Default is 1. Higher values improve concurrency but increase overhead.
58    pub shards: Option<usize>,
59}
60
61impl Configurator for FoyerConfig {
62    type Builder = FoyerBuilder;
63
64    fn from_uri(uri: &OperatorUri) -> Result<Self> {
65        let mut map = uri.options().clone();
66
67        if let Some(name) = uri.option("name") {
68            map.insert("name".to_string(), name.to_string());
69        }
70
71        if let Some(root) = uri.root()
72            && !root.is_empty()
73        {
74            map.insert("root".to_string(), root.to_string());
75        }
76
77        Self::from_iter(map)
78    }
79
80    fn into_builder(self) -> Self::Builder {
81        FoyerBuilder {
82            config: self,
83            ..Default::default()
84        }
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn test_from_uri_sets_memory() {
94        let uri = OperatorUri::new(
95            "foyer:///cache?name=test&memory=67108864",
96            Vec::<(String, String)>::new(),
97        )
98        .unwrap();
99
100        let cfg = FoyerConfig::from_uri(&uri).unwrap();
101        assert_eq!(cfg.name.as_deref(), Some("test"));
102        assert_eq!(cfg.root.as_deref(), Some("cache"));
103        assert_eq!(cfg.memory, Some(64 * 1024 * 1024));
104    }
105
106    #[test]
107    fn test_from_uri_sets_name_and_root() {
108        let uri =
109            OperatorUri::new("foyer:///data?name=session", Vec::<(String, String)>::new()).unwrap();
110
111        let cfg = FoyerConfig::from_uri(&uri).unwrap();
112        assert_eq!(cfg.name.as_deref(), Some("session"));
113        assert_eq!(cfg.root.as_deref(), Some("data"));
114    }
115
116    #[test]
117    fn test_from_uri_sets_disk_config() {
118        let uri = OperatorUri::new(
119            "foyer:///cache?memory=67108864&disk_path=/tmp/foyer&disk_capacity=1073741824&disk_file_size=2097152",
120            Vec::<(String, String)>::new(),
121        )
122        .unwrap();
123
124        let cfg = FoyerConfig::from_uri(&uri).unwrap();
125        assert_eq!(cfg.memory, Some(64 * 1024 * 1024));
126        assert_eq!(cfg.disk_path.as_deref(), Some("/tmp/foyer"));
127        assert_eq!(cfg.disk_capacity, Some(1024 * 1024 * 1024));
128        assert_eq!(cfg.disk_file_size, Some(2 * 1024 * 1024));
129    }
130
131    #[test]
132    fn test_from_uri_sets_recovery_and_shards() {
133        let uri = OperatorUri::new(
134            "foyer:///?recover_mode=quiet&shards=4",
135            Vec::<(String, String)>::new(),
136        )
137        .unwrap();
138
139        let cfg = FoyerConfig::from_uri(&uri).unwrap();
140        assert_eq!(cfg.recover_mode.as_deref(), Some("quiet"));
141        assert_eq!(cfg.shards, Some(4));
142    }
143}