summaryrefslogtreecommitdiff
path: root/include/mbgl/storage/database_file_source.hpp
blob: cc492709b8223b9b5215f86956e8e04c32808a4d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#pragma once

#include <mbgl/storage/file_source.hpp>
#include <mbgl/storage/offline.hpp>
#include <mbgl/util/expected.hpp>
#include <mbgl/util/optional.hpp>

namespace mbgl {

class ResourceOptions;

// This class represents ambient cache.
class AmbientCache {
public:
    virtual ~AmbientCache() = default;
    /*
     * Insert the provided resource into the ambient cache
     *
     * Consumers of the resource will expect the uncompressed version; the
     * OfflineDatabase will determine whether to compress the data on disk.
     * This call is asynchronous: the data may not be immediately available
     * for in-progress requests, although subsequent requests should have
     * access to the cached data.
     */
    virtual void put(const Resource&, const Response&) = 0;

    /*
     * Forces revalidation of the ambient cache.
     *
     * Forces Mapbox GL Native to revalidate resources stored in the ambient
     * cache with the tile server before using them, making sure they
     * are the latest version. This is more efficient than cleaning the
     * cache because if the resource is considered valid after the server
     * lookup, it will not get downloaded again.
     *
     * Resources overlapping with offline regions will not be affected
     * by this call.
     */
    virtual void invalidateAmbientCache(std::function<void(std::exception_ptr)>) = 0;

    /*
     * Erase resources from the ambient cache, freeing storage space.
     *
     * Erases the ambient cache, freeing resources.
     *
     * Note that this operation can be potentially slow if packing the database
     * occurs automatically (see runPackDatabaseAutomatically() and packDatabase()).
     *
     * Resources overlapping with offline regions will not be affected
     * by this call.
     */
    virtual void clearAmbientCache(std::function<void(std::exception_ptr)>) = 0;

    /*
     * Sets the maximum size in bytes for the ambient cache.
     *
     * This call is potentially expensive because it will try
     * to trim the data in case the database is larger than the
     * size defined. The size of offline regions are not affected
     * by this settings, but the ambient cache will always try
     * to not exceed the maximum size defined, taking into account
     * the current size for the offline regions.
     *
     * If the maximum size is set to 50 MB and 40 MB are already
     * used by offline regions, the cache size will be effectively
     * 10 MB.
     *
     * Setting the size to 0 will disable the cache if there is no
     * offline region on the database.
     *
     * This method should always be called before using the database,
     * otherwise the default maximum size will be used.
     */
    virtual void setMaximumAmbientCacheSize(uint64_t size, std::function<void(std::exception_ptr)> callback) = 0;
};

// This class represents offline regions storage.
class OfflineRegionsStorage {
public:
    virtual ~OfflineRegionsStorage() = default;
    /*
     * Retrieve all regions in the offline database.
     *
     * The query will be executed asynchronously and the results passed to the given
     * callback, which will be executed on the database thread; it is the responsibility
     * of the SDK bindings to re-execute a user-provided callback on the main thread.
     */
    virtual void listOfflineRegions(std::function<void(expected<OfflineRegions, std::exception_ptr>)>) = 0;

    /*
     * Create an offline region in the database.
     *
     * When the initial database queries have completed, the provided callback will be
     * executed on the database thread; it is the responsibility of the SDK bindings
     * to re-execute a user-provided callback on the main thread.
     *
     * Note that the resulting region will be in an inactive download state; to begin
     * downloading resources, call `setOfflineRegionDownloadState(OfflineRegionDownloadState::Active)`,
     * optionally registering an `OfflineRegionObserver` beforehand.
     */
    virtual void createOfflineRegion(const OfflineRegionDefinition& definition,
                                     const OfflineRegionMetadata& metadata,
                                     std::function<void(expected<OfflineRegion, std::exception_ptr>)>) = 0;
    /*
     * Update an offline region metadata in the database.
     */
    virtual void updateOfflineMetadata(const int64_t regionID,
                                       const OfflineRegionMetadata& metadata,
                                       std::function<void(expected<OfflineRegionMetadata, std::exception_ptr>)>) = 0;

    /*
     * Register an observer to be notified when the state of the region changes.
     */
    virtual void setOfflineRegionObserver(OfflineRegion&, std::unique_ptr<OfflineRegionObserver>) = 0;

    /*
     * Pause or resume downloading of regional resources.
     */
    virtual void setOfflineRegionDownloadState(OfflineRegion&, OfflineRegionDownloadState) = 0;

    /*
     * Retrieve the current status of the region. The query will be executed
     * asynchronously and the results passed to the given callback, which will be
     * executed on the database thread; it is the responsibility of the SDK bindings
     * to re-execute a user-provided callback on the main thread.
     */
    virtual void getOfflineRegionStatus(
        OfflineRegion&, std::function<void(expected<OfflineRegionStatus, std::exception_ptr>)>) const = 0;

    /*
     * Merge offline regions from a secondary database into the main offline database.
     *
     * When the database merge is completed, the provided callback will be
     * executed on the database thread; it is the responsibility of the SDK bindings
     * to re-execute a user-provided callback on the main thread.
     *
     * The secondary database may need to be upgraded to the latest schema. This is done
     * in-place and requires write-access to `sideDatabasePath`; it is the
     * responsibility of the SDK bindings to ensure that this path is writeable.
     *
     * Only resources and tiles that belong to a region will be copied over. Identical
     * regions will be flattened into a single new region in the main database.
     *
     * Invokes the callback with a `MapboxOfflineTileCountExceededException` error if
     * the merge operation would result in the offline tile count limit being exceeded.
     *
     * Merged regions may not be in a completed status if the secondary database
     * does not contain all the tiles or resources required by the region definition.
     */
    virtual void mergeOfflineRegions(const std::string& sideDatabasePath,
                                     std::function<void(expected<OfflineRegions, std::exception_ptr>)>) = 0;

    /*
     * Remove an offline region from the database and perform any resources evictions
     * necessary as a result.
     *
     * Eviction works by removing the least-recently requested resources not also required
     * by other regions, until the database shrinks below a certain size.
     *
     * Note that this method takes ownership of the input, reflecting the fact that once
     * region deletion is initiated, it is not legal to perform further actions with the
     * region.
     *
     * Note that this operation can be potentially slow if packing the database occurs
     * automatically (see runPackDatabaseAutomatically() and packDatabase()).
     *
     * When the operation is complete or encounters an error, the given callback will be
     * executed on the database thread; it is the responsibility of the SDK bindings
     * to re-execute a user-provided callback on the main thread.
     */
    virtual void deleteOfflineRegion(OfflineRegion, std::function<void(std::exception_ptr)>) = 0;

    /*
     * Invalidate all the tiles from an offline region forcing Mapbox GL to revalidate
     * the tiles with the server before using. This is more efficient than deleting the
     * offline region and downloading it again because if the data on the cache matches
     * the server, no new data gets transmitted.
     */
    virtual void invalidateOfflineRegion(OfflineRegion&, std::function<void(std::exception_ptr)>) = 0;

    /*
     * Changing or bypassing this limit without permission from Mapbox is prohibited
     * by the Mapbox Terms of Service.
     */
    virtual void setOfflineMapboxTileCountLimit(uint64_t) const = 0;
};

// This class represents the local database storage, which is used for storing both ambient cache and offline regions.
class JointDatabaseStorage : public AmbientCache, public OfflineRegionsStorage {
public:
    virtual ~JointDatabaseStorage() = default;
    /*
     * Sets path of a database to be used by DatabaseFileSource and invokes provided
     * callback when a database path is set.
     */
    virtual void setDatabasePath(const std::string&, std::function<void()> callback) = 0;

    /*
     * Delete existing database and re-initialize.
     *
     * When the operation is complete or encounters an error, the given callback will be
     * executed on the database thread; it is the responsibility of the SDK bindings
     * to re-execute a user-provided callback on the main thread.
     */
    virtual void resetDatabase(std::function<void(std::exception_ptr)>) = 0;

    /*
     * Packs the existing database file into a minimal amount of disk space.
     *
     * This operation has a performance impact as it will vacuum the database,
     * forcing it to move pages on the filesystem.
     *
     * When the operation is complete or encounters an error, the given callback will be
     * executed on the database thread; it is the responsibility of the SDK bindings
     * to re-execute a user-provided callback on the main thread.
     */
    virtual void packDatabase(std::function<void(std::exception_ptr)> callback) = 0;

    /*
     * Sets whether packing the database file occurs automatically after an offline
     * region is deleted (deleteOfflineRegion()) or the ambient cache is cleared
     * (clearAmbientCache()).
     *
     * By default, packing is enabled. If disabled, disk space will not be freed
     * after resources are removed unless packDatabase() is explicitly called.
     */
    virtual void runPackDatabaseAutomatically(bool) = 0;
};
class DatabaseFileSource : public FileSource, public JointDatabaseStorage {
public:
    explicit DatabaseFileSource(const ResourceOptions& options);
    ~DatabaseFileSource() override;

private:
    // JointDatabaseStorage overrides
    void setDatabasePath(const std::string&, std::function<void()> callback) override;
    void resetDatabase(std::function<void(std::exception_ptr)>) override;
    void packDatabase(std::function<void(std::exception_ptr)> callback) override;
    void runPackDatabaseAutomatically(bool) override;

    // AmbientCache overrides
    void put(const Resource&, const Response&) override;
    void invalidateAmbientCache(std::function<void(std::exception_ptr)>) override;
    void clearAmbientCache(std::function<void(std::exception_ptr)>) override;
    void setMaximumAmbientCacheSize(uint64_t size, std::function<void(std::exception_ptr)> callback) override;

    // OfflineRegionsStorage overrides
    void listOfflineRegions(std::function<void(expected<OfflineRegions, std::exception_ptr>)>) override;
    void createOfflineRegion(const OfflineRegionDefinition& definition,
                             const OfflineRegionMetadata& metadata,
                             std::function<void(expected<OfflineRegion, std::exception_ptr>)>) override;
    void updateOfflineMetadata(const int64_t regionID,
                               const OfflineRegionMetadata& metadata,
                               std::function<void(expected<OfflineRegionMetadata, std::exception_ptr>)>) override;
    void setOfflineRegionObserver(OfflineRegion&, std::unique_ptr<OfflineRegionObserver>) override;
    void setOfflineRegionDownloadState(OfflineRegion&, OfflineRegionDownloadState) override;
    void getOfflineRegionStatus(OfflineRegion&,
                                std::function<void(expected<OfflineRegionStatus, std::exception_ptr>)>) const override;
    void mergeOfflineRegions(const std::string& sideDatabasePath,
                             std::function<void(expected<OfflineRegions, std::exception_ptr>)>) override;
    void deleteOfflineRegion(OfflineRegion, std::function<void(std::exception_ptr)>) override;
    void invalidateOfflineRegion(OfflineRegion&, std::function<void(std::exception_ptr)>) override;
    void setOfflineMapboxTileCountLimit(uint64_t) const override;

private:
    // FileSource overrides
    std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
    void forward(const Resource&, const Response&, std::function<void()> callback) override;
    bool canRequest(const Resource&) const override;
    void setProperty(const std::string&, const mapbox::base::Value&) override;
    void pause() override;
    void resume() override;

    class Impl;
    const std::unique_ptr<Impl> impl;
};

} // namespace mbgl