Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[core] allow changing the necessity of a TileSource
Browse files Browse the repository at this point in the history
  • Loading branch information
kkaefer committed May 27, 2016
1 parent 9a7fe6b commit 62200ff
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 13 deletions.
2 changes: 2 additions & 0 deletions src/mbgl/source/source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ bool Source::update(const StyleUpdateParameters& 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;
Expand Down Expand Up @@ -315,6 +316,7 @@ bool Source::update(const StyleUpdateParameters& 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 {
Expand Down
11 changes: 10 additions & 1 deletion src/mbgl/tile/file_based_tile_source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace mbgl {

class FileSource;
class AsyncRequest;
class Response;

template <typename T, typename I>
class FileBasedTileSource : public T {
Expand All @@ -14,7 +15,15 @@ class FileBasedTileSource : public T {
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;
};
Expand Down
66 changes: 57 additions & 9 deletions src/mbgl/tile/file_based_tile_source_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,73 @@
#include <mbgl/tile/file_based_tile_source.hpp>
#include <mbgl/storage/file_source.hpp>

#include <cassert>

namespace mbgl {

template <typename T, typename I>
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
2 changes: 1 addition & 1 deletion src/mbgl/tile/tile_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class TileData : private util::noncopyable {

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;
Expand Down Expand Up @@ -60,7 +61,6 @@ class TileData : private util::noncopyable {
return availableData == DataAvailability::Some;
}


void dumpDebugLogs() const;

const OverscaledTileID id;
Expand Down
63 changes: 61 additions & 2 deletions src/mbgl/tile/tile_source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,64 @@
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;
Expand All @@ -17,7 +73,9 @@ class GeometryTileSource : public TileSource {
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;
Expand All @@ -31,7 +89,8 @@ class RasterTileSource : public TileSource {
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;
Expand Down

0 comments on commit 62200ff

Please sign in to comment.