1 #pragma once
2 
3 #include <mbgl/storage/resource.hpp>
4 #include <mbgl/storage/offline.hpp>
5 #include <mbgl/util/exception.hpp>
6 #include <mbgl/util/noncopyable.hpp>
7 #include <mbgl/util/optional.hpp>
8 #include <mbgl/util/constants.hpp>
9 #include <mbgl/util/mapbox.hpp>
10 
11 #include <unordered_map>
12 #include <memory>
13 #include <string>
14 #include <list>
15 
16 namespace mapbox {
17 namespace sqlite {
18 class Database;
19 class Statement;
20 class Query;
21 } // namespace sqlite
22 } // namespace mapbox
23 
24 namespace mbgl {
25 
26 class Response;
27 class TileID;
28 
29 struct MapboxTileLimitExceededException :  util::Exception {
MapboxTileLimitExceededExceptionmbgl::MapboxTileLimitExceededException30     MapboxTileLimitExceededException() : util::Exception("Mapbox tile limit exceeded") {}
31 };
32 
33 class OfflineDatabase : private util::noncopyable {
34 public:
35     // Limits affect ambient caching (put) only; resources required by offline
36     // regions are exempt.
37     OfflineDatabase(std::string path, uint64_t maximumCacheSize = util::DEFAULT_MAX_CACHE_SIZE);
38     ~OfflineDatabase();
39 
40     optional<Response> get(const Resource&);
41 
42     // Return value is (inserted, stored size)
43     std::pair<bool, uint64_t> put(const Resource&, const Response&);
44 
45     std::vector<OfflineRegion> listRegions();
46 
47     OfflineRegion createRegion(const OfflineRegionDefinition&,
48                                const OfflineRegionMetadata&);
49 
50     OfflineRegionMetadata updateMetadata(const int64_t regionID, const OfflineRegionMetadata&);
51 
52     void deleteRegion(OfflineRegion&&);
53 
54     // Return value is (response, stored size)
55     optional<std::pair<Response, uint64_t>> getRegionResource(int64_t regionID, const Resource&);
56     optional<int64_t> hasRegionResource(int64_t regionID, const Resource&);
57     uint64_t putRegionResource(int64_t regionID, const Resource&, const Response&);
58     void putRegionResources(int64_t regionID, const std::list<std::tuple<Resource, Response>>&, OfflineRegionStatus&);
59 
60     OfflineRegionDefinition getRegionDefinition(int64_t regionID);
61     OfflineRegionStatus getRegionCompletedStatus(int64_t regionID);
62 
63     void setOfflineMapboxTileCountLimit(uint64_t);
64     uint64_t getOfflineMapboxTileCountLimit();
65     bool offlineMapboxTileCountLimitExceeded();
66     uint64_t getOfflineMapboxTileCount();
67     bool exceedsOfflineMapboxTileCountLimit(const Resource&);
68 
69 private:
70     int userVersion();
71     void ensureSchema();
72     void removeExisting();
73     void removeOldCacheTable();
74     void migrateToVersion3();
75     void migrateToVersion5();
76     void migrateToVersion6();
77 
78     mapbox::sqlite::Statement& getStatement(const char *);
79 
80     optional<std::pair<Response, uint64_t>> getTile(const Resource::TileData&);
81     optional<int64_t> hasTile(const Resource::TileData&);
82     bool putTile(const Resource::TileData&, const Response&,
83                  const std::string&, bool compressed);
84 
85     optional<std::pair<Response, uint64_t>> getResource(const Resource&);
86     optional<int64_t> hasResource(const Resource&);
87     bool putResource(const Resource&, const Response&,
88                      const std::string&, bool compressed);
89 
90     uint64_t putRegionResourceInternal(int64_t regionID, const Resource&, const Response&);
91 
92     optional<std::pair<Response, uint64_t>> getInternal(const Resource&);
93     optional<int64_t> hasInternal(const Resource&);
94     std::pair<bool, uint64_t> putInternal(const Resource&, const Response&, bool evict);
95 
96     // Return value is true iff the resource was previously unused by any other regions.
97     bool markUsed(int64_t regionID, const Resource&);
98 
99     std::pair<int64_t, int64_t> getCompletedResourceCountAndSize(int64_t regionID);
100     std::pair<int64_t, int64_t> getCompletedTileCountAndSize(int64_t regionID);
101 
102     const std::string path;
103     std::unique_ptr<mapbox::sqlite::Database> db;
104     std::unordered_map<const char *, const std::unique_ptr<mapbox::sqlite::Statement>> statements;
105 
106     template <class T>
107     T getPragma(const char *);
108 
109     uint64_t maximumCacheSize;
110 
111     uint64_t offlineMapboxTileCountLimit = util::mapbox::DEFAULT_OFFLINE_TILE_COUNT_LIMIT;
112     optional<uint64_t> offlineMapboxTileCount;
113 
114     bool evict(uint64_t neededFreeSize);
115 };
116 
117 } // namespace mbgl
118