Skip to content

Commit e0ba039

Browse files
Wrap PrefetchTiles call into CancellationContext. (#1336)
This helps speed-up cancelling of the operation as chain of contexts doesn't break. Previously to this, the `execution_context` was not used internally in the `PrefetchTilesHelper::Prefetch` method which resulted in a break of the cancellation context chain and thus it was not able to cancel all subsequently triggered prefetch jobs from the one master context, which was handed over to the caller of the VersionedLayerClient::PrefetchTiles() API. Due to this then when user actually cancelled the request it would still have to wait for the download to finish until the callback came. Now this is fixed. Relates-To: OLPSUP-17825 Signed-off-by: Andrey Kashcheev <[email protected]> Signed-off-by: Andrei Popescu <[email protected]>
1 parent c0c6445 commit e0ba039

File tree

2 files changed

+185
-157
lines changed

2 files changed

+185
-157
lines changed

olp-cpp-sdk-core/include/olp/core/client/ApiError.h

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,32 +39,50 @@ class CORE_API ApiError {
3939
/**
4040
* @brief Creates the `ApiError` instance with the cancelled error code and
4141
* description.
42-
* @param description The optional description.
42+
*
43+
* @param message The optional description.
44+
*
4345
* @return The `ApiError` instance.
4446
*/
45-
static ApiError Cancelled(const char* description = "Cancelled") {
46-
return ApiError(ErrorCode::Cancelled, description);
47+
static ApiError Cancelled(const char* message = "Cancelled") {
48+
return {ErrorCode::Cancelled, message};
4749
}
4850

4951
/**
5052
* @brief Creates the `ApiError` instance with the network connection error
5153
* code and description.
52-
* @param description The optional description.
54+
*
55+
* @param message The optional description.
56+
*
5357
* @return The `ApiError` instance.
5458
*/
55-
static ApiError NetworkConnection(const char* description = "Offline") {
56-
return ApiError(ErrorCode::NetworkConnection, description);
59+
static ApiError NetworkConnection(const char* message = "Offline") {
60+
return {ErrorCode::NetworkConnection, message};
5761
}
5862

5963
/**
6064
* @brief Creates the `ApiError` instance with the precondition failed error
6165
* code and description.
62-
* @param description The optional description.
66+
*
67+
* @param message The optional description.
68+
*
6369
* @return The `ApiError` instance.
6470
*/
6571
static ApiError PreconditionFailed(
66-
const char* description = "Precondition failed") {
67-
return ApiError(ErrorCode::PreconditionFailed, description);
72+
const char* message = "Precondition failed") {
73+
return {ErrorCode::PreconditionFailed, message};
74+
}
75+
76+
/**
77+
* @brief Creates the `ApiError` instance with the invalid argument error code
78+
* and description.
79+
*
80+
* @param message The optional description.
81+
*
82+
* @return The `ApiError` instance.
83+
*/
84+
static ApiError InvalidArgument(const char* message = "Invalid argument") {
85+
return {ErrorCode::InvalidArgument, message};
6886
}
6987

7088
ApiError() = default;

olp-cpp-sdk-dataservice-read/src/VersionedLayerClientImpl.cpp

Lines changed: 158 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -367,167 +367,177 @@ client::CancellationToken VersionedLayerClientImpl::PrefetchTiles(
367367

368368
client::CancellationContext execution_context;
369369

370-
return task_sink_.AddTask(
371-
[=](client::CancellationContext context) mutable -> void {
372-
if (context.IsCancelled()) {
373-
callback(ApiError::Cancelled());
374-
return;
375-
}
376-
377-
const auto key = request.CreateKey(layer_id_);
378-
379-
if (!settings_.cache) {
380-
OLP_SDK_LOG_ERROR_F(
381-
kLogTag,
382-
"PrefetchPartitions: cache is missing, aborting, hrn=%s, key=%s",
383-
catalog_.ToCatalogHRNString().c_str(), key.c_str());
384-
callback(ApiError::PreconditionFailed(
385-
"Unable to prefetch without a cache"));
386-
return;
387-
}
388-
389-
if (request.GetTileKeys().empty()) {
390-
OLP_SDK_LOG_WARNING_F(
391-
kLogTag, "PrefetchTiles: invalid request, catalog=%s, key=%s",
392-
catalog_.ToCatalogHRNString().c_str(), key.c_str());
393-
callback(ApiError(ErrorCode::InvalidArgument, "Empty tile key list"));
394-
return;
395-
}
396-
397-
auto response =
398-
GetVersion(request.GetBillingTag(), OnlineIfNotFound, context);
370+
execution_context.ExecuteOrCancelled([&]() -> client::CancellationToken {
371+
return task_sink_.AddTask(
372+
[=](client::CancellationContext context) mutable -> void {
373+
if (context.IsCancelled()) {
374+
callback(ApiError::Cancelled());
375+
return;
376+
}
399377

400-
if (!response.IsSuccessful()) {
401-
OLP_SDK_LOG_WARNING_F(
402-
kLogTag, "PrefetchTiles: getting catalog version failed, key=%s",
403-
key.c_str());
404-
callback(response.GetError());
405-
return;
406-
}
378+
const auto key = request.CreateKey(layer_id_);
407379

408-
auto version = response.GetResult().GetVersion();
409-
410-
OLP_SDK_LOG_DEBUG_F(kLogTag, "PrefetchTiles: using key=%s",
411-
key.c_str());
412-
413-
// Calculate the minimal set of Tile keys and depth to
414-
// cover tree.
415-
bool request_only_input_tiles =
416-
!(request.GetMinLevel() <= request.GetMaxLevel() &&
417-
request.GetMaxLevel() < geo::TileKey::LevelCount &&
418-
request.GetMinLevel() < geo::TileKey::LevelCount);
419-
unsigned int min_level =
420-
(request_only_input_tiles
421-
? static_cast<unsigned int>(geo::TileKey::LevelCount)
422-
: request.GetMinLevel());
423-
unsigned int max_level =
424-
(request_only_input_tiles
425-
? static_cast<unsigned int>(geo::TileKey::LevelCount)
426-
: request.GetMaxLevel());
427-
428-
repository::PrefetchTilesRepository repository(
429-
catalog_, layer_id_, settings_, lookup_client_,
430-
request.GetBillingTag(), mutex_storage_);
431-
432-
auto sliced_tiles = repository.GetSlicedTiles(request.GetTileKeys(),
433-
min_level, max_level);
434-
435-
if (sliced_tiles.empty()) {
436-
OLP_SDK_LOG_WARNING_F(kLogTag,
437-
"PrefetchTiles: tile/level mismatch, key=%s",
438-
key.c_str());
439-
callback(
440-
ApiError(ErrorCode::InvalidArgument, "TileKeys/levels mismatch"));
441-
return;
442-
}
380+
if (!settings_.cache) {
381+
OLP_SDK_LOG_ERROR_F(kLogTag,
382+
"PrefetchPartitions: cache is missing, "
383+
"aborting, hrn=%s, key=%s",
384+
catalog_.ToString().c_str(), key.c_str());
385+
callback(ApiError::PreconditionFailed(
386+
"Unable to prefetch without a cache"));
387+
return;
388+
}
443389

444-
OLP_SDK_LOG_DEBUG_F(kLogTag, "PrefetchTiles, subquads=%zu, key=%s",
445-
sliced_tiles.size(), key.c_str());
390+
if (request.GetTileKeys().empty()) {
391+
OLP_SDK_LOG_WARNING_F(
392+
kLogTag, "PrefetchTiles: invalid request, catalog=%s, key=%s",
393+
catalog_.ToString().c_str(), key.c_str());
394+
callback(ApiError::InvalidArgument("Empty tile key list"));
395+
return;
396+
}
446397

447-
const bool aggregation_enabled = request.GetDataAggregationEnabled();
398+
auto response =
399+
GetVersion(request.GetBillingTag(), OnlineIfNotFound, context);
448400

449-
auto filter = [=](repository::SubQuadsResult tiles) mutable
450-
-> repository::SubQuadsResult {
451-
if (request_only_input_tiles) {
452-
return repository.FilterTilesByList(request, std::move(tiles));
453-
} else {
454-
return repository.FilterTilesByLevel(request, std::move(tiles));
401+
if (!response.IsSuccessful()) {
402+
OLP_SDK_LOG_WARNING_F(kLogTag,
403+
"PrefetchTiles: getting catalog version "
404+
"failed, catalog=%s, key=%s",
405+
catalog_.ToString().c_str(), key.c_str());
406+
callback(response.GetError());
407+
return;
455408
}
456-
};
457409

458-
auto query = [=](geo::TileKey root,
459-
client::CancellationContext inner_context) mutable {
460-
auto response = repository.GetVersionedSubQuads(
461-
root, kQuadTreeDepth, version, inner_context);
410+
auto version = response.GetResult().GetVersion();
462411

463-
if (response.IsSuccessful() && aggregation_enabled) {
464-
auto subquads = filter(response.GetResult());
465-
auto network_stats = repository.LoadAggregatedSubQuads(
466-
root, std::move(subquads), version, inner_context);
412+
OLP_SDK_LOG_DEBUG_F(kLogTag, "PrefetchTiles: using key=%s",
413+
key.c_str());
467414

468-
// append network statistics
469-
network_stats += GetNetworkStatistics(response);
470-
response = {response.GetResult(), network_stats};
415+
// Calculate the minimal set of Tile keys and depth to cover tree
416+
bool request_only_input_tiles =
417+
!(request.GetMinLevel() <= request.GetMaxLevel() &&
418+
request.GetMaxLevel() < geo::TileKey::LevelCount &&
419+
request.GetMinLevel() < geo::TileKey::LevelCount);
420+
421+
unsigned int min_level =
422+
(request_only_input_tiles
423+
? static_cast<unsigned int>(geo::TileKey::LevelCount)
424+
: request.GetMinLevel());
425+
unsigned int max_level =
426+
(request_only_input_tiles
427+
? static_cast<unsigned int>(geo::TileKey::LevelCount)
428+
: request.GetMaxLevel());
429+
430+
repository::PrefetchTilesRepository repository(
431+
catalog_, layer_id_, settings_, lookup_client_,
432+
request.GetBillingTag(), mutex_storage_);
433+
434+
auto sliced_tiles = repository.GetSlicedTiles(request.GetTileKeys(),
435+
min_level, max_level);
436+
437+
if (sliced_tiles.empty()) {
438+
OLP_SDK_LOG_WARNING_F(
439+
kLogTag,
440+
"PrefetchTiles: tile/level mismatch, catalog=%s, key=%s",
441+
catalog_.ToString().c_str(), key.c_str());
442+
callback(ApiError::InvalidArgument("TileKeys/levels mismatch"));
443+
return;
471444
}
472445

473-
return response;
474-
};
446+
OLP_SDK_LOG_DEBUG_F(kLogTag, "PrefetchTiles: subquads=%zu, key=%s",
447+
sliced_tiles.size(), key.c_str());
475448

476-
auto& billing_tag = request.GetBillingTag();
477-
auto download = [=](std::string data_handle,
478-
client::CancellationContext inner_context) mutable {
479-
if (data_handle.empty()) {
480-
return BlobApi::DataResponse(
481-
ApiError(ErrorCode::NotFound, "Not found"));
482-
}
483-
repository::DataCacheRepository data_cache_repository(
484-
catalog_, settings_.cache);
485-
if (data_cache_repository.IsCached(layer_id_, data_handle)) {
486-
return BlobApi::DataResponse(nullptr);
487-
}
449+
const bool aggregation_enabled = request.GetDataAggregationEnabled();
488450

489-
repository::DataRepository repository(catalog_, settings_,
490-
lookup_client_, mutex_storage_);
491-
// Fetch from online
492-
return repository.GetVersionedData(
493-
layer_id_,
494-
DataRequest()
495-
.WithDataHandle(std::move(data_handle))
496-
.WithBillingTag(billing_tag),
497-
version, std::move(inner_context), true);
498-
};
499-
500-
std::vector<geo::TileKey> roots;
501-
roots.reserve(sliced_tiles.size());
502-
503-
std::transform(
504-
sliced_tiles.begin(), sliced_tiles.end(), std::back_inserter(roots),
505-
[](const repository::RootTilesForRequest::value_type& root) {
506-
return root.first;
507-
});
508-
509-
auto append_result = [](ExtendedDataResponse response,
510-
geo::TileKey item,
511-
PrefetchTilesResult& prefetch_result) {
512-
if (response.IsSuccessful()) {
513-
prefetch_result.push_back(std::make_shared<PrefetchTileResult>(
514-
item, PrefetchTileNoError()));
515-
} else {
516-
prefetch_result.push_back(std::make_shared<PrefetchTileResult>(
517-
item, response.GetError()));
518-
}
519-
};
520-
521-
auto download_job = std::make_shared<PrefetchTilesHelper::DownloadJob>(
522-
std::move(download), std::move(append_result), std::move(callback),
523-
std::move(status_callback));
524-
525-
return PrefetchTilesHelper::Prefetch(
526-
std::move(download_job), std::move(roots), std::move(query),
527-
std::move(filter), task_sink_, request.GetPriority(),
528-
std::move(context));
529-
},
530-
request.GetPriority(), execution_context);
451+
auto filter = [=](repository::SubQuadsResult tiles) mutable {
452+
if (request_only_input_tiles) {
453+
return repository.FilterTilesByList(request, std::move(tiles));
454+
}
455+
return repository.FilterTilesByLevel(request, std::move(tiles));
456+
};
457+
458+
auto query = [=](geo::TileKey root,
459+
client::CancellationContext inner_context) mutable {
460+
auto response = repository.GetVersionedSubQuads(
461+
root, kQuadTreeDepth, version, inner_context);
462+
463+
if (response.IsSuccessful() && aggregation_enabled) {
464+
auto network_stats = repository.LoadAggregatedSubQuads(
465+
root, filter(response.GetResult()), version, inner_context);
466+
467+
// append network statistics
468+
network_stats += GetNetworkStatistics(response);
469+
response = {response.MoveResult(), network_stats};
470+
}
471+
472+
return response;
473+
};
474+
475+
auto& billing_tag = request.GetBillingTag();
476+
477+
auto download =
478+
[=](std::string data_handle,
479+
client::CancellationContext inner_context) mutable {
480+
if (data_handle.empty()) {
481+
return BlobApi::DataResponse(
482+
ApiError(ErrorCode::NotFound, "Not found"));
483+
}
484+
485+
repository::DataCacheRepository cache(catalog_,
486+
settings_.cache);
487+
488+
if (cache.IsCached(layer_id_, data_handle)) {
489+
return BlobApi::DataResponse(nullptr);
490+
}
491+
492+
repository::DataRepository repository(
493+
catalog_, settings_, lookup_client_, mutex_storage_);
494+
495+
// Fetch from online
496+
return repository.GetVersionedData(
497+
layer_id_,
498+
DataRequest()
499+
.WithDataHandle(std::move(data_handle))
500+
.WithBillingTag(billing_tag),
501+
version, std::move(inner_context), true);
502+
};
503+
504+
std::vector<geo::TileKey> roots;
505+
roots.reserve(sliced_tiles.size());
506+
507+
std::transform(
508+
sliced_tiles.begin(), sliced_tiles.end(),
509+
std::back_inserter(roots),
510+
[](const repository::RootTilesForRequest::value_type& root) {
511+
return root.first;
512+
});
513+
514+
auto append_result = [](ExtendedDataResponse response,
515+
geo::TileKey item,
516+
PrefetchTilesResult& prefetch_result) {
517+
if (response.IsSuccessful()) {
518+
prefetch_result.emplace_back(std::make_shared<PrefetchTileResult>(
519+
item, PrefetchTileNoError()));
520+
} else {
521+
prefetch_result.emplace_back(std::make_shared<PrefetchTileResult>(
522+
item, response.GetError()));
523+
}
524+
};
525+
526+
auto download_job =
527+
std::make_shared<PrefetchTilesHelper::DownloadJob>(
528+
std::move(download), std::move(append_result),
529+
std::move(callback), std::move(status_callback));
530+
531+
return PrefetchTilesHelper::Prefetch(
532+
std::move(download_job), std::move(roots), std::move(query),
533+
std::move(filter), task_sink_, request.GetPriority(),
534+
execution_context);
535+
},
536+
request.GetPriority(), client::CancellationContext{});
537+
});
538+
539+
return client::CancellationToken(
540+
[execution_context]() mutable { execution_context.CancelOperation(); });
531541
}
532542

533543
client::CancellableFuture<PrefetchTilesResponse>

0 commit comments

Comments
 (0)