summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2016-05-23 18:03:49 +0200
committerKonstantin Käfer <mail@kkaefer.com>2016-06-10 12:42:14 +0200
commitf180179d1b98e6610263b71ea0d9ef7f44725005 (patch)
tree98532bcd04ab826333e3e0ce98eab181853cbe26
parent4357fed93bedfa4db675bfcae7bddfa07627ea56 (diff)
downloadqtlocation-mapboxgl-f180179d1b98e6610263b71ea0d9ef7f44725005.tar.gz
[core] allow changing the necessity of a TileSource
-rw-r--r--src/mbgl/style/source.cpp2
-rw-r--r--src/mbgl/tile/file_based_tile_source.hpp11
-rw-r--r--src/mbgl/tile/file_based_tile_source_impl.hpp66
-rw-r--r--src/mbgl/tile/tile_data.hpp2
-rw-r--r--src/mbgl/tile/tile_source.hpp63
5 files changed, 131 insertions, 13 deletions
diff --git a/src/mbgl/style/source.cpp b/src/mbgl/style/source.cpp
index 10959a9fd8..dcf8278c0d 100644
--- a/src/mbgl/style/source.cpp
+++ b/src/mbgl/style/source.cpp
@@ -287,6 +287,7 @@ bool Source::update(const UpdateParameters& parameters) {
};
auto createTileDataFn = [this, &parameters](const OverscaledTileID& dataTileID) -> TileData* {
if (auto data = createTile(dataTileID, parameters)) {
+ data->getTileSource()->setNecessity(TileSource::Necessity::Required);
return tileDataMap.emplace(dataTileID, std::move(data)).first->second.get();
} else {
return nullptr;
@@ -316,6 +317,7 @@ bool Source::update(const UpdateParameters& parameters) {
auto retainIt = retain.begin();
while (dataIt != tileDataMap.end()) {
if (retainIt == retain.end() || dataIt->first < *retainIt) {
+ dataIt->second->getTileSource()->setNecessity(TileSource::Necessity::Optional);
cache.add(dataIt->first, std::move(dataIt->second));
tileDataMap.erase(dataIt++);
} else {
diff --git a/src/mbgl/tile/file_based_tile_source.hpp b/src/mbgl/tile/file_based_tile_source.hpp
index e4099ed316..72d0782710 100644
--- a/src/mbgl/tile/file_based_tile_source.hpp
+++ b/src/mbgl/tile/file_based_tile_source.hpp
@@ -6,6 +6,7 @@ namespace mbgl {
class FileSource;
class AsyncRequest;
+class Response;
template <typename T, typename I>
class FileBasedTileSource : public T {
@@ -14,7 +15,15 @@ protected:
virtual ~FileBasedTileSource() = default;
protected:
- const Resource resource;
+ void makeRequired() override;
+ void makeOptional() override;
+
+private:
+ void loadedData(const Response&);
+ void loadRequired();
+
+private:
+ Resource resource;
FileSource& fileSource;
std::unique_ptr<AsyncRequest> request;
};
diff --git a/src/mbgl/tile/file_based_tile_source_impl.hpp b/src/mbgl/tile/file_based_tile_source_impl.hpp
index 1527f3b13a..c64789ca3c 100644
--- a/src/mbgl/tile/file_based_tile_source_impl.hpp
+++ b/src/mbgl/tile/file_based_tile_source_impl.hpp
@@ -3,6 +3,8 @@
#include <mbgl/tile/file_based_tile_source.hpp>
#include <mbgl/storage/file_source.hpp>
+#include <cassert>
+
namespace mbgl {
template <typename T, typename I>
@@ -10,18 +12,64 @@ FileBasedTileSource<T, I>::FileBasedTileSource(typename T::data_type& tileData_,
const Resource& resource_,
FileSource& fileSource_)
: T(tileData_), resource(resource_), fileSource(fileSource_) {
+ assert(!request);
+ // The first request is always optional.
+ resource.necessity = Resource::Optional;
request = fileSource.request(resource, [this](Response res) {
- if (res.error) {
- T::tileData.setError(std::make_exception_ptr(std::runtime_error(res.error->message)));
- } else if (res.notModified) {
- return;
- } else if (res.noContent) {
- T::tileData.setData(nullptr, res.modified, res.expires);
- } else {
-
- T::tileData.setData(I::parseData(res.data), res.modified, res.expires);
+ request.reset();
+ loadedData(res);
+ T::loaded = true;
+ if (T::isRequired()) {
+ loadRequired();
}
});
}
+template <typename T, typename I>
+void FileBasedTileSource<T, I>::makeRequired() {
+ if (T::loaded && !request) {
+ loadRequired();
+ }
+}
+
+template <typename T, typename I>
+void FileBasedTileSource<T, I>::makeOptional() {
+ if (T::loaded && request) {
+ // Abort a potential HTTP request.
+ request.reset();
+ }
+}
+
+template <typename T, typename I>
+void FileBasedTileSource<T, I>::loadedData(const Response& res) {
+ if (res.error && !T::loaded && res.error->reason == Response::Error::Reason::NotFound) {
+ // When the optional request could not be satisfied, don't treat it as an error. Instead,
+ // we make sure that the next request knows that there has been an optional request before
+ // by setting one of the prior* fields.
+ resource.priorExpires = Timestamp{ Seconds::zero() };
+ } else if (res.error) {
+ T::tileData.setError(std::make_exception_ptr(std::runtime_error(res.error->message)));
+ } else if (res.notModified) {
+ resource.priorExpires = res.expires;
+ // Do not notify the TileData object; when we get this message, it already has the current
+ // version of the data.
+ } else {
+ resource.priorModified = res.modified;
+ resource.priorExpires = res.expires;
+ resource.priorEtag = res.etag;
+ T::tileData.setData(res.noContent ? nullptr : I::parseData(res.data), res.modified,
+ res.expires);
+ }
+}
+
+template <typename T, typename I>
+void FileBasedTileSource<T, I>::loadRequired() {
+ assert(!request);
+
+ resource.necessity = Resource::Required;
+ request = fileSource.request(resource, [this](Response res) {
+ loadedData(res);
+ });
+}
+
} // namespace mbgl
diff --git a/src/mbgl/tile/tile_data.hpp b/src/mbgl/tile/tile_data.hpp
index a0614455b6..c3877d0d63 100644
--- a/src/mbgl/tile/tile_data.hpp
+++ b/src/mbgl/tile/tile_data.hpp
@@ -33,6 +33,7 @@ public:
void setObserver(TileDataObserver* observer);
void setTileSource(std::unique_ptr<TileSource>);
+ TileSource* getTileSource() { return tileSource.get(); }
// Mark this tile as no longer needed and cancel any pending work.
virtual void cancel() = 0;
@@ -63,7 +64,6 @@ public:
return availableData == DataAvailability::Some;
}
-
void dumpDebugLogs() const;
const OverscaledTileID id;
diff --git a/src/mbgl/tile/tile_source.hpp b/src/mbgl/tile/tile_source.hpp
index ba4555129d..230b259321 100644
--- a/src/mbgl/tile/tile_source.hpp
+++ b/src/mbgl/tile/tile_source.hpp
@@ -6,7 +6,63 @@ namespace mbgl {
class TileSource : private util::noncopyable {
public:
+ // TileSources can have two states: optional or required.
+ // - optional means that only low-cost actions should be taken to obtain the data
+ // (e.g. load from cache, but accept stale data)
+ // - required means that every effort should be taken to obtain the data (e.g. load
+ // from internet and keep the data fresh if it expires)
+ enum class Necessity : bool {
+ Optional = false,
+ Required = true,
+ };
+
+protected:
+ TileSource(Necessity necessity_ = Necessity::Optional) : necessity(necessity_) {
+ }
+
+public:
virtual ~TileSource() = default;
+
+ bool isOptional() const {
+ return necessity == Necessity::Optional;
+ }
+
+ bool isRequired() const {
+ return necessity == Necessity::Required;
+ }
+
+ void setNecessity(Necessity newNecessity) {
+ if (newNecessity != necessity) {
+ necessity = newNecessity;
+ if (necessity == Necessity::Required) {
+ makeRequired();
+ } else {
+ makeOptional();
+ }
+ }
+ }
+
+ bool isLoaded() const {
+ // "loaded" is considered true once the initial load action completed, regardless of whether
+ // the TileData is required or optional, and whether any actual TileData was loaded in the
+ // case of optional TileData
+ return loaded;
+ }
+
+protected:
+ // called when the tile is one of the ideal tiles that we want to show definitely. the tile source
+ // should try to make every effort (e.g. fetch from internet, or revalidate existing resources).
+ virtual void makeRequired() {}
+
+ // called when the zoom level no longer corresponds to the displayed one, but
+ // we're still interested in retaining the tile, e.g. for backfill.
+ // subclassed TileSources should cancel actions they are taking to provide
+ // an up-to-date version or load new data
+ virtual void makeOptional() {}
+
+protected:
+ Necessity necessity;
+ bool loaded = false;
};
class GeometryTileData;
@@ -17,7 +73,9 @@ public:
using data_type = GeometryTileData;
protected:
- GeometryTileSource(data_type& tileData_) : tileData(tileData_) {}
+ GeometryTileSource(data_type& tileData_, Necessity necessity_ = Necessity::Optional)
+ : TileSource(necessity_), tileData(tileData_) {
+ }
public:
virtual ~GeometryTileSource() = default;
@@ -31,7 +89,8 @@ public:
using data_type = RasterTileData;
protected:
- RasterTileSource(data_type& tileData_) : tileData(tileData_) {};
+ RasterTileSource(data_type& tileData_, Necessity necessity_ = Necessity::Optional)
+ : TileSource(necessity_), tileData(tileData_){};
public:
virtual ~RasterTileSource() = default;