Skip to content

Commit

Permalink
Rename MartinError, benchmarks, streamline get_tile (#1016)
Browse files Browse the repository at this point in the history
Use MartinError, MartinResult, FileError and FileResult, and other similar enums.
  • Loading branch information
nyurik authored Nov 21, 2023
1 parent 566e8fa commit 0f2cd10
Show file tree
Hide file tree
Showing 35 changed files with 344 additions and 211 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

6 changes: 5 additions & 1 deletion martin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ lints.workspace = true
[package]
name = "martin"
# Once the release is published with the hash, update https://github.com/maplibre/homebrew-martin
version = "0.11.0"
version = "0.11.1"
authors = ["Stepan Kuzmin <[email protected]>", "Yuri Astrakhan <[email protected]>", "MapLibre contributors"]
description = "Blazing fast and lightweight tile server with PostGIS, MBTiles, and PMTiles support"
keywords = ["maps", "tiles", "mbtiles", "pmtiles", "postgis"]
Expand Down Expand Up @@ -54,6 +54,10 @@ path = "src/bin/martin.rs"
name = "martin-cp"
path = "src/bin/martin-cp.rs"

[[bench]]
name = "bench"
harness = false

[features]
default = []
bless-tests = []
Expand Down
73 changes: 73 additions & 0 deletions martin/benches/bench.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use async_trait::async_trait;
use criterion::async_executor::FuturesExecutor;
use criterion::{criterion_group, criterion_main, Criterion};
use martin::srv::get_tile_response;
use martin::{
CatalogSourceEntry, MartinResult, Source, TileCoord, TileData, TileSources, UrlQuery,
};
use martin_tile_utils::{Encoding, Format, TileInfo};
use tilejson::{tilejson, TileJSON};

#[derive(Clone, Debug)]
struct NullSource {
tilejson: TileJSON,
}

impl NullSource {
fn new() -> Self {
Self {
tilejson: tilejson! { "https://example.com/".to_string() },
}
}
}

#[async_trait]
impl Source for NullSource {
fn get_id(&self) -> &str {
"null"
}

fn get_tilejson(&self) -> &TileJSON {
&self.tilejson
}

fn get_tile_info(&self) -> TileInfo {
TileInfo::new(Format::Png, Encoding::Internal)
}

fn clone_source(&self) -> Box<dyn Source> {
Box::new(self.clone())
}

fn support_url_query(&self) -> bool {
false
}

async fn get_tile(
&self,
_xyz: &TileCoord,
_query: &Option<UrlQuery>,
) -> MartinResult<TileData> {
Ok(Vec::new())
}

fn get_catalog_entry(&self) -> CatalogSourceEntry {
CatalogSourceEntry::default()
}
}

async fn process_tile(sources: &TileSources) {
get_tile_response(sources, TileCoord { z: 0, x: 0, y: 0 }, "null", "", None)
.await
.unwrap();
}

fn bench_null_source(c: &mut Criterion) {
let sources = TileSources::new(vec![vec![Box::new(NullSource::new())]]);
c.bench_function("get_table_source_tile", |b| {
b.to_async(FuturesExecutor).iter(|| process_tile(&sources));
});
}

criterion_group!(benches, bench_null_source);
criterion_main!(benches);
6 changes: 3 additions & 3 deletions martin/src/args/connections.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::Error;
use crate::{MartinError, MartinResult};

#[derive(Debug, Clone)]
pub enum State<T: Clone> {
Expand Down Expand Up @@ -58,7 +58,7 @@ impl Arguments {
}

/// Check that all params have been claimed
pub fn check(self) -> Result<(), Error> {
pub fn check(self) -> MartinResult<()> {
let mut unrecognized = Vec::new();
for (i, value) in self.values.into_iter().enumerate() {
if let State::Ignore = self.state[i] {
Expand All @@ -68,7 +68,7 @@ impl Arguments {
if unrecognized.is_empty() {
Ok(())
} else {
Err(Error::UnrecognizableConnections(unrecognized))
Err(MartinError::UnrecognizableConnections(unrecognized))
}
}
}
4 changes: 2 additions & 2 deletions martin/src/args/pg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ mod tests {

use super::*;
use crate::test_utils::{os, some, FauxEnv};
use crate::Error;
use crate::MartinError;

#[test]
fn test_extract_conn_strings() {
Expand All @@ -217,7 +217,7 @@ mod tests {
vec!["postgresql://localhost:5432", "postgres://localhost:5432"]
);
assert!(matches!(args.check(), Err(
Error::UnrecognizableConnections(v)) if v == vec!["mysql://localhost:3306"]));
MartinError::UnrecognizableConnections(v)) if v == vec!["mysql://localhost:3306"]));
}

#[test]
Expand Down
18 changes: 12 additions & 6 deletions martin/src/args/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use crate::args::srv::SrvArgs;
use crate::args::State::{Ignore, Share, Take};
use crate::config::Config;
use crate::file_config::FileConfigEnum;
use crate::{Error, OptOneMany, Result};
use crate::MartinError::ConfigAndConnectionsError;
use crate::{MartinResult, OptOneMany};

#[derive(Parser, Debug, PartialEq, Default)]
#[command(about, version)]
Expand Down Expand Up @@ -57,15 +58,19 @@ pub struct ExtraArgs {
}

impl Args {
pub fn merge_into_config<'a>(self, config: &mut Config, env: &impl Env<'a>) -> Result<()> {
pub fn merge_into_config<'a>(
self,
config: &mut Config,
env: &impl Env<'a>,
) -> MartinResult<()> {
if self.meta.watch {
warn!("The --watch flag is no longer supported, and will be ignored");
}
if env.has_unused_var("WATCH_MODE") {
warn!("The WATCH_MODE env variable is no longer supported, and will be ignored");
}
if self.meta.config.is_some() && !self.meta.connection.is_empty() {
return Err(Error::ConfigAndConnectionsError(self.meta.connection));
return Err(ConfigAndConnectionsError(self.meta.connection));
}

self.srv.merge_into_config(&mut config.srv);
Expand Down Expand Up @@ -122,8 +127,9 @@ mod tests {
use crate::pg::PgConfig;
use crate::test_utils::{some, FauxEnv};
use crate::utils::OptOneMany;
use crate::MartinError::UnrecognizableConnections;

fn parse(args: &[&str]) -> Result<(Config, MetaArgs)> {
fn parse(args: &[&str]) -> MartinResult<(Config, MetaArgs)> {
let args = Args::parse_from(args);
let meta = args.meta.clone();
let mut config = Config::default();
Expand Down Expand Up @@ -188,7 +194,7 @@ mod tests {
let env = FauxEnv::default();
let mut config = Config::default();
let err = args.merge_into_config(&mut config, &env).unwrap_err();
assert!(matches!(err, crate::Error::ConfigAndConnectionsError(..)));
assert!(matches!(err, ConfigAndConnectionsError(..)));
}

#[test]
Expand All @@ -199,6 +205,6 @@ mod tests {
let mut config = Config::default();
let err = args.merge_into_config(&mut config, &env).unwrap_err();
let bad = vec!["foobar".to_string()];
assert!(matches!(err, crate::Error::UnrecognizableConnections(v) if v == bad));
assert!(matches!(err, UnrecognizableConnections(v) if v == bad));
}
}
38 changes: 20 additions & 18 deletions martin/src/bin/martin-cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ use futures::stream::{self, StreamExt};
use futures::TryStreamExt;
use log::{debug, error, info, log_enabled};
use martin::args::{Args, ExtraArgs, MetaArgs, OsEnv, PgArgs, SrvArgs};
use martin::srv::{get_composite_tile, merge_tilejson, RESERVED_KEYWORDS};
use martin::srv::{get_tile_content, merge_tilejson, RESERVED_KEYWORDS};
use martin::{
append_rect, read_config, Config, Error, IdResolver, Result, ServerState, TileRect, Xyz,
append_rect, read_config, Config, IdResolver, MartinError, MartinResult, ServerState,
TileCoord, TileData, TileRect,
};
use mbtiles::{
init_mbtiles_schema, is_empty_database, CopyDuplicateMode, MbtType, MbtTypeCli, Mbtiles,
Expand Down Expand Up @@ -81,7 +82,7 @@ pub struct CopyArgs {
pub zoom_levels: Vec<u8>,
}

async fn start(copy_args: CopierArgs) -> Result<()> {
async fn start(copy_args: CopierArgs) -> MartinResult<()> {
info!("Starting Martin v{VERSION}");

let env = OsEnv::default();
Expand Down Expand Up @@ -153,12 +154,12 @@ fn compute_tile_ranges(args: &CopyArgs) -> Vec<TileRect> {
ranges
}

struct Tile {
xyz: Xyz,
data: Vec<u8>,
struct TileXyz {
xyz: TileCoord,
data: TileData,
}

impl Debug for Tile {
impl Debug for TileXyz {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} - {} bytes", self.xyz, self.data.len())
}
Expand Down Expand Up @@ -216,24 +217,24 @@ impl Display for Progress {
}

/// Given a list of tile ranges, iterate over all tiles in the ranges
fn iterate_tiles(tiles: Vec<TileRect>) -> impl Iterator<Item = Xyz> {
fn iterate_tiles(tiles: Vec<TileRect>) -> impl Iterator<Item = TileCoord> {
tiles.into_iter().flat_map(|t| {
let z = t.zoom;
(t.min_x..=t.max_x).flat_map(move |x| (t.min_y..=t.max_y).map(move |y| Xyz { z, x, y }))
(t.min_x..=t.max_x)
.flat_map(move |x| (t.min_y..=t.max_y).map(move |y| TileCoord { z, x, y }))
})
}

pub async fn run_tile_copy(args: CopyArgs, state: ServerState) -> Result<()> {
async fn run_tile_copy(args: CopyArgs, state: ServerState) -> MartinResult<()> {
let output_file = &args.output_file;
let concurrency = args.concurrency.unwrap_or(1);
let (sources, _use_url_query, info) = state.tiles.get_sources(args.source.as_str(), None)?;
let sources = sources.as_slice();
let tile_info = sources.first().unwrap().get_tile_info();
let (tx, mut rx) = channel::<Tile>(500);
let (tx, mut rx) = channel::<TileXyz>(500);
let tiles = compute_tile_ranges(&args);
let mbt = Mbtiles::new(output_file)?;
let mut conn = mbt.open_or_new().await?;
let on_dupl = args.on_duplicate;

let dst_type = if is_empty_database(&mut conn).await? {
let dst_type = match args.dst_type.unwrap_or(MbtTypeCli::Normalized) {
Expand Down Expand Up @@ -269,14 +270,15 @@ pub async fn run_tile_copy(args: CopyArgs, state: ServerState) -> Result<()> {
try_join!(
async move {
stream::iter(iterate_tiles(tiles))
.map(Ok::<Xyz, Error>)
.map(MartinResult::Ok)
.try_for_each_concurrent(concurrency, |xyz| {
let tx = tx.clone();
async move {
let data = get_composite_tile(sources, info, &xyz, None).await?;
tx.send(Tile { xyz, data })
let tile = get_tile_content(sources, info, &xyz, None, None).await?;
let data = tile.data;
tx.send(TileXyz { xyz, data })
.await
.map_err(|e| Error::InternalError(e.to_string()))?;
.map_err(|e| MartinError::InternalError(e.into()))?;
Ok(())
}
})
Expand All @@ -293,7 +295,7 @@ pub async fn run_tile_copy(args: CopyArgs, state: ServerState) -> Result<()> {
} else {
batch.push((tile.xyz.z, tile.xyz.x, tile.xyz.y, tile.data));
if batch.len() >= BATCH_SIZE || last_saved.elapsed() > SAVE_EVERY {
mbt.insert_tiles(&mut conn, dst_type, on_dupl, &batch)
mbt.insert_tiles(&mut conn, dst_type, args.on_duplicate, &batch)
.await?;
batch.clear();
last_saved = Instant::now();
Expand All @@ -308,7 +310,7 @@ pub async fn run_tile_copy(args: CopyArgs, state: ServerState) -> Result<()> {
}
}
if !batch.is_empty() {
mbt.insert_tiles(&mut conn, dst_type, on_dupl, &batch)
mbt.insert_tiles(&mut conn, dst_type, args.on_duplicate, &batch)
.await?;
}
Ok(())
Expand Down
4 changes: 2 additions & 2 deletions martin/src/bin/martin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use clap::Parser;
use log::{error, info, log_enabled};
use martin::args::{Args, OsEnv};
use martin::srv::{new_server, RESERVED_KEYWORDS};
use martin::{read_config, Config, IdResolver, Result};
use martin::{read_config, Config, IdResolver, MartinResult};

const VERSION: &str = env!("CARGO_PKG_VERSION");

async fn start(args: Args) -> Result<Server> {
async fn start(args: Args) -> MartinResult<Server> {
info!("Starting Martin v{VERSION}");

let env = OsEnv::default();
Expand Down
19 changes: 10 additions & 9 deletions martin/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ use crate::pmtiles::PmtSource;
use crate::source::{TileInfoSources, TileSources};
use crate::sprites::SpriteSources;
use crate::srv::SrvConfig;
use crate::Error::{ConfigLoadError, ConfigParseError, ConfigWriteError, NoSources};
use crate::{IdResolver, OptOneMany, Result};
use crate::MartinError::{ConfigLoadError, ConfigParseError, ConfigWriteError, NoSources};
use crate::{IdResolver, MartinResult, OptOneMany};

pub type UnrecognizedValues = HashMap<String, serde_yaml::Value>;

Expand Down Expand Up @@ -56,7 +56,7 @@ pub struct Config {

impl Config {
/// Apply defaults to the config, and validate if there is a connection string
pub fn finalize(&mut self) -> Result<UnrecognizedValues> {
pub fn finalize(&mut self) -> MartinResult<UnrecognizedValues> {
let mut res = UnrecognizedValues::new();
copy_unrecognized_config(&mut res, "", &self.unrecognized);

Expand All @@ -83,18 +83,19 @@ impl Config {
}
}

pub async fn resolve(&mut self, idr: IdResolver) -> Result<ServerState> {
pub async fn resolve(&mut self, idr: IdResolver) -> MartinResult<ServerState> {
Ok(ServerState {
tiles: self.resolve_tile_sources(idr).await?,
sprites: SpriteSources::resolve(&mut self.sprites)?,
fonts: FontSources::resolve(&mut self.fonts)?,
})
}

async fn resolve_tile_sources(&mut self, idr: IdResolver) -> Result<TileSources> {
async fn resolve_tile_sources(&mut self, idr: IdResolver) -> MartinResult<TileSources> {
let new_pmt_src = &mut PmtSource::new_box;
let new_mbt_src = &mut MbtSource::new_box;
let mut sources: Vec<Pin<Box<dyn Future<Output = Result<TileInfoSources>>>>> = Vec::new();
let mut sources: Vec<Pin<Box<dyn Future<Output = MartinResult<TileInfoSources>>>>> =
Vec::new();

for s in self.postgres.iter_mut() {
sources.push(Box::pin(s.resolve(idr.clone())));
Expand All @@ -113,7 +114,7 @@ impl Config {
Ok(TileSources::new(try_join_all(sources).await?))
}

pub fn save_to_file(&self, file_name: PathBuf) -> Result<()> {
pub fn save_to_file(&self, file_name: PathBuf) -> MartinResult<()> {
let yaml = serde_yaml::to_string(&self).expect("Unable to serialize config");
if file_name.as_os_str() == OsStr::new("-") {
info!("Current system configuration:");
Expand Down Expand Up @@ -147,7 +148,7 @@ pub fn copy_unrecognized_config(
}

/// Read config from a file
pub fn read_config<'a, M>(file_name: &Path, env: &'a M) -> Result<Config>
pub fn read_config<'a, M>(file_name: &Path, env: &'a M) -> MartinResult<Config>
where
M: VariableMap<'a>,
M::Value: AsRef<str>,
Expand All @@ -159,7 +160,7 @@ where
parse_config(&contents, env, file_name)
}

pub fn parse_config<'a, M>(contents: &str, env: &'a M, file_name: &Path) -> Result<Config>
pub fn parse_config<'a, M>(contents: &str, env: &'a M, file_name: &Path) -> MartinResult<Config>
where
M: VariableMap<'a>,
M::Value: AsRef<str>,
Expand Down
Loading

0 comments on commit 0f2cd10

Please sign in to comment.