[Question] How is the code handling huge amount of tiles ? #170
Replies: 1 comment
-
Hi @idouiri9806, Great to hear that you like the project! To be fair, a lot of the heavy lifting is done by flutter_map and ObjectBox, but all the connecting components and tile generation for bulk downloading is done by us. In browse caching, flutter_map asks the tile provider for a tile at some specific coordinates - it is up to In the default implementation, a long-lived worker thread runs in the background that communicates with the database, to try to keep things fast. Whether this is actually necessary is a point for discussion - I can't find it right now, but there was a comment about this recently. The main thread is implemented in this file, whilst the worker thread is implemented in here. In terms of how tiles are actually stored: they are just stored as blobs with some metadata in the ObjectBox database. In theory, the storage engine could actually be a seperate from FMTC - it should be able to store any binary blob, including vector tiles or raster tiles, or any other file type. It could make quite an advanced and interesting storage library 🤔. In bulk downloading, the downloader gets a region, defined by its coordinates. There's a generator and counter algorithm for each region type - the counter is a generalisation/simplification/shortcut of the generator, that only needs to count tiles, it does not need to loop through them all (so, for example, it's easy to calculate the number of tiles in a rectangle region using multiplication, but the generator must use a nested loop to generate each tile's coordinates). At the start of the download, the counter is called, which allows the number to be reported in statistics, and a couple other bits and pieces. The speed comes from heavy use of multi-threading (Isolates) and optimisation - there's probably loads more that could be done, but there's no point, since the bottleneck is pretty much always the network (FMTC can download at 1,500+ tiles/second on my laptop when the tile server is the testing tile server running locally). The downloader is essentially split into 3 parts, each of which is running in an Isolate:
Essentially, flow is controlled by a series of To make things fast, it's just lots of Isolates, lots of lines of code to do simple tasks at first look (114 to write/update a single tile to multiple stores) - a lot of the complexity is added by keeping the statistics up to date, so that a statistic retrieval can be as fast as possible. For any more detail, I would advise looking at the implementation. Lookup is fast because of ObjectBox and the magic of indexes. One thing you will notice is that mass/bulk operations can be quite slow - for example, deleting a large store may take some time. This is because we have to run through every tile that belongs to that store, and attempt to orphan it. If it is orphaned (it only belonged to that store), then we can delete it. If it still belongs to any other stores, we also have to update all of those store's statistics, as well as the tile itself. But we try to make some optimisations at the expense of memory-consumption to minimize the number of actual database writes made. Again, a lot of the heavy lifting is done by ObjectBox - the storage engine - and flutter_map - which actually lays out the tiles. How those work is a different story, but I would recommend looking at the implementation of flutter_map's TileLayer to find out how the layout is done. The purpose of FMTC is to bridge those two libraries (and theoretically any other storage engine) in a way that is efficient and extremely flexible. The complexity added by v10 is quite large - as are the API changes coming 🫥. I hope this was helpful! |
Beta Was this translation helpful? Give feedback.
-
Hi Jaffa!
Great project! I'm new to Flutter and would like to create something similar for my school project. I just want to understand the logic behind how the tiles are stored on the device and then retrieved. After the download is complete, how are the tiles for a specific region read and plotted at the correct location on the map? How are they stored — in XYZ folders, PMTiles, MBTiles, or vector formats?
I remember there was a document that explained all this. It was a great read, but I can't seem to find it anymore. If it's not too much trouble, could you explain it again? A short one would be ok. Thank you.
Beta Was this translation helpful? Give feedback.
All reactions