Skip to main content

ferripfs_config/
datastore.rs

1// Ported from: kubo/config/datastore.go
2// Kubo version: v0.39.0
3// Original: https://github.com/ipfs/kubo/blob/v0.39.0/config/datastore.go
4//
5// Original work: Copyright (c) Protocol Labs, Inc.
6// Port: Copyright (c) 2026 ferripfs contributors
7// SPDX-License-Identifier: MIT OR Apache-2.0
8
9//! Datastore configuration.
10
11use crate::{Flag, OptionalInteger};
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14
15/// Default datastore directory name
16pub const DEFAULT_DATASTORE_DIRECTORY: &str = "datastore";
17
18/// Default blocks directory name
19pub const DEFAULT_BLOCKS_DIRECTORY: &str = "blocks";
20
21/// Default storage maximum
22pub const DEFAULT_STORAGE_MAX: &str = "10GB";
23
24/// Default GC watermark (percentage)
25pub const DEFAULT_STORAGE_GC_WATERMARK: i64 = 90;
26
27/// Default GC period
28pub const DEFAULT_GC_PERIOD: &str = "1h";
29
30/// Datastore configuration section
31#[derive(Debug, Clone, Default, Serialize, Deserialize)]
32#[serde(rename_all = "PascalCase")]
33pub struct Datastore {
34    /// Maximum storage size (e.g., "10GB")
35    #[serde(default)]
36    pub storage_max: String,
37
38    /// GC watermark percentage (0-100)
39    #[serde(default, rename = "StorageGCWatermark")]
40    pub storage_gc_watermark: i64,
41
42    /// GC period (e.g., "1h")
43    #[serde(default, rename = "GCPeriod")]
44    pub gc_period: String,
45
46    /// Datastore specification (type-dependent configuration)
47    #[serde(default)]
48    pub spec: HashMap<String, serde_json::Value>,
49
50    /// Whether to verify block hashes on read
51    #[serde(default)]
52    pub hash_on_read: bool,
53
54    /// Bloom filter size for blockstore
55    #[serde(default)]
56    pub bloom_filter_size: i32,
57
58    /// Block key cache size
59    #[serde(default, skip_serializing_if = "Option::is_none")]
60    pub block_key_cache_size: Option<OptionalInteger>,
61
62    /// Whether to write through cache
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub write_through: Option<Flag>,
65}
66
67impl Datastore {
68    /// Create default datastore configuration
69    pub fn default_config() -> Self {
70        Self {
71            storage_max: DEFAULT_STORAGE_MAX.to_string(),
72            storage_gc_watermark: DEFAULT_STORAGE_GC_WATERMARK,
73            gc_period: DEFAULT_GC_PERIOD.to_string(),
74            spec: Self::default_spec(),
75            hash_on_read: false,
76            bloom_filter_size: 0,
77            block_key_cache_size: None,
78            write_through: None,
79        }
80    }
81
82    /// Get the default FlatFS datastore spec
83    pub fn default_spec() -> HashMap<String, serde_json::Value> {
84        let mut spec = HashMap::new();
85        spec.insert("type".to_string(), serde_json::json!("mount"));
86        spec.insert(
87            "mounts".to_string(),
88            serde_json::json!([
89                {
90                    "mountpoint": "/blocks",
91                    "type": "measure",
92                    "prefix": "flatfs.datastore",
93                    "child": {
94                        "type": "flatfs",
95                        "path": "blocks",
96                        "sync": true,
97                        "shardFunc": "/repo/flatfs/shard/v1/next-to-last/2"
98                    }
99                },
100                {
101                    "mountpoint": "/",
102                    "type": "measure",
103                    "prefix": "leveldb.datastore",
104                    "child": {
105                        "type": "levelds",
106                        "path": "datastore",
107                        "compression": "none"
108                    }
109                }
110            ]),
111        );
112        spec
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn test_datastore_defaults() {
122        let ds = Datastore::default_config();
123        assert_eq!(ds.storage_max, "10GB");
124        assert_eq!(ds.storage_gc_watermark, 90);
125    }
126
127    #[test]
128    fn test_default_spec() {
129        let spec = Datastore::default_spec();
130        assert!(spec.contains_key("type"));
131        assert!(spec.contains_key("mounts"));
132    }
133}