1use crate::cli_utils::*;
2use crate::file_utils;
3use crate::json_printer::BracketType;
4use crate::sbx_specs::{ver_to_block_size, ver_to_data_size, ver_to_usize, ver_uses_rs};
5use clap::*;
6use std::str::FromStr;
7
8pub fn sub_command<'a, 'b>() -> App<'a, 'b> {
9 SubCommand::with_name("calc")
10 .about("Calculate and display detailed information given an encoding configuration")
11 .arg(
12 Arg::with_name("in_file_size")
13 .value_name("INFILE-SIZE")
14 .required(true)
15 .index(1)
16 .help("Input file size"),
17 )
18 .arg(sbx_version_arg())
19 .arg(Arg::with_name("no_meta").long("no-meta").help(
20 "Skip metadata block in the calculations. Metadata block is
21never skipped for version 17, 18, 19.
22This means this option has no effect for version 17, 18, 19.",
23 ))
24 .arg(rs_data_arg())
25 .arg(rs_parity_arg())
26 .arg(burst_arg())
27 .arg(json_arg())
28}
29
30pub fn calc<'a>(matches: &ArgMatches<'a>) -> i32 {
31 let json_printer = get_json_printer!(matches);
32
33 json_printer.print_open_bracket(None, BracketType::Curly);
34
35 let (version, data_par_burst) = get_ver_and_data_par_burst_w_defaults!(matches, json_printer);
36
37 let meta_enabled = Some(get_meta_enabled!(matches));
38
39 let in_file_size = match u64::from_str(matches.value_of("in_file_size").unwrap()) {
40 Ok(x) => x,
41 Err(_) => exit_with_msg!(usr json_printer => "Invalid file size"),
42 };
43
44 let out_file_size = file_utils::from_orig_file_size::calc_container_size(
45 version,
46 meta_enabled,
47 data_par_burst,
48 in_file_size,
49 );
50
51 let total_block_count = file_utils::from_orig_file_size::calc_total_block_count_exc_burst_gaps(
52 version,
53 meta_enabled,
54 data_par_burst,
55 in_file_size,
56 );
57
58 let meta_block_count =
59 file_utils::calc_meta_block_count_exc_burst_gaps(version, meta_enabled, data_par_burst);
60
61 let (data_only_block_count, parity_block_count) =
62 file_utils::from_orig_file_size::calc_data_only_and_parity_block_count_exc_burst_gaps(
63 version,
64 data_par_burst,
65 in_file_size,
66 );
67
68 json_printer.print_open_bracket(Some("stats"), BracketType::Curly);
69
70 print_if!(not_json => json_printer =>
71 "SBX container general info";
72 "========================================";);
73 if ver_uses_rs(version) {
74 print_maybe_json!(
75 json_printer,
76 " SBX container version : {}",
77 ver_to_usize(version)
78 );
79 } else {
80 print_maybe_json!(
81 json_printer,
82 " SBX container version : {}",
83 ver_to_usize(version)
84 );
85 }
86 print_maybe_json!(
87 json_printer,
88 " SBX container block size : {}",
89 ver_to_block_size(version)
90 );
91 print_maybe_json!(
92 json_printer,
93 " SBX container data size : {}",
94 ver_to_data_size(version)
95 );
96
97 print_if!(not_json => json_printer => "";);
98
99 print_if!(not_json => json_printer => "SBX block distribution";);
100 print_if!(not_json => json_printer => "========================================";);
101 if ver_uses_rs(version) {
102 print_maybe_json!(
103 json_printer,
104 " Metadata block count : {}",
105 meta_block_count
106 );
107 print_maybe_json!(
108 json_printer,
109 " Data only block count : {}",
110 data_only_block_count
111 );
112 print_maybe_json!(
113 json_printer,
114 " Data parity block count : {}",
115 parity_block_count
116 );
117 print_maybe_json!(
118 json_printer,
119 " Total block count : {}",
120 total_block_count
121 );
122 } else {
123 print_maybe_json!(
124 json_printer,
125 " Metadata block count : {}",
126 meta_block_count
127 );
128 print_maybe_json!(
129 json_printer,
130 " Data block count : {}",
131 data_only_block_count
132 );
133 print_maybe_json!(
134 json_printer,
135 " Total block count : {}",
136 total_block_count
137 );
138 }
139
140 print_if!(not_json => json_printer => "";);
141
142 print_if!(not_json => json_printer => "Error correction info";);
143 print_if!(not_json => json_printer => "========================================";);
144 if ver_uses_rs(version) {
145 print_maybe_json!(
146 json_printer,
147 " RS data shard count : {}",
148 data_par_burst.unwrap().0
149 );
150 print_maybe_json!(
151 json_printer,
152 " RS parity shard count : {}",
153 data_par_burst.unwrap().1
154 );
155 print_maybe_json!(
156 json_printer,
157 " Burst error resistance level : {}",
158 data_par_burst.unwrap().2
159 );
160 } else {
161 print_maybe_json!(
162 json_printer,
163 " RS data shard count : {}",
164 null_if_json_else!(json_printer, "version does not use RS")
165 );
166 print_maybe_json!(
167 json_printer,
168 " RS parity shard count : {}",
169 null_if_json_else!(json_printer, "version does not use RS")
170 );
171 print_maybe_json!(
172 json_printer,
173 " Burst error resistance level : {}",
174 null_if_json_else!(
175 json_printer,
176 "version does not support burst error resistance"
177 )
178 );
179 }
180
181 print_if!(not_json => json_printer => "";);
182
183 if ver_uses_rs(version) && !json_printer.json_enabled() {
184 let (data, par, burst) = data_par_burst.unwrap();
185
186 let block_size = ver_to_block_size(version);
187
188 println!("Error correction parameters interpretation");
189 println!("========================================");
190 if burst == 0 {
191 print_block!(
192 " The container can tolerate {} SBX block corruptions", par;
193 " in each block set.";
194 "";
195 " A block set consists of {} blocks ({} bytes).", (data + par), (data + par) * block_size;
196 "";
197 " In total, {} blocks({} bytes) may be corrupted in", par, par * block_size;
198 " each block set.";
199 );
200 } else {
201 if burst == 1 {
202 print_block!(
203 " Warning :";
204 "";
205 " Burst error resistance level of {} may not provide", burst;
206 " meaningful resistance.";
207 "";
208 );
209 }
210
211 let block_set_size = data + par;
212 let super_block_set_size = (data + par) * burst;
213
214 print_block!(" The container can tolerate {} burst SBX block corruptions in", par;
215 " each super block set ({} interleaved block sets).", burst;
216 "";
217 " A block set consists of {} blocks ({} bytes).", block_set_size, block_set_size * block_size;
218 "";
219 " A super block set consists of {} blocks ({} bytes).", super_block_set_size, super_block_set_size * block_size;
220 "";
221 " Each burst error may be up to {} blocks ({} bytes) in size.", burst, burst * block_size;
222 "";
223 " In total, {} sets of {} consecutive blocks ({} bytes) may be", par, burst, burst * block_size;
224 " corrupted in each super block set.";
225 "";
226 " The sets of corrupted blocks may be connected as well, so the";
227 " largest single burst error that can be tolerated in each super";
228 " block set is {} blocks ({} bytes) in size.", par * burst, par * burst * block_size;
229 "";
230 " Note that the actual tolerance depends on the behaviour of";
231 " the file system.";
232 );
233 }
234
235 println!();
236 }
237
238 print_if!(not_json => json_printer => "File and container size";);
239 print_if!(not_json => json_printer => "========================================";);
240 print_maybe_json!(
241 json_printer,
242 " File size : {}",
243 in_file_size
244 );
245 print_maybe_json!(
246 json_printer,
247 " SBX container size : {}",
248 out_file_size
249 );
250
251 json_printer.print_close_bracket();
252
253 exit_with_msg!(ok json_printer => "")
254}