1use rusqlite::Connection;
2use serde::{Deserialize, Serialize};
3use tracing::debug;
4
5use crate::errors::UtilesResult;
6use crate::mbt::MbtType;
7use crate::mbt::mbtiles::{zoom_stats, zoom_stats_full};
8use crate::mbt::query::query_mbtiles_type;
9use crate::sqlite::{pragma_freelist_count, pragma_page_count, pragma_page_size};
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct MbtilesZoomStats {
13 pub zoom: u32,
14 pub ntiles: u64,
15 pub xmin: u32,
16 pub xmax: u32,
17 pub ymin: u32,
18 pub ymax: u32,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub nbytes: Option<u64>,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub nbytes_avg: Option<f64>,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct MbtilesStats {
27 pub filesize: u64,
28 pub mbtype: MbtType,
29 pub ntiles: u64,
30 pub nzooms: u32,
31 pub page_count: i64,
32 pub page_size: i64,
33 pub freelist_count: i64,
34 pub minzoom: Option<u32>,
35 pub maxzoom: Option<u32>,
36 pub zooms: Vec<MbtilesZoomStats>,
37}
38
39pub fn query_mbt_stats(
40 conn: &Connection,
41 full: Option<bool>,
42) -> UtilesResult<MbtilesStats> {
43 let query_ti = std::time::Instant::now();
44 let maybe_filepath = conn.path().map(|p| p.to_string());
45 let filesize = match maybe_filepath {
46 Some(fp) => std::fs::metadata(fp).map(|md| md.len()).unwrap_or(0),
47 None => 0,
48 };
49
50 debug!("Started zoom_stats query");
52 let page_count = pragma_page_count(conn)?;
53
54 let page_size = pragma_page_size(conn, None)?;
55 let freelist_count = pragma_freelist_count(conn)?;
56 let zoom_stats =
60 if full.unwrap_or(false) || (filesize < 10_000_000_000 && filesize > 0) {
61 zoom_stats_full(conn)?
62 } else {
63 zoom_stats(conn)?
64 };
65 debug!("zoom_stats: {:?}", zoom_stats);
66 let query_dt = query_ti.elapsed();
67 debug!("Finished zoom_stats query in {:?}", query_dt);
68 let mbt_type = query_mbtiles_type(conn)?;
69 if zoom_stats.is_empty() {
70 return Ok(MbtilesStats {
71 filesize,
72 mbtype: mbt_type,
73 page_count,
74 page_size,
75 freelist_count,
76 ntiles: 0,
77 minzoom: None,
78 maxzoom: None,
79 nzooms: 0,
80 zooms: vec![],
81 });
82 }
83
84 let minzoom = zoom_stats.iter().map(|r| r.zoom).min();
85 let maxzoom = zoom_stats.iter().map(|r| r.zoom).max();
86 Ok(MbtilesStats {
87 ntiles: zoom_stats.iter().map(|r| r.ntiles).sum(),
88 filesize,
89 mbtype: mbt_type,
90 page_count,
91 page_size,
92 freelist_count,
93 minzoom,
94 maxzoom,
95 nzooms: zoom_stats.len() as u32,
96 zooms: zoom_stats,
97 })
98}