Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple mbtiles and martin-cp fixes #1083

Merged
merged 2 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion martin-tile-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ lints.workspace = true

[package]
name = "martin-tile-utils"
version = "0.3.0"
version = "0.3.1"
authors = ["Yuri Astrakhan <YuriAstrakhan@gmail.com>", "MapLibre contributors"]
description = "Utilites to help with map tile processing, such as type and compression detection. Used by the MapLibre's Martin tile server."
keywords = ["maps", "tiles", "mvt", "tileserver"]
Expand Down
14 changes: 14 additions & 0 deletions martin-tile-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ impl Format {
})
}

/// Get the `format` value as it should be stored in the `MBTiles` metadata table
#[must_use]
pub fn metadata_format_value(&self) -> &'static str {
match *self {
Self::Gif => "gif",
Self::Jpeg => "jpeg",
Self::Json => "json",
// QGIS uses `pbf` instead of `mvt` for some reason
Self::Mvt => "pbf",
Self::Png => "png",
Self::Webp => "webp",
}
}

#[must_use]
pub fn content_type(&self) -> &str {
match *self {
Expand Down
37 changes: 24 additions & 13 deletions martin/src/bin/martin-cp.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::fmt::{Debug, Display, Formatter};
use std::path::PathBuf;
use std::sync::atomic::{AtomicU64, Ordering};
Expand Down Expand Up @@ -153,20 +154,12 @@ async fn start(copy_args: CopierArgs) -> MartinCpResult<()> {

fn compute_tile_ranges(args: &CopyArgs) -> Vec<TileRect> {
let mut ranges = Vec::new();
let mut zooms_vec = Vec::new();
let zooms = if let Some(max_zoom) = args.max_zoom {
let min_zoom = args.min_zoom.unwrap_or(0);
zooms_vec.extend(min_zoom..=max_zoom);
&zooms_vec
} else {
&args.zoom_levels
};
let boxes = if args.bbox.is_empty() {
vec![Bounds::MAX_TILED]
} else {
args.bbox.clone()
};
for zoom in zooms {
for zoom in get_zooms(args).iter() {
for bbox in &boxes {
let (min_x, min_y, max_x, max_y) =
bbox_to_xyz(bbox.left, bbox.bottom, bbox.right, bbox.top, *zoom);
Expand All @@ -179,6 +172,17 @@ fn compute_tile_ranges(args: &CopyArgs) -> Vec<TileRect> {
ranges
}

fn get_zooms(args: &CopyArgs) -> Cow<Vec<u8>> {
if let Some(max_zoom) = args.max_zoom {
let mut zooms_vec = Vec::new();
let min_zoom = args.min_zoom.unwrap_or(0);
zooms_vec.extend(min_zoom..=max_zoom);
Cow::Owned(zooms_vec)
} else {
Cow::Borrowed(&args.zoom_levels)
}
}

struct TileXyz {
xyz: TileCoord,
data: TileData,
Expand Down Expand Up @@ -281,7 +285,7 @@ async fn run_tile_copy(args: CopyArgs, state: ServerState) -> MartinCpResult<()>
} else {
CopyDuplicateMode::Override
};
let mbt_type = init_schema(&mbt, &mut conn, sources, tile_info, args.mbt_type).await?;
let mbt_type = init_schema(&mbt, &mut conn, sources, tile_info, &args).await?;
let query = args.url_query.as_deref();
let req = TestRequest::default()
.insert_header((ACCEPT_ENCODING, args.encoding.as_str()))
Expand Down Expand Up @@ -371,10 +375,10 @@ async fn init_schema(
conn: &mut SqliteConnection,
sources: &[&dyn Source],
tile_info: TileInfo,
mbt_type: Option<MbtTypeCli>,
args: &CopyArgs,
) -> Result<MbtType, MartinError> {
Ok(if is_empty_database(&mut *conn).await? {
let mbt_type = match mbt_type.unwrap_or(MbtTypeCli::Normalized) {
let mbt_type = match args.mbt_type.unwrap_or(MbtTypeCli::Normalized) {
MbtTypeCli::Flat => MbtType::Flat,
MbtTypeCli::FlatWithHash => MbtType::FlatWithHash,
MbtTypeCli::Normalized => MbtType::Normalized { hash_view: true },
Expand All @@ -383,12 +387,19 @@ async fn init_schema(
let mut tj = merge_tilejson(sources, String::new());
tj.other.insert(
"format".to_string(),
serde_json::Value::String(tile_info.format.to_string()),
serde_json::Value::String(tile_info.format.metadata_format_value().to_string()),
);
tj.other.insert(
"generator".to_string(),
serde_json::Value::String(format!("martin-cp v{VERSION}")),
);
let zooms = get_zooms(args);
if let Some(min_zoom) = zooms.iter().min() {
tj.minzoom = Some(*min_zoom);
}
if let Some(max_zoom) = zooms.iter().max() {
tj.maxzoom = Some(*max_zoom);
}
mbt.insert_metadata(&mut *conn, &tj).await?;
mbt_type
} else {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion mbtiles/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ lints.workspace = true

[package]
name = "mbtiles"
version = "0.8.4"
version = "0.8.5"
authors = ["Yuri Astrakhan <YuriAstrakhan@gmail.com>", "MapLibre contributors"]
description = "A simple low-level MbTiles access and processing library, with some tile format detection and other relevant heuristics."
keywords = ["mbtiles", "maps", "tiles", "mvt", "tilejson"]
Expand Down
10 changes: 10 additions & 0 deletions mbtiles/src/bin/mbtiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ enum Commands {
/// Diff file
diff_file: PathBuf,
},
/// Update metadata to match the content of the file
#[command(name = "meta-update", alias = "update-meta")]
UpdateMetadata {
/// MBTiles file to validate
file: PathBuf,
},
/// Validate tile data if hash of tile data exists in file
#[command(name = "validate", alias = "check", alias = "verify")]
Validate {
Expand Down Expand Up @@ -173,6 +179,10 @@ async fn main_int() -> anyhow::Result<()> {
} => {
apply_patch(src_file, diff_file).await?;
}
Commands::UpdateMetadata { file } => {
let mbt = Mbtiles::new(file.as_path())?;
mbt.update_metadata().await?;
}
Commands::Validate {
file,
integrity_check,
Expand Down
2 changes: 2 additions & 0 deletions mbtiles/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ pub use queries::*;

mod summary;

mod update;

mod validation;
pub use validation::{
calc_agg_tiles_hash, AggHashType, IntegrityCheckType, MbtType, AGG_TILES_HASH,
Expand Down
33 changes: 33 additions & 0 deletions mbtiles/src/update.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use log::info;
use sqlx::query;

use crate::errors::MbtResult;
use crate::Mbtiles;

impl Mbtiles {
pub async fn update_metadata(&self) -> MbtResult<()> {
let mut conn = self.open().await?;

let info = query!(
"
SELECT min(zoom_level) AS min_zoom,
max(zoom_level) AS max_zoom
FROM tiles"
)
.fetch_one(&mut conn)
.await?;

if let Some(min_zoom) = info.min_zoom {
info!("Updating minzoom to {min_zoom}");
self.set_metadata_value(&mut conn, "minzoom", &min_zoom)
.await?;
}
if let Some(max_zoom) = info.max_zoom {
info!("Updating maxzoom to {max_zoom}");
self.set_metadata_value(&mut conn, "maxzoom", &max_zoom)
.await?;
}

Ok(())
}
}
10 changes: 10 additions & 0 deletions mbtiles/tests/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,16 @@ fn databases() -> Databases {
})
}

#[actix_rt::test]
async fn update() -> MbtResult<()> {
let (mbt, mut cn) = new_file_no_hash!(databases, Flat, METADATA_V1, TILES_V1, "update");
mbt.update_metadata().await?;
let dmp = dump(&mut cn).await?;
assert_snapshot!(&dmp, "update");

Ok(())
}

#[rstest]
#[trace]
#[actix_rt::test]
Expand Down
51 changes: 51 additions & 0 deletions mbtiles/tests/snapshots/copy__update@update.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
source: mbtiles/tests/copy.rs
expression: actual_value
---
[[]]
type = 'table'
tbl_name = 'metadata'
sql = '''
CREATE TABLE metadata (
name text NOT NULL PRIMARY KEY,
value text)'''
values = [
'( "maxzoom", "6" )',
'( "md-edit", "value - v1" )',
'( "md-remove", "value - remove" )',
'( "md-same", "value - same" )',
'( "minzoom", "3" )',
]

[[]]
type = 'table'
tbl_name = 'tiles'
sql = '''
CREATE TABLE tiles (
zoom_level integer NOT NULL,
tile_column integer NOT NULL,
tile_row integer NOT NULL,
tile_data blob,
PRIMARY KEY(zoom_level, tile_column, tile_row))'''
values = [
'( 3, 6, 7, blob(root) )',
'( 5, 0, 0, blob(same) )',
'( 5, 0, 1, blob() )',
'( 5, 1, 1, blob(edit-v1) )',
'( 5, 1, 2, blob() )',
'( 5, 1, 3, blob(non-empty) )',
'( 5, 2, 2, blob(remove) )',
'( 5, 2, 3, blob() )',
'( 6, 0, 3, blob(same) )',
'( 6, 0, 5, blob(1-keep-1-rm) )',
'( 6, 1, 4, blob(edit-v1) )',
'( 6, 2, 6, blob(1-keep-1-rm) )',
]

[[]]
type = 'index'
tbl_name = 'metadata'

[[]]
type = 'index'
tbl_name = 'tiles'
4 changes: 3 additions & 1 deletion tests/expected/martin-cp/flat-with-hash_metadata.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ tilejson:
tilejson: 3.0.0
tiles: []
description: public.function_zxy_query_test
maxzoom: 6
minzoom: 0
name: function_zxy_query_test
format: mvt
format: pbf
generator: martin-cp v0.0.0
agg_tiles_hash: 9B931A386D6075D1DA55323BD4DBEDAE

4 changes: 3 additions & 1 deletion tests/expected/martin-cp/flat_metadata.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ tilejson:
- -1.0
- 142.84131509869133
- 45.0
maxzoom: 6
minzoom: 0
name: table_source
foo: '{"bar":"foo"}'
format: mvt
format: pbf
generator: martin-cp v0.0.0
agg_tiles_hash: EF19FCBCE73ADE1C85E856E6BBA9B4C7

Loading
Loading