diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2016-01-19 15:57:17 -0800 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2016-01-21 11:22:11 -0800 |
commit | 1c21d0fd4cd30cbf6c5b863fd0179b227c28bc0b (patch) | |
tree | dfb6b788285d2b28f7060138ae28734ece13942e | |
parent | c33ed50c98c57ce2f2cf3b971bcf72c4208bf120 (diff) | |
download | qtlocation-mapboxgl-1c21d0fd4cd30cbf6c5b863fd0179b227c28bc0b.tar.gz |
[core] Use better types for modified / expires / etag
33 files changed, 231 insertions, 169 deletions
diff --git a/include/mbgl/storage/response.hpp b/include/mbgl/storage/response.hpp index a7a200c53a..e81af710f7 100644 --- a/include/mbgl/storage/response.hpp +++ b/include/mbgl/storage/response.hpp @@ -2,6 +2,7 @@ #define MBGL_STORAGE_RESPONSE #include <mbgl/util/chrono.hpp> +#include <mbgl/util/optional.hpp> #include <string> #include <memory> @@ -25,9 +26,9 @@ public: // The actual data of the response. This is guaranteed to never be empty. std::shared_ptr<const std::string> data; - Seconds modified = Seconds::zero(); - Seconds expires = Seconds::zero(); - std::string etag; + optional<SystemTimePoint> modified; + optional<SystemTimePoint> expires; + optional<std::string> etag; }; class Response::Error { diff --git a/platform/android/src/http_request_android.cpp b/platform/android/src/http_request_android.cpp index 05d719938c..81fb6fd306 100644 --- a/platform/android/src/http_request_android.cpp +++ b/platform/android/src/http_request_android.cpp @@ -124,10 +124,10 @@ HTTPAndroidRequest::HTTPAndroidRequest(HTTPAndroidContext* context_, const std:: std::string etagStr; std::string modifiedStr; if (existingResponse) { - if (!existingResponse->etag.empty()) { - etagStr = existingResponse->etag; - } else if (existingResponse->modified != Seconds::zero()) { - modifiedStr = util::rfc1123(existingResponse->modified.count()); + if (existingResponse->etag) { + etagStr = *existingResponse->etag; + } else if (existingResponse->modified) { + modifiedStr = util::rfc1123(SystemClock::to_time_t(*existingResponse->modified)); } } @@ -195,11 +195,11 @@ void HTTPAndroidRequest::onResponse(int code, std::string message, std::string e // the message param is unused, this generates a warning at build time // this was breaking builds for `make android -j4` (void)message; - response->modified = Seconds(parse_date(modified.c_str())); + response->modified = SystemClock::from_time_t(parse_date(modified.c_str())); response->etag = etag; response->expires = parseCacheControl(cacheControl.c_str()); if (!expires.empty()) { - response->expires = Seconds(parse_date(expires.c_str())); + response->expires = SystemClock::from_time_t(parse_date(expires.c_str())); } response->data = std::make_shared<std::string>(body); @@ -211,15 +211,15 @@ void HTTPAndroidRequest::onResponse(int code, std::string message, std::string e if (existingResponse) { response->data = existingResponse->data; - if (response->expires == Seconds::zero()) { + if (!response->expires) { response->expires = existingResponse->expires; } - if (response->modified == Seconds::zero()) { + if (!response->modified) { response->modified = existingResponse->modified; } - if (response->etag.empty()) { + if (!response->etag) { response->etag = existingResponse->etag; } } diff --git a/platform/darwin/http_request_nsurl.mm b/platform/darwin/http_request_nsurl.mm index bb8bb57314..68b9863f74 100644 --- a/platform/darwin/http_request_nsurl.mm +++ b/platform/darwin/http_request_nsurl.mm @@ -113,12 +113,12 @@ HTTPNSURLRequest::HTTPNSURLRequest(HTTPNSURLContext* context_, NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url]; if (existingResponse) { - if (!existingResponse->etag.empty()) { - [req addValue:@(existingResponse->etag.c_str()) - forHTTPHeaderField:@"If-None-Match"]; - } else if (existingResponse->modified != Seconds::zero()) { - const std::string time = util::rfc1123(existingResponse->modified.count()); - [req addValue:@(time.c_str()) forHTTPHeaderField:@"If-Modified-Since"]; + if (existingResponse->etag) { + [req addValue:@((*existingResponse->etag).c_str()) + forHTTPHeaderField:@"If-None-Match"]; + } else if (existingResponse->modified) { + [req addValue:@(util::rfc1123(SystemClock::to_time_t(*existingResponse->modified)).c_str()) + forHTTPHeaderField:@"If-Modified-Since"]; } } @@ -217,17 +217,17 @@ void HTTPNSURLRequest::handleResult(NSData *data, NSURLResponse *res, NSError *e NSString *expires = [headers objectForKey:@"Expires"]; if (expires) { - response->expires = Seconds(parse_date([expires UTF8String])); + response->expires = SystemClock::from_time_t(parse_date([expires UTF8String])); } NSString *last_modified = [headers objectForKey:@"Last-Modified"]; if (last_modified) { - response->modified = Seconds(parse_date([last_modified UTF8String])); + response->modified = SystemClock::from_time_t(parse_date([last_modified UTF8String])); } NSString *etag = [headers objectForKey:@"ETag"]; if (etag) { - response->etag = [etag UTF8String]; + response->etag = std::string([etag UTF8String]); } if (responseCode == 200) { @@ -238,15 +238,15 @@ void HTTPNSURLRequest::handleResult(NSData *data, NSURLResponse *res, NSError *e if (existingResponse) { response->data = existingResponse->data; - if (response->expires == Seconds::zero()) { + if (!response->expires) { response->expires = existingResponse->expires; } - if (response->modified == Seconds::zero()) { + if (!response->modified) { response->modified = existingResponse->modified; } - if (response->etag.empty()) { + if (!response->etag) { response->etag = existingResponse->etag; } } diff --git a/platform/default/http_request_curl.cpp b/platform/default/http_request_curl.cpp index f5fc395862..078a172c2b 100644 --- a/platform/default/http_request_curl.cpp +++ b/platform/default/http_request_curl.cpp @@ -363,12 +363,12 @@ HTTPCURLRequest::HTTPCURLRequest(HTTPCURLContext* context_, const std::string& u // If there's already a response, set the correct etags/modified headers to make sure we are // getting a 304 response if possible. This avoids redownloading unchanged data. if (existingResponse) { - if (!existingResponse->etag.empty()) { - const std::string header = std::string("If-None-Match: ") + existingResponse->etag; + if (existingResponse->etag) { + const std::string header = std::string("If-None-Match: ") + *existingResponse->etag; headers = curl_slist_append(headers, header.c_str()); - } else if (existingResponse->modified != Seconds::zero()) { + } else if (existingResponse->modified) { const std::string time = - std::string("If-Modified-Since: ") + util::rfc1123(existingResponse->modified.count()); + std::string("If-Modified-Since: ") + util::rfc1123(SystemClock::to_time_t(*existingResponse->modified)); headers = curl_slist_append(headers, time.c_str()); } } @@ -466,15 +466,15 @@ size_t HTTPCURLRequest::headerCallback(char *const buffer, const size_t size, co // Always overwrite the modification date; We might already have a value here from the // Date header, but this one is more accurate. const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n - baton->response->modified = Seconds(curl_getdate(value.c_str(), nullptr)); + baton->response->modified = SystemClock::from_time_t(curl_getdate(value.c_str(), nullptr)); } else if ((begin = headerMatches("etag: ", buffer, length)) != std::string::npos) { - baton->response->etag = { buffer + begin, length - begin - 2 }; // remove \r\n + baton->response->etag = std::string(buffer + begin, length - begin - 2); // remove \r\n } else if ((begin = headerMatches("cache-control: ", buffer, length)) != std::string::npos) { const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n baton->response->expires = parseCacheControl(value.c_str()); } else if ((begin = headerMatches("expires: ", buffer, length)) != std::string::npos) { const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n - baton->response->expires = Seconds(curl_getdate(value.c_str(), nullptr)); + baton->response->expires = SystemClock::from_time_t(curl_getdate(value.c_str(), nullptr)); } return length; @@ -534,15 +534,15 @@ void HTTPCURLRequest::handleResult(CURLcode code) { if (existingResponse) { response->data = existingResponse->data; - if (response->expires == Seconds::zero()) { + if (!response->expires) { response->expires = existingResponse->expires; } - if (response->modified == Seconds::zero()) { + if (!response->modified) { response->modified = existingResponse->modified; } - if (response->etag.empty()) { + if (!response->etag) { response->etag = existingResponse->etag; } } diff --git a/platform/default/online_file_source.cpp b/platform/default/online_file_source.cpp index 18f166b833..89a9d019f0 100644 --- a/platform/default/online_file_source.cpp +++ b/platform/default/online_file_source.cpp @@ -192,14 +192,13 @@ void OnlineFileRequestImpl::scheduleCacheRequest(OnlineFileSource::Impl& impl) { callback(*response); } - // Force an immediate request if the cached response is stale. Note that this is not - // quite the same as what `expirationTimeout` would calculate, because in `expirationTimeout` - // Seconds::zero() is treated as "no expiration", but here we want it to force a revalidation. - scheduleRealRequest(impl, response && response->expires <= toSeconds(SystemClock::now())); + // Force immediate revalidation if the cached response didn't indicate an expiration. If + // it did indicate an expiration, revalidation will happen in the normal scheduling flow. + scheduleRealRequest(impl, response && !response->expires); }); } -static Seconds errorRetryTimeout(const Response& response, uint32_t failedRequests) { +static Duration errorRetryTimeout(const Response& response, uint32_t failedRequests) { if (response.error && response.error->reason == Response::Error::Reason::Server) { // Retry after one second three times, then start exponential backoff. return Seconds(failedRequests <= 3 ? 1 : 1 << std::min(failedRequests - 3, 31u)); @@ -209,16 +208,15 @@ static Seconds errorRetryTimeout(const Response& response, uint32_t failedReques return Seconds(1 << std::min(failedRequests - 1, 31u)); } else { // No error, or not an error that triggers retries. - return Seconds::max(); + return Duration::max(); } } -static Seconds expirationTimeout(const Response& response) { - // Seconds::zero() is a special value meaning "no expiration". - if (response.expires > Seconds::zero()) { - return std::max(Seconds::zero(), response.expires - toSeconds(SystemClock::now())); +static Duration expirationTimeout(const Response& response) { + if (response.expires) { + return std::max(SystemDuration::zero(), *response.expires - SystemClock::now()); } else { - return Seconds::max(); + return Duration::max(); } } @@ -228,7 +226,7 @@ void OnlineFileRequestImpl::scheduleRealRequest(OnlineFileSource::Impl& impl, bo return; } - Seconds timeout = Seconds::zero(); + Duration timeout = Duration::zero(); // If there was a prior response and we're not being asked for a forced refresh, calculate a timeout // that depends on how many consecutive errors we've encountered, and on the expiration time. @@ -236,7 +234,7 @@ void OnlineFileRequestImpl::scheduleRealRequest(OnlineFileSource::Impl& impl, bo timeout = std::min(errorRetryTimeout(*response, failedRequests), expirationTimeout(*response)); - if (timeout == Seconds::max()) { + if (timeout == Duration::max()) { return; } } diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp index 7e8a56f7f9..5122e01015 100644 --- a/platform/default/sqlite3.cpp +++ b/platform/default/sqlite3.cpp @@ -4,6 +4,8 @@ #include <cassert> #include <cstring> #include <cstdio> +#include <chrono> +#include <experimental/optional> #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-variable" @@ -24,6 +26,9 @@ const static bool sqliteVersionCheck = []() { namespace mapbox { namespace sqlite { +template <typename T> +using optional = std::experimental::optional<T>; + Database::Database(const std::string &filename, int flags) { const int err = sqlite3_open_v2(filename.c_str(), &db, flags, nullptr); if (err != SQLITE_OK) { @@ -105,6 +110,11 @@ void Statement::check(int err) { } } +template <> void Statement::bind(int offset, std::nullptr_t) { + assert(stmt); + check(sqlite3_bind_null(stmt, offset)); +} + template <> void Statement::bind(int offset, int value) { assert(stmt); check(sqlite3_bind_int(stmt, offset, value)); @@ -130,12 +140,33 @@ template <> void Statement::bind(int offset, const char *value) { check(sqlite3_bind_text(stmt, offset, value, -1, SQLITE_STATIC)); } -void Statement::bind(int offset, const std::string &value, bool retain) { +void Statement::bind(int offset, const std::string& value, bool retain) { assert(stmt); check(sqlite3_bind_blob(stmt, offset, value.data(), int(value.size()), retain ? SQLITE_TRANSIENT : SQLITE_STATIC)); } +template <> void Statement::bind(int offset, std::chrono::system_clock::time_point value) { + assert(stmt); + check(sqlite3_bind_int64(stmt, offset, std::chrono::system_clock::to_time_t(value))); +} + +template <> void Statement::bind(int offset, optional<std::string> value) { + if (!value) { + bind(offset, nullptr); + } else { + bind(offset, *value); + } +} + +template <> void Statement::bind(int offset, optional<std::chrono::system_clock::time_point> value) { + if (!value) { + bind(offset, nullptr); + } else { + bind(offset, *value); + } +} + bool Statement::run() { assert(stmt); const int err = sqlite3_step(stmt); @@ -173,6 +204,29 @@ template <> std::string Statement::get(int offset) { }; } +template <> std::chrono::system_clock::time_point Statement::get(int offset) { + assert(stmt); + return std::chrono::system_clock::from_time_t(sqlite3_column_int64(stmt, offset)); +} + +template <> optional<std::string> Statement::get(int offset) { + assert(stmt); + if (sqlite3_column_type(stmt, offset) == SQLITE_NULL) { + return optional<std::string>(); + } else { + return get<std::string>(offset); + } +} + +template <> optional<std::chrono::system_clock::time_point> Statement::get(int offset) { + assert(stmt); + if (sqlite3_column_type(stmt, offset) == SQLITE_NULL) { + return optional<std::chrono::system_clock::time_point>(); + } else { + return get<std::chrono::system_clock::time_point>(offset); + } +} + void Statement::reset() { assert(stmt); sqlite3_reset(stmt); diff --git a/platform/default/sqlite_cache.cpp b/platform/default/sqlite_cache.cpp index 5816467aa5..1980b3dead 100644 --- a/platform/default/sqlite_cache.cpp +++ b/platform/default/sqlite_cache.cpp @@ -332,9 +332,9 @@ void SQLiteCache::Impl::get(const Resource &resource, Callback callback) { // Status codes > 1 indicate an error response->error = std::make_unique<Response::Error>(Response::Error::Reason(status)); } - response->modified = Seconds(getStmt->get<int64_t>(1)); - response->etag = getStmt->get<std::string>(2); - response->expires = Seconds(getStmt->get<int64_t>(3)); + response->modified = getStmt->get<optional<SystemTimePoint>>(1); + response->etag = getStmt->get<optional<std::string>>(2); + response->expires = getStmt->get<optional<SystemTimePoint>>(3); response->data = std::make_shared<std::string>(getStmt->get<std::string>(4)); if (getStmt->get<int>(5)) { // == compressed response->data = std::make_shared<std::string>(util::decompress(*response->data)); @@ -357,7 +357,7 @@ void SQLiteCache::Impl::get(const Resource &resource, Callback callback) { accessedStmt->reset(); } - accessedStmt->bind(1, int64_t(toSeconds(SystemClock::now()).count())); + accessedStmt->bind(1, SystemClock::now()); accessedStmt->bind(2, canonicalURL.c_str()); accessedStmt->run(); } @@ -419,10 +419,10 @@ void SQLiteCache::Impl::put(const Resource& resource, const Response& response) putStmt->bind(2 /* status */, 1 /* success */); } putStmt->bind(3 /* kind */, int(resource.kind)); - putStmt->bind(4 /* modified */, int64_t(response.modified.count())); - putStmt->bind(5 /* etag */, response.etag.c_str()); - putStmt->bind(6 /* expires */, int64_t(response.expires.count())); - putStmt->bind(7 /* accessed */, int64_t(toSeconds(SystemClock::now()).count())); + putStmt->bind(4 /* modified */, response.modified); + putStmt->bind(5 /* etag */, response.etag); + putStmt->bind(6 /* expires */, response.expires); + putStmt->bind(7 /* accessed */, SystemClock::now()); std::string data; if (resource.kind != Resource::SpriteImage && response.data) { @@ -452,7 +452,7 @@ void SQLiteCache::Impl::put(const Resource& resource, const Response& response) } } -void SQLiteCache::Impl::refresh(const Resource& resource, Seconds expires) { +void SQLiteCache::Impl::refresh(const Resource& resource, optional<SystemTimePoint> expires) { try { initializeDatabase(); @@ -466,8 +466,8 @@ void SQLiteCache::Impl::refresh(const Resource& resource, Seconds expires) { } const auto canonicalURL = util::mapbox::canonicalURL(resource.url); - refreshStmt->bind(1, int64_t(toSeconds(SystemClock::now()).count())); - refreshStmt->bind(2, int64_t(expires.count())); + refreshStmt->bind(1, SystemClock::now()); + refreshStmt->bind(2, expires); refreshStmt->bind(3, canonicalURL.c_str()); refreshStmt->run(); } catch (mapbox::sqlite::Exception& ex) { diff --git a/platform/default/sqlite_cache_impl.hpp b/platform/default/sqlite_cache_impl.hpp index aef91efec9..e156532402 100644 --- a/platform/default/sqlite_cache_impl.hpp +++ b/platform/default/sqlite_cache_impl.hpp @@ -3,6 +3,7 @@ #include <mbgl/storage/sqlite_cache.hpp> #include <mbgl/util/chrono.hpp> +#include <mbgl/util/optional.hpp> namespace mapbox { namespace sqlite { @@ -23,7 +24,7 @@ public: void get(const Resource&, Callback); void put(const Resource&, const Response&); - void refresh(const Resource&, Seconds expires); + void refresh(const Resource&, optional<SystemTimePoint> expires); private: void initializeDatabase(); diff --git a/platform/node/src/node_request.cpp b/platform/node/src/node_request.cpp index 8e03a3bc1d..1c8b46b838 100644 --- a/platform/node/src/node_request.cpp +++ b/platform/node/src/node_request.cpp @@ -44,7 +44,6 @@ v8::Handle<v8::Object> NodeRequest::Create(const mbgl::Resource& resource, mbgl: NAN_METHOD(NodeRequest::Respond) { using Error = mbgl::Response::Error; - using Milliseconds = mbgl::Milliseconds; mbgl::Response response; @@ -80,14 +79,14 @@ NAN_METHOD(NodeRequest::Respond) { if (Nan::Has(res, Nan::New("modified").ToLocalChecked()).FromJust()) { const double modified = Nan::Get(res, Nan::New("modified").ToLocalChecked()).ToLocalChecked()->ToNumber()->Value(); if (!std::isnan(modified)) { - response.modified = mbgl::asSeconds(Milliseconds(Milliseconds::rep(modified))); + response.modified = mbgl::SystemClock::from_time_t(modified / 1000); } } if (Nan::Has(res, Nan::New("expires").ToLocalChecked()).FromJust()) { const double expires = Nan::Get(res, Nan::New("expires").ToLocalChecked()).ToLocalChecked()->ToNumber()->Value(); if (!std::isnan(expires)) { - response.expires = mbgl::asSeconds(Milliseconds(Milliseconds::rep(expires))); + response.expires = mbgl::SystemClock::from_time_t(expires / 1000); } } diff --git a/src/mbgl/annotation/annotation_tile.cpp b/src/mbgl/annotation/annotation_tile.cpp index 39dbee408a..a4590ffe30 100644 --- a/src/mbgl/annotation/annotation_tile.cpp +++ b/src/mbgl/annotation/annotation_tile.cpp @@ -44,7 +44,7 @@ std::unique_ptr<FileRequest> AnnotationTileMonitor::monitorTile(const GeometryTi } void AnnotationTileMonitor::update(std::unique_ptr<GeometryTile> tile) { - callback(nullptr, std::move(tile), Seconds::zero(), Seconds::zero()); + callback(nullptr, std::move(tile), {}, {}); } } // namespace mbgl diff --git a/src/mbgl/map/geometry_tile.hpp b/src/mbgl/map/geometry_tile.hpp index dd9a21bc62..e906fed8f3 100644 --- a/src/mbgl/map/geometry_tile.hpp +++ b/src/mbgl/map/geometry_tile.hpp @@ -55,8 +55,8 @@ public: using Callback = std::function<void (std::exception_ptr, std::unique_ptr<GeometryTile>, - Seconds modified, - Seconds expires)>; + optional<SystemTimePoint> modified, + optional<SystemTimePoint> expires)>; /* * Monitor the tile held by this object for changes. When the tile is loaded for the first time, * or updates, the callback is executed. If an error occurs, the first parameter will be set. diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp index 1067c86d3d..fec8ba4901 100644 --- a/src/mbgl/map/tile_data.hpp +++ b/src/mbgl/map/tile_data.hpp @@ -3,6 +3,7 @@ #include <mbgl/util/noncopyable.hpp> #include <mbgl/util/chrono.hpp> +#include <mbgl/util/optional.hpp> #include <mbgl/map/tile_id.hpp> #include <mbgl/renderer/bucket.hpp> #include <mbgl/text/placement_config.hpp> @@ -91,8 +92,8 @@ public: void dumpDebugLogs() const; const TileID id; - Seconds modified = Seconds::zero(); - Seconds expires = Seconds::zero(); + optional<SystemTimePoint> modified; + optional<SystemTimePoint> expires; // Contains the tile ID string for painting debug information. std::unique_ptr<DebugBucket> debugBucket; diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index 9e1390decd..fa08432b20 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -29,8 +29,8 @@ VectorTileData::VectorTileData(const TileID& id_, state = State::loading; tileRequest = monitor->monitorTile([callback, this](std::exception_ptr err, std::unique_ptr<GeometryTile> tile, - Seconds modified_, - Seconds expires_) { + optional<SystemTimePoint> modified_, + optional<SystemTimePoint> expires_) { if (err) { callback(err); return; diff --git a/src/mbgl/renderer/debug_bucket.cpp b/src/mbgl/renderer/debug_bucket.cpp index a1a24eab73..a6663b35c3 100644 --- a/src/mbgl/renderer/debug_bucket.cpp +++ b/src/mbgl/renderer/debug_bucket.cpp @@ -10,7 +10,7 @@ using namespace mbgl; -DebugBucket::DebugBucket(const TileID id, const TileData::State state_, Seconds modified_, Seconds expires_, MapDebugOptions debugMode_) +DebugBucket::DebugBucket(const TileID id, const TileData::State state_, optional<SystemTimePoint> modified_, optional<SystemTimePoint> expires_, MapDebugOptions debugMode_) : state(state_), modified(modified_), expires(expires_), @@ -22,11 +22,11 @@ DebugBucket::DebugBucket(const TileID id, const TileData::State state_, Seconds baseline += 200; } - if (debugMode & MapDebugOptions::Timestamps && modified > Seconds::zero() && expires > Seconds::zero()) { - const std::string modifiedText = "modified: " + util::iso8601(modified.count()); + if (debugMode & MapDebugOptions::Timestamps && modified && expires) { + const std::string modifiedText = "modified: " + util::iso8601(SystemClock::to_time_t(*modified)); fontBuffer.addText(modifiedText.c_str(), 50, baseline, 5); - const std::string expiresText = "expires: " + util::iso8601(expires.count()); + const std::string expiresText = "expires: " + util::iso8601(SystemClock::to_time_t(*expires)); fontBuffer.addText(expiresText.c_str(), 50, baseline + 200, 5); } } diff --git a/src/mbgl/renderer/debug_bucket.hpp b/src/mbgl/renderer/debug_bucket.hpp index 73af338c2c..5c7511ce87 100644 --- a/src/mbgl/renderer/debug_bucket.hpp +++ b/src/mbgl/renderer/debug_bucket.hpp @@ -13,14 +13,17 @@ class PlainShader; class DebugBucket : private util::noncopyable { public: - DebugBucket(TileID id, TileData::State, Seconds modified, Seconds expires, MapDebugOptions); + DebugBucket(TileID id, TileData::State, + optional<SystemTimePoint> modified, + optional<SystemTimePoint> expires, + MapDebugOptions); void drawLines(PlainShader& shader); void drawPoints(PlainShader& shader); const TileData::State state; - const Seconds modified; - const Seconds expires; + const optional<SystemTimePoint> modified; + const optional<SystemTimePoint> expires; const MapDebugOptions debugMode; private: diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp index 0a0900526a..d6b1aec73c 100644 --- a/src/mbgl/renderer/painter_debug.cpp +++ b/src/mbgl/renderer/painter_debug.cpp @@ -25,8 +25,8 @@ void Painter::renderDebugText(TileData& tileData, const mat4 &matrix) { config.depthTest = GL_FALSE; if (!tileData.debugBucket || tileData.debugBucket->state != tileData.getState() - || tileData.debugBucket->modified != tileData.modified - || tileData.debugBucket->expires != tileData.expires + || !(tileData.debugBucket->modified == tileData.modified) + || !(tileData.debugBucket->expires == tileData.expires) || tileData.debugBucket->debugMode != data.getDebug()) { tileData.debugBucket = std::make_unique<DebugBucket>(tileData.id, tileData.getState(), tileData.modified, tileData.expires, data.getDebug()); } diff --git a/src/mbgl/storage/http_request_base.cpp b/src/mbgl/storage/http_request_base.cpp index 8a4a81b291..81be716ff2 100644 --- a/src/mbgl/storage/http_request_base.cpp +++ b/src/mbgl/storage/http_request_base.cpp @@ -5,15 +5,19 @@ namespace mbgl { -Seconds HTTPRequestBase::parseCacheControl(const char *value) { - if (value) { - const auto cacheControl = http::CacheControl::parse(value); - if (cacheControl.maxAge) { - return toSeconds(SystemClock::now()) + Seconds(*cacheControl.maxAge); - } +optional<SystemTimePoint> HTTPRequestBase::parseCacheControl(const char *value) { + if (!value) { + return {}; } - return Seconds::zero(); + const auto cacheControl = http::CacheControl::parse(value); + if (!cacheControl.maxAge) { + return {}; + } + + // Round trip through time_t to truncate fractional seconds. + return SystemClock::from_time_t(SystemClock::to_time_t( + SystemClock::now() + std::chrono::seconds(*cacheControl.maxAge))); } } // namespace mbgl diff --git a/src/mbgl/storage/http_request_base.hpp b/src/mbgl/storage/http_request_base.hpp index 8f1caf7bdc..1a8cf73da6 100644 --- a/src/mbgl/storage/http_request_base.hpp +++ b/src/mbgl/storage/http_request_base.hpp @@ -3,6 +3,7 @@ #include <mbgl/util/noncopyable.hpp> #include <mbgl/util/chrono.hpp> +#include <mbgl/util/optional.hpp> #include <memory> #include <functional> @@ -27,7 +28,7 @@ public: virtual void cancel() { cancelled = true; }; protected: - static Seconds parseCacheControl(const char *value); + static optional<SystemTimePoint> parseCacheControl(const char *value); std::string url; Callback notify; diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index e7ce5385fe..d8eabf00a2 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -120,7 +120,7 @@ void GeoJSONTileMonitor::setGeoJSONVT(mapbox::geojsonvt::GeoJSONVT* vt) { void GeoJSONTileMonitor::update() { if (geojsonvt) { auto tile = convertTile(geojsonvt->getTile(tileID.z, tileID.x, tileID.y)); - callback(nullptr, std::move(tile), Seconds::zero(), Seconds::zero()); + callback(nullptr, std::move(tile), {}, {}); } } diff --git a/test/storage/cache_response.cpp b/test/storage/cache_response.cpp index 511403e840..aa5e5dbfcf 100644 --- a/test/storage/cache_response.cpp +++ b/test/storage/cache_response.cpp @@ -25,9 +25,9 @@ TEST_F(Storage, CacheResponse) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Response 1", *res.data); - EXPECT_LT(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_TRUE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); response = res; // Now test that we get the same values as in the previous request. If we'd go to the server @@ -78,9 +78,9 @@ TEST_F(Storage, CacheNotFound) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("existing data", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); } else if (counter == 1) { EXPECT_NE(nullptr, res.error); EXPECT_EQ(Response::Error::Reason::NotFound, res.error->reason); @@ -135,9 +135,9 @@ TEST_F(Storage, DontCacheConnectionErrors) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("existing data", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); } else if (counter == 1) { EXPECT_NE(nullptr, res.error); EXPECT_EQ(Response::Error::Reason::Connection, res.error->reason); @@ -190,9 +190,9 @@ TEST_F(Storage, DontCacheServerErrors) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("existing data", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); } else if (counter == 1) { EXPECT_NE(nullptr, res.error); EXPECT_EQ(Response::Error::Reason::Server, res.error->reason); diff --git a/test/storage/cache_revalidate.cpp b/test/storage/cache_revalidate.cpp index 483a7edc74..d46f95801e 100644 --- a/test/storage/cache_revalidate.cpp +++ b/test/storage/cache_revalidate.cpp @@ -26,9 +26,9 @@ TEST_F(Storage, CacheRevalidateSame) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Response", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("snowfall", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_EQ("snowfall", *res.etag); // Second request returns the cached response, then immediately revalidates. req2 = fs.request(revalidateSame, [&, res](Response res2) { @@ -42,10 +42,10 @@ TEST_F(Storage, CacheRevalidateSame) { EXPECT_TRUE(res2.notModified); ASSERT_TRUE(res2.data.get()); EXPECT_EQ("Response", *res2.data); - EXPECT_LT(Seconds::zero(), res2.expires); - EXPECT_EQ(Seconds::zero(), res2.modified); + EXPECT_TRUE(bool(res2.expires)); + EXPECT_FALSE(bool(res2.modified)); // We're not sending the ETag in the 304 reply, but it should still be there. - EXPECT_EQ("snowfall", res2.etag); + EXPECT_EQ("snowfall", *res2.etag); loop.stop(); CacheRevalidateSame.finish(); @@ -78,9 +78,9 @@ TEST_F(Storage, CacheRevalidateModified) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Response", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(1420070400, res.modified.count()); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_EQ(SystemClock::from_time_t(1420070400), *res.modified); + EXPECT_FALSE(res.etag); // Second request returns the cached response, then immediately revalidates. req2 = fs.request(revalidateModified, [&, res](Response res2) { @@ -94,9 +94,9 @@ TEST_F(Storage, CacheRevalidateModified) { EXPECT_TRUE(res2.notModified); ASSERT_TRUE(res2.data.get()); EXPECT_EQ("Response", *res2.data); - EXPECT_LT(Seconds::zero(), res2.expires); - EXPECT_EQ(1420070400, res2.modified.count()); - EXPECT_EQ("", res2.etag); + EXPECT_TRUE(bool(res2.expires)); + EXPECT_EQ(SystemClock::from_time_t(1420070400), *res2.modified); + EXPECT_FALSE(res2.etag); loop.stop(); CacheRevalidateModified.finish(); @@ -128,9 +128,9 @@ TEST_F(Storage, CacheRevalidateEtag) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Response 1", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("response-1", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_EQ("response-1", *res.etag); // Second request returns the cached response, then immediately revalidates. req2 = fs.request(revalidateEtag, [&, res](Response res2) { @@ -144,9 +144,9 @@ TEST_F(Storage, CacheRevalidateEtag) { ASSERT_TRUE(res2.data.get()); EXPECT_NE(res.data, res2.data); EXPECT_EQ("Response 2", *res2.data); - EXPECT_EQ(Seconds::zero(), res2.expires); - EXPECT_EQ(Seconds::zero(), res2.modified); - EXPECT_EQ("response-2", res2.etag); + EXPECT_FALSE(bool(res2.expires)); + EXPECT_FALSE(bool(res2.modified)); + EXPECT_EQ("response-2", *res2.etag); loop.stop(); CacheRevalidateEtag.finish(); diff --git a/test/storage/cache_size.cpp b/test/storage/cache_size.cpp index 4ef4371e98..78e3697790 100644 --- a/test/storage/cache_size.cpp +++ b/test/storage/cache_size.cpp @@ -39,8 +39,8 @@ void insertTile(mbgl::SQLiteCache* cache, unsigned id, uint64_t size) { auto url = std::string("http://tile") + mbgl::util::toString(id); Response response; - response.modified = toSeconds(SystemClock::now()); - response.expires = toSeconds(SystemClock::now()) + Seconds(5000); + response.modified = SystemClock::now(); + response.expires = SystemClock::now() + Seconds(5000); response.etag = url; auto data = std::make_shared<std::string>(size, 0); @@ -62,8 +62,8 @@ void refreshTile(mbgl::SQLiteCache* cache, unsigned id) { auto url = std::string("http://tile") + mbgl::util::toString(id); Response response; - response.modified = toSeconds(SystemClock::now()); - response.expires = toSeconds(SystemClock::now()) + Seconds(5000); + response.modified = SystemClock::now(); + response.expires = SystemClock::now() + Seconds(5000); response.notModified = true; Resource resource{ Resource::Kind::Tile, url }; diff --git a/test/storage/cache_stale.cpp b/test/storage/cache_stale.cpp index 96fd9bbbcd..9ad0d1c06e 100644 --- a/test/storage/cache_stale.cpp +++ b/test/storage/cache_stale.cpp @@ -27,7 +27,7 @@ void checkRendering(Map& map, Response expiredItem(const std::string& path) { Response response; response.data = std::make_shared<std::string>(util::read_file("test/fixtures/"s + path)); - response.expires = 0s; + response.expires = SystemClock::from_time_t(0); return response; } diff --git a/test/storage/database.cpp b/test/storage/database.cpp index 700b58ed24..19b46763b9 100644 --- a/test/storage/database.cpp +++ b/test/storage/database.cpp @@ -257,7 +257,7 @@ TEST_F(Storage, DatabaseLockedRefresh) { // Then, try to refresh it. Log::setObserver(std::make_unique<FixtureLogObserver>()); - cache.refresh({ Resource::Unknown, "mapbox://test" }, Seconds::zero()); + cache.refresh({ Resource::Unknown, "mapbox://test" }, {}); cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) { EXPECT_EQ(nullptr, res.get()); }); diff --git a/test/storage/http_cancel.cpp b/test/storage/http_cancel.cpp index 4b6ff75381..4d816c5095 100644 --- a/test/storage/http_cancel.cpp +++ b/test/storage/http_cancel.cpp @@ -43,9 +43,9 @@ TEST_F(Storage, HTTPCancelMultiple) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Hello World!", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); loop.stop(); HTTPCancelMultiple.finish(); }); diff --git a/test/storage/http_error.cpp b/test/storage/http_error.cpp index 159e5a17a1..28e8573a2c 100644 --- a/test/storage/http_error.cpp +++ b/test/storage/http_error.cpp @@ -28,9 +28,9 @@ TEST_F(Storage, HTTPTemporaryError) { EXPECT_EQ("HTTP status code 500", res.error->message); ASSERT_TRUE(res.data.get()); EXPECT_EQ("", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); } break; case 1: { req1.reset(); @@ -40,9 +40,9 @@ TEST_F(Storage, HTTPTemporaryError) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Hello World!", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); loop.stop(); HTTPTemporaryError.finish(); } break; @@ -82,9 +82,9 @@ TEST_F(Storage, HTTPConnectionError) { FAIL(); #endif ASSERT_FALSE(res.data.get()); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); if (counter == 2) { req2.reset(); diff --git a/test/storage/http_header_parsing.cpp b/test/storage/http_header_parsing.cpp index 14bd99bdb3..827aa70abc 100644 --- a/test/storage/http_header_parsing.cpp +++ b/test/storage/http_header_parsing.cpp @@ -21,9 +21,9 @@ TEST_F(Storage, HTTPExpiresParsing) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Hello World!", *res.data); - EXPECT_EQ(1420797926, res.expires.count()); - EXPECT_EQ(1420794326, res.modified.count()); - EXPECT_EQ("foo", res.etag); + EXPECT_EQ(SystemClock::from_time_t(1420797926), res.expires); + EXPECT_EQ(SystemClock::from_time_t(1420794326), res.modified); + EXPECT_EQ("foo", *res.etag); loop.stop(); HTTPExpiresTest.finish(); }); @@ -47,9 +47,9 @@ TEST_F(Storage, HTTPCacheControlParsing) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Hello World!", *res.data); - EXPECT_GT(2, std::abs(res.expires.count() - now.count() - 120)) << "Expiration date isn't about 120 seconds in the future"; - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_GT(2, std::abs(toSeconds(*res.expires).count() - now.count() - 120)) << "Expiration date isn't about 120 seconds in the future"; + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); loop.stop(); HTTPCacheControlTest.finish(); }); diff --git a/test/storage/http_issue_1369.cpp b/test/storage/http_issue_1369.cpp index bf67da0da1..17c6f86f74 100644 --- a/test/storage/http_issue_1369.cpp +++ b/test/storage/http_issue_1369.cpp @@ -36,9 +36,9 @@ TEST_F(Storage, HTTPIssue1369) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Hello World!", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); loop.stop(); HTTPIssue1369.finish(); }); diff --git a/test/storage/http_load.cpp b/test/storage/http_load.cpp index 0750e04cf4..8088bb5e34 100644 --- a/test/storage/http_load.cpp +++ b/test/storage/http_load.cpp @@ -27,9 +27,9 @@ TEST_F(Storage, HTTPLoad) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ(std::string("Request ") + std::to_string(current), *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); if (number <= max) { req(i); diff --git a/test/storage/http_other_loop.cpp b/test/storage/http_other_loop.cpp index 0fbe43b3d3..fda51c3cf3 100644 --- a/test/storage/http_other_loop.cpp +++ b/test/storage/http_other_loop.cpp @@ -19,9 +19,9 @@ TEST_F(Storage, HTTPOtherLoop) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Hello World!", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); loop.stop(); HTTPOtherLoop.finish(); }); diff --git a/test/storage/http_reading.cpp b/test/storage/http_reading.cpp index ba3907eb3a..4d8d510615 100644 --- a/test/storage/http_reading.cpp +++ b/test/storage/http_reading.cpp @@ -23,9 +23,9 @@ TEST_F(Storage, HTTPTest) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Hello World!", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); loop.stop(); HTTPTest.finish(); }); @@ -50,9 +50,9 @@ TEST_F(Storage, HTTP404) { ASSERT_TRUE(res.data.get()); EXPECT_EQ("Cannot GET /doesnotexist\n", *res.data); EXPECT_EQ("HTTP status code 404", res.error->message); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); loop.stop(); HTTP404.finish(); }); @@ -77,9 +77,9 @@ TEST_F(Storage, HTTP500) { ASSERT_TRUE(res.data.get()); EXPECT_EQ("Server Error!", *res.data); EXPECT_EQ("HTTP status code 500", res.error->message); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); loop.stop(); HTTP500.finish(); }); diff --git a/test/storage/http_retry_network_status.cpp b/test/storage/http_retry_network_status.cpp index 1925e714d4..4598b8e402 100644 --- a/test/storage/http_retry_network_status.cpp +++ b/test/storage/http_retry_network_status.cpp @@ -28,9 +28,9 @@ TEST_F(Storage, HTTPNetworkStatusChange) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Response", *res.data); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); loop.stop(); HTTPNetworkStatusChange.finish(); }); @@ -87,9 +87,9 @@ TEST_F(Storage, HTTPNetworkStatusChangePreempt) { FAIL(); #endif ASSERT_FALSE(res.data.get()); - EXPECT_EQ(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_FALSE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); if (counter++ == 1) { req.reset(); diff --git a/test/storage/http_timeout.cpp b/test/storage/http_timeout.cpp index c736dbe05f..8f8a5e2633 100644 --- a/test/storage/http_timeout.cpp +++ b/test/storage/http_timeout.cpp @@ -21,9 +21,9 @@ TEST_F(Storage, HTTPTimeout) { EXPECT_EQ(nullptr, res.error); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Hello World!", *res.data); - EXPECT_LT(Seconds::zero(), res.expires); - EXPECT_EQ(Seconds::zero(), res.modified); - EXPECT_EQ("", res.etag); + EXPECT_TRUE(bool(res.expires)); + EXPECT_FALSE(bool(res.modified)); + EXPECT_FALSE(bool(res.etag)); if (counter == 4) { req.reset(); loop.stop(); |