ceph_safe_disk/
pgmap.rs

1use serde_json::Value;
2
3// See `src/mon/PGMap.h` in ceph's source
4#[derive(Deserialize, Debug, PartialEq, Clone)]
5pub struct PGMap {
6    pub osd_stats_sum: OsdStatsSum,
7    pub pg_stats_delta: PgStatsDelta,
8    pub min_last_epoch_clean: Option<i32>,
9    pub stamp: String,
10    pub pg_stats_sum: PgStatsSum,
11    pub last_pg_scan: i32,
12    pub full_ratio: Option<Value>,
13    pub pool_stats: Vec<PoolStats>,
14    pub version: i32,
15    pub last_osdmap_epoch: i32,
16    pub near_full_ratio: Option<Value>,
17    pub osd_stats: Vec<OsdStats>,
18    pub pg_stats: Vec<PgStats>,
19}
20
21#[derive(Deserialize, Debug, PartialEq, Clone)]
22pub struct OsdStats {
23    pub snap_trim_queue_len: i32,
24    pub kb: i32,
25    pub fs_perf_stat: Option<FsPerfStat>,
26    pub hb_in: Option<Vec<i32>>,
27    pub num_snap_trimming: i32,
28    pub hb_out: Option<Vec<i32>>,
29    pub kb_avail: i32,
30    pub kb_used: i32,
31    pub op_queue_age_hist: OpQueueAgeHist,
32    pub osd: i32,
33}
34
35#[derive(Deserialize, Debug, PartialEq, Clone)]
36pub struct PgStatsDelta {
37    pub acting: Option<i32>,
38    pub log_size: i32,
39    pub ondisk_log_size: i32,
40    pub stat_sum: StatSum,
41    pub up: Option<i32>,
42}
43
44#[derive(Deserialize, Debug, PartialEq, Clone)]
45pub struct StatSum {
46    pub num_evict: Option<i32>,
47    pub num_evict_kb: Option<i32>,
48    pub num_bytes_hit_set_archive: Option<i32>,
49    pub num_whiteouts: i32,
50    pub num_objects_pinned: Option<i32>,
51    pub num_scrub_errors: i32,
52    pub num_evict_mode_full: Option<i32>,
53    pub num_read: i32,
54    pub num_objects_recovered: i32,
55    pub num_objects_omap: i32,
56    pub num_objects_missing_on_primary: i32,
57    pub num_write: i32,
58    pub num_object_clones: i32,
59    pub num_objects: i32,
60    pub num_deep_scrub_errors: i32,
61    pub num_shallow_scrub_errors: i32,
62    pub num_read_kb: i32,
63    pub num_objects_missing: Option<i32>,
64    pub num_flush_kb: Option<i32>,
65    pub num_flush_mode_high: Option<i32>,
66    pub num_write_kb: i32,
67    pub num_evict_mode_some: Option<i32>,
68    pub num_objects_degraded: i32,
69    pub num_flush: Option<i32>,
70    pub num_objects_misplaced: Option<i32>,
71    pub num_bytes_recovered: i32,
72    pub num_objects_hit_set_archive: i32,
73    pub num_keys_recovered: i32,
74    pub num_flush_mode_low: Option<i32>,
75    pub num_objects_unfound: i32,
76    pub num_promote: Option<i32>,
77    pub num_object_copies: i32,
78    pub num_bytes: i32,
79    pub num_objects_dirty: i32,
80}
81
82#[derive(Deserialize, Debug, PartialEq, Clone)]
83pub struct PgStatsSum {
84    pub acting: Option<i32>,
85    pub log_size: i32,
86    pub ondisk_log_size: i32,
87    pub stat_sum: StatSum,
88    pub up: Option<i32>,
89}
90
91#[derive(Deserialize, Debug, PartialEq, Clone)]
92pub struct OsdStatsSum {
93    pub snap_trim_queue_len: i32,
94    pub kb: i32,
95    pub fs_perf_stat: Option<FsPerfStat>,
96    pub hb_in: Option<Vec<i32>>,
97    pub num_snap_trimming: i32,
98    pub hb_out: Option<Vec<i32>>,
99    pub kb_avail: i32,
100    pub kb_used: i32,
101    pub op_queue_age_hist: OpQueueAgeHist,
102}
103
104#[derive(Deserialize, Debug, PartialEq, Clone)]
105pub struct OpQueueAgeHist {
106    pub upper_bound: i32,
107    pub histogram: Vec<i32>,
108}
109
110#[derive(Deserialize, Debug, PartialEq, Clone)]
111pub struct FsPerfStat {
112    pub apply_latency_ms: i32,
113    pub commit_latency_ms: i32,
114}
115
116#[derive(Deserialize, Debug, PartialEq, Clone)]
117pub struct PoolStats {
118    pub log_size: i32,
119    pub ondisk_log_size: i32,
120    pub up: Option<i32>,
121    pub acting: Option<i32>,
122    pub poolid: i32,
123    pub stat_sum: StatSum,
124}
125
126#[derive(Deserialize, Debug, PartialEq, Clone)]
127pub struct PgStats {
128    pub last_scrub: String,
129    pub last_clean_scrub_stamp: String,
130    pub parent_split_bits: i32,
131    pub last_active: String,
132    pub pin_stats_invalid: Option<bool>,
133    pub reported_epoch: String,
134    pub log_start: String,
135    pub log_size: i32,
136    pub hitset_stats_invalid: Option<bool>,
137    pub stats_invalid: Value,
138    pub acting_primary: i32,
139    pub reported_seq: String,
140    pub ondisk_log_size: i32,
141    pub mapping_epoch: i32,
142    pub dirty_stats_invalid: Option<bool>,
143    pub state: String,
144    pub version: String,
145    pub last_became_peered: Option<String>,
146    pub last_undegraded: Option<String>,
147    pub pgid: String,
148    pub parent: String,
149    pub acting: Vec<i32>,
150    pub up_primary: i32,
151    pub last_fullsized: Option<String>,
152    pub last_epoch_clean: i32,
153    pub last_deep_scrub_stamp: String,
154    pub stat_sum: StatSum,
155    pub last_deep_scrub: String,
156    pub last_fresh: String,
157    pub last_scrub_stamp: String,
158    pub created: i32,
159    pub up: Vec<i32>,
160    pub hitset_bytes_stats_invalid: Option<bool>,
161    pub last_peered: Option<String>,
162    pub last_became_active: String,
163    pub omap_stats_invalid: Option<bool>,
164    pub last_clean: String,
165    pub last_unstale: String,
166    pub last_change: String,
167    pub blocked_by: Option<Vec<i32>>,
168    pub ondisk_log_start: String,
169}
170
171#[cfg(test)]
172mod tests {
173    use super::PGMap;
174    use crate::from::FromFile;
175
176    // Jewel tests
177    #[test]
178    #[should_panic]
179    fn pgmap_from_jewel_file_panic() {
180        let pgmap = PGMap::from_file("test/jewel/pg_dump_safe.json").unwrap();
181        // An OSD is safe to remove so up should not be 0
182        assert_eq!(pgmap.pg_stats.first().unwrap().up.len(), 0);
183    }
184
185    #[test]
186    fn pgmap_from_jewel_file() {
187        let pgmap = PGMap::from_file("test/jewel/pg_dump_safe.json").unwrap();
188        // First pg_stat.up should be length 3
189        assert_eq!(pgmap.pg_stats.first().unwrap().up.len() as i32, 3);
190    }
191
192    #[test]
193    #[should_panic]
194    fn pgmap_from_jewel_file_no_osd_panic() {
195        let pgmap = PGMap::from_file("test/jewel/pg_dump_no_osd.json").unwrap();
196        // First pg_stat.state should be "creating" since there are no OSDs
197        assert_eq!(
198            pgmap.pg_stats.first().unwrap().state,
199            "active+clean".to_owned()
200        );
201    }
202
203    #[test]
204    fn pgmap_from_jewel_file_no_osd() {
205        let pgmap = PGMap::from_file("test/jewel/pg_dump_no_osd.json").unwrap();
206        // First pg_stat.up should be length 0
207        assert_eq!(pgmap.pg_stats.first().unwrap().up.len() as i32, 0);
208    }
209
210    #[test]
211    fn pgmap_from_jewel_file_non_safe() {
212        let pgmap = PGMap::from_file("test/jewel/pg_dump_non_safe.json").unwrap();
213        // Up should be 2 as to not meet min_size + 1, as such acting should be 2
214        assert_eq!(pgmap.pg_stats.first().unwrap().up.len() as i32, 2);
215        assert_eq!(pgmap.pg_stats.first().unwrap().acting.len() as i32, 2);
216    }
217
218    #[test]
219    #[should_panic]
220    fn pgmap_from_jewel_file_non_safe_panic() {
221        let pgmap = PGMap::from_file("test/jewel/pg_dump_non_safe.json").unwrap();
222        assert_eq!(pgmap.pg_stats.first().unwrap().up.len() as i32, 3);
223    }
224
225    // Firefly tests
226    #[test]
227    fn pgmap_from_firefly_file() {
228        let pgmap = PGMap::from_file("test/firefly/pg_dump_safe.json").unwrap();
229        assert_eq!(pgmap.pg_stats.first().unwrap().up.len() as i32, 3);
230    }
231
232    #[test]
233    #[should_panic]
234    fn pgmap_from_firefly_file_panic() {
235        let pgmap = PGMap::from_file("test/firefly/pg_dump_safe.json").unwrap();
236        assert_eq!(pgmap.pg_stats.first().unwrap().acting.len() as i32, 0);
237    }
238
239    #[test]
240    #[should_panic]
241    fn pgmap_from_ceph_panic() {
242        use crate::from::FromCeph;
243        let pgmap = PGMap::from_ceph("pg dump");
244        assert_eq!(pgmap.is_ok(), true);
245    }
246}