[core] Fix offline region download freezing

Downloaded resources are put in the buffer and inserted in the database in batches.

Before this change, the buffer was flushed only at the network response callback
and thus it never got flushed if the last required resources were present locally
and did not initiate network requests -> it caused freezing.

Now the buffer is flushed every time the remaining resources container gets empty.
This commit is contained in:
Mikhail Pozdnyakov
2020-02-25 12:44:44 +02:00
parent ba315b4bbb
commit 3c05bd984a
2 changed files with 26 additions and 16 deletions

View File

@@ -40,6 +40,7 @@ private:
void activateDownload();
void continueDownload();
void deactivateDownload();
bool flushResourcesBuffer();
/*
* Ensure that the resource is stored in the database, requesting it if necessary.

View File

@@ -360,10 +360,14 @@ void OfflineDownload::activateDownload() {
the first few errors is fruitless anyway.
*/
void OfflineDownload::continueDownload() {
if (resourcesRemaining.empty() && status.complete()) {
markPendingUsedResources();
setState(OfflineRegionDownloadState::Inactive);
return;
if (resourcesRemaining.empty()) {
// Flush pending buffers.
if (!flushResourcesBuffer()) return;
if (status.complete()) {
markPendingUsedResources();
setState(OfflineRegionDownloadState::Inactive);
return;
}
}
if (resourcesToBeMarkedAsUsed.size() >= kMarkBatchSize) markPendingUsedResources();
@@ -387,6 +391,19 @@ void OfflineDownload::deactivateDownload() {
buffer.clear();
}
bool OfflineDownload::flushResourcesBuffer() {
if (buffer.empty()) return true;
try {
offlineDatabase.putRegionResources(id, buffer, status);
buffer.clear();
observer->statusChanged(status);
return true;
} catch (const MapboxTileLimitExceededException&) {
onMapboxTileCountLimitExceeded();
return false;
}
}
void OfflineDownload::queueResource(Resource&& resource) {
resource.setPriority(Resource::Priority::Low);
resource.setUsage(Resource::Usage::Offline);
@@ -479,18 +496,10 @@ void OfflineDownload::ensureResource(Resource&& resource,
// Queue up for batched insertion
buffer.emplace_back(resource, onlineResponse);
// Flush buffer periodically
if (buffer.size() == kResourcesBatchSize || resourcesRemaining.empty()) {
try {
offlineDatabase.putRegionResources(id, buffer, status);
} catch (const MapboxTileLimitExceededException&) {
onMapboxTileCountLimitExceeded();
return;
}
buffer.clear();
observer->statusChanged(status);
}
// Flush buffer periodically.
// Have to keep `resourcesRemaining.empty()` as the following condition would fail otherwise.
// TODO: Simplify the tile count limit check code path!
if ((buffer.size() == kResourcesBatchSize || resourcesRemaining.empty()) && !flushResourcesBuffer()) return;
if (offlineDatabase.exceedsOfflineMapboxTileCountLimit(resource)) {
onMapboxTileCountLimitExceeded();