utiles/mbt/
mbt_stats.rs

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    // let zoom_stats_full = full.unwrap_or(false) || filesize < 10_000_000_000;
51    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    // if the file is over 10gb and full is None or false just don't do the
57    // zoom_stats query that counts size... bc it is slow af
58    // let zoom_stats = self.zoom_stats(zoom_stats_full)?;
59    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}