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

[Merged][core] Deprioritize offline downloads #13019

Merged
merged 3 commits into from
Oct 23, 2018

Conversation

chaupow
Copy link
Contributor

@chaupow chaupow commented Oct 3, 2018

Working towards targeting #12655:

This issue covers prioritizing all regular requests, i.e. all requests necessary to show the current map view, above offline download request. This should resolve the issue outlined in #11461.

Current approach:

  • Add a priority-aware logic to favour "regular" requests over offline requests
    • currently implemented by adding two queues in OnlineFileSource
  • Set requests made by OfflineDownload to low priority
    • currently realised by adding a bool isLowPriority flag to Resource

Todos:

  • implement current approach
  • get feedback on approach
    • currently, offline requests set their resources to low priority by calling setLowPriority() here. Would it be better to set the priority flag via an input parameter in the constructors? Should it be a parameter that defaults to zero? Or would it be better to enforce it being set explicitly?
  • test whether this is actually working as intended
  • check manually if there's an improvement by downloading data and scrolling in the app
  • clean up code
    • rename commit messages to precede with [core]
  • get a code review

related work: #12910

@chaupow chaupow force-pushed the deprioritize_offline_downloads branch 5 times, most recently from 719c4da to 843b8b5 Compare October 5, 2018 09:14
@friedbunny friedbunny added feature performance Speed, stability, CPU usage, memory usage, or power usage offline Core The cross-platform C++ core, aka mbgl labels Oct 5, 2018
Kind kind;
LoadingMethod loadingMethod;
std::string url;
std::size_t isLowPriority;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a boolean or enum would better convey the fact that this is a flag, and not a scalar type.

// context: https://github.com/mapbox/mapbox-gl-native/issues/12655
PendingRequests() : prioritizedPendingRequestsList(2), prioritizedPendingRequestsMap(2) {}

std::vector<std::list<OnlineFileRequest*>> prioritizedPendingRequestsList;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using std::array<std::list<OnlineFileRequest*>, 2> conveys the intention better: a std::vector is resizable and uses dynamically allocated memory, while a std::array is fixed size and is stored inline.

it = prioritizedPendingRequestsMap[1].find(request);
if (it != prioritizedPendingRequestsMap[1].end()) {
prioritizedPendingRequestsList[1].erase(it->second);
prioritizedPendingRequestsMap[1].erase(it);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To reduce code duplication, you could wrap the list + map together in one class, and handle the prioritization outside of the class.

PendingRequests() : prioritizedPendingRequestsList(2), prioritizedPendingRequestsMap(2) {}

std::vector<std::list<OnlineFileRequest*>> prioritizedPendingRequestsList;
std::vector<std::unordered_map<OnlineFileRequest*, std::list<OnlineFileRequest*>::iterator>> prioritizedPendingRequestsMap;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original code used a list and a map with request pointer -> list iterator and was added in f5b521f, but I'm not convinced that we need two separate data structures here. Given that the number of requests we have in the queue is usually pretty small (<100), a linear search in the queue might be just as fast and would simplify the logic quite a bit.

else {
assert(num_high_priority_requests <= (int) queue.size());
auto new_pos = queue.begin();
for (int i = 0; i < num_high_priority_requests; i++) new_pos++;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of this iterator increment - you could replace num_high_priority_requests with the iterator to the last inserted high priority request. Regular insertions can then be made without traversing the list. When removing/popping requests, an additional check is needed before the removal/pop to ensure that the lastHighPriorityRequest iterator points to a valid list entry.

tileData(std::move(tileData_)) {
}

void setLowPriority() { isLowPriority = true; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would an enum with regular and low/background be more appropriate here?

@chaupow chaupow force-pushed the deprioritize_offline_downloads branch 11 times, most recently from ebb0026 to c2a949c Compare October 18, 2018 08:51
@chaupow
Copy link
Contributor Author

chaupow commented Oct 18, 2018

Tests pass, I have cleaned up the commit history and it is rebased to current master.

@kkaefer or @asheemmamoowala mind taking another look? 🙂

Wrt to the needed changes for setting the number of maximum concurrent requests, I have opened another separate issue here #13130 and was thinking on working on that next as a follow-up issue of this PR.

@chaupow chaupow changed the title [WIP][core] Deprioritize offline downloads [Waiting for review][core] Deprioritize offline downloads Oct 18, 2018
Copy link
Contributor

@asheemmamoowala asheemmamoowala left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved pending a few nit picks

@@ -169,13 +156,80 @@ class OnlineFileSource::Impl {
networkIsReachableAgain();
}

void setMaximumConcurrentRequestsOverride(const uint32_t maximum_concurrent_requests_override_) {
maximum_concurrent_requests_override = maximum_concurrent_requests_override_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use camelCase for variable names

void networkIsReachableAgain() {
for (auto& request : allRequests) {
request->networkIsReachableAgain();
}
}


struct PendingRequests {
PendingRequests() : queue(), first_low(queue.begin()) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: nit: use camelCase for variable names. Also expand first_low to firstLowPriorityRequest

Copy link
Member

@kkaefer kkaefer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are we handling requests that get added to the queue with a low priority, then another request comes in that has standard priority? Are they getting upgraded?

@@ -24,6 +24,11 @@ class Resource {
Image
};

enum Priority : uint8_t {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use an enum class here. Ideally the type would be bool

@chaupow chaupow force-pushed the deprioritize_offline_downloads branch 2 times, most recently from 969cd07 to 25f659a Compare October 19, 2018 12:55
@chaupow
Copy link
Contributor Author

chaupow commented Oct 22, 2018

Changed some small fixups according to the comments 🙂

Gonna merge now as soon as GH is back 🎉 Thanks for helping pushing it through, everyone! ❤️✨


How are we handling requests that get added to the queue with a low priority, then another request comes in that has standard priority? Are they getting upgraded?

Currently, the requests would not be upgraded but appear in the queue twice. If we request a resource A and there is a request A1 with low priority and we request it a second time with a regular priority in request A2, both will be in the queue, A2 will be processed first and then we will process A1

As far I understand, there is no deduplication logic in online_file_source. The default_file_source has some logic to not request resources if they're already in the offline database here but as soon as the requests are in the queue, there is no deduplication (please correct me if wrong).

This is something that can be checked before we insert a request in a queue but the benefit is probably not too high to do it now.

- priorities can be low or regular
- offline downloads should have low priority to not throttle "regular requests"
- only process low priority requests (=offline requests) if there are no outstanding regular requests
- favour regular requests over low priority ones
- ensure that low priority requests are handled last
- add option to set the number of maximum concurrent requests for tests
- some style fixups
@chaupow chaupow force-pushed the deprioritize_offline_downloads branch from 25f659a to eedf8cf Compare October 22, 2018 13:03
@chaupow chaupow merged commit fa78bca into master Oct 23, 2018
@chaupow chaupow deleted the deprioritize_offline_downloads branch October 23, 2018 10:47
@chaupow chaupow changed the title [Waiting for review][core] Deprioritize offline downloads [Merged][core] Deprioritize offline downloads Oct 23, 2018
@friedbunny friedbunny added the needs changelog Indicates PR needs a changelog entry prior to merging. label Oct 23, 2018
@friedbunny friedbunny added this to the release-h milestone Oct 24, 2018
@friedbunny friedbunny removed needs changelog Indicates PR needs a changelog entry prior to merging. labels Oct 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Core The cross-platform C++ core, aka mbgl feature offline performance Speed, stability, CPU usage, memory usage, or power usage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants