# Manage data in protected cache

When you work with a catalog in the protected cache, you can download, remove, or update entire regions. It enables you to use OCMAM in full offline mode, where you get a consistent view for the downloaded region at all tile levels.

The following diagram shows a high-level structural view of how to work with map regions.

When you download OCM data from a given catalog to the protected cache, you keep a consistent view of the regions that these catalogs contain and make them available for offline usage.

To download map regions, you need to prefetch them. You can prefetch regions in one or several requests. Before you launch the prefetch process, make sure that, except for prefetch requests, there are no other tasks in progress in the protected cache.

For more information, see the example in examples/load-regions/main.cpp.

1. Create a DataStoreServer instance and add a catalog to it.

Make sure the DataStoreServer instance is always in online mode during the prefetch process. If it is set to Offline mode, all your prefetch requests will be paused.

Note: To omit version discrepancy between data in the mutable and protected caches and easily switch to the version saved in the protected cache, use separate DataStoreClient instances for each of them.

2. To get the list of available regions, run the GetMapRegions method.

Note: If you skip this step, all your prefetch requests will fail.

 std::promise< Response< MapRegionsResult > > promise;

cache_update_manager.GetMapRegions(
catalog_handle,
[&]( Response< MapRegionsResult > response ) { promise.set_value( response ); } );

3. Wait for the response.

 auto response = promise.get_future( ).get( );
if ( !response.IsSuccessful( ) )
{
// process error
return;
}

4. Iterate over the regions to find their IDs.

 const std::vector< std::string > kRegionNamesList = {"Canada", "Mexico", "United States"};
std::vector< uint64_t > requested_region_ids;

const auto map_regions = response.MoveResult( );
map_regions.ForEach( [&]( const datastore::MapRegionsResult::Region& region, const auto& ) {
for ( const auto& name : region.names( ) )
{
// Find the ID that matches the specified language.
if ( name.language( ) == "en" )
{
const std::string& region_name = name.text( );

// Check if the item is present in the region list.
if ( std::find( kRegionNamesList.cbegin( ), kRegionNamesList.cend( ), region_name )
!= kRegionNamesList.cend( ) )
{
// Add IDs for each region.
requested_region_ids.push_back( region.id( ) );

OLP_SDK_LOG_INFO_F(
kLogTag,
region_name.c_str( ), region.id( ), region.parent_id( ) );
}
}
}
} );


For each region, you get its total size and the size of each layer. If there are no regions, you get an error.

5. Create the MapRegionsPrefetchRequest using the IDs of the regions that you want to download and the layer groups.

Note: By default, prefetch requests have low priority (100). If you want to run this request before other tasks, add the WithPriority parameter. The lower the number you specify, the higher the priority.

 auto request = MapRegionsPrefetchRequest( )
.WithMapRegions( requested_region_ids )
.WithPriority(1);


Assets can be prefetched and updated with PrefetchMapRegions or UpdateMapRegions APIs. After the assets are prefetched or updated, you can access the assets by using LoadAssets API in offline.

For more information about LoadAssets API, refer to Obtain assets with LoadAssets API.

1. Prefetch map regions using the catalog handle and the request that you created in step 4.

 std::promise< Response< MapRegionsPrefetchResult > > promise;

auto context = cache_update_manager.PrefetchMapRegions(
catalog_handle, request,
[&]( Response< MapRegionsPrefetchResult > response ) {
promise.set_value( std::move( response ) );
},
[&]( MapRegionPrefetchStatus status ) {
// An optional callback to get the regular prefetch progress.
} );


For each region, you get the status of the prefetch progress with the following information:

• The map region ID
• The number of prefetched bundles
• The number of bundles to prefetch
• The number of transferred bytes
• An error

If the request is successful, you get the kNone error. If you get one of the following retriable errors, the prefetch request is paused: kTimeOut, kFailedToGetResponse, kTooManyRequests, kServiceUnavailable, and kNetworkConnectionError. Fix the issue that causes the error, and then resume the prefetch request.

• The pause state

If the prefetch request is paused or you get a retriable error, the pause flag is set to true. Otherwise, it is set to false.

Also, the CacheUpdateContext instance is automatically created. You can use it to pause, resume, and cancel your prefetch requests.

2. Wait for the response.

 auto response = promise.get_future( ).get( );
if (!response.IsSuccessful())
{
// process error
return;
}

const auto& result = response.GetResult();
// process prefetch result


Now, you have the requested regions in the protected cache, and they are ready for the full offline experience.

## Update map regions

Map regions are not updated automatically. If you need to get a newer version of the catalog in the protected cache, request to update all the regions that it contains or delete the regions that you no longer need before the update. For example, if your prefetched catalog has three regions – Germany, Belgium, and the Netherlands – and you want to get the latest map version for Germany, do one of the following:

• Update the catalog with all the regions that it contains.
• Delete Belgium and the Netherlands, and then update the catalog.

The following diagram shows a detailed view of the incremental update strategy for the protected cache based on map regions:

You can also change the list of prefetched layer groups in the current catalog version.

To update a catalog to a newer version or manage the prefetched layer groups:

1. Create a DataStoreServer instance.

2. To check which version is already in the cache, run the GetAvailableVersion method using the catalog HRN and cache type.

Note: Run this method each time you restart the app to check if catalog data is available offline.

 const auto response = server->GetAvailableVersion( hrn, cache::DefaultCache::CacheType::kProtected );

int64_t available_version = -1;
if ( !response )
{
// There is no stored version in the protected cache.
}
else
{
available_version = response.GetResult( );
}

3. Add the catalog with the newer version to the previously created DataStoreServer instance.

For more information, see the related instruction. You can also add the catalog after the update (step 6). Use the new catalog handle in future operations with this catalog version.

4. Get the cache update manager from the DataStoreServer instance.

 auto& cache_update_manager = server_->GetCacheUpdateManager( );

5. Do one of the following:

• To update map regions included in a catalog to a newer version, create the MapRegionsUpdateRequest request with this version.

Note: If you want to update the catalog to the latest available online version, do not specify the WithTargetVersion parameter.

  const auto request = MapRegionsUpdateRequest( )
.WithTargetVersion( kUpdateCatalogVersion );

• To change the list of the prefetched layer groups, create the MapRegionsUpdateRequest request with the current catalog version and layers that you want to get.

Note: If you do not specify the WithLayerGroups parameter, the list of the prefetched layer groups is unchanged.

  const auto request = MapRegionsUpdateRequest( )
.WithTargetVersion( kUpdateCatalogVersion )
.WithLayerGroups( "search" );


If you do not specify the WithLayerGroups parameter, the list of the prefetched layer groups is unchanged. If you specify fewer layer groups than before, the redundant data is removed. If you specify more layer groups, the extra data is downloaded for the new layer groups.

The request is aborted if one of the following is true:

• The specified version is lower than the currently used offline version.
• The specified version does not exist online.
• You did not specify a catalog version, and there is no new catalog version available online.
6. Run the UpdateMapRegions method.

 std::promise< Response< MapRegionsUpdateResponse > > promise;
auto context = cache_update_manager.UpdateMapRegions(
server_catalog_handle, request,
[&]( Response< MapRegionsUpdateResponse > response ) {
promise.set_value( std::move( response ) );
},
// An optional callback to get the regular update progress.
} );


For each region, you get the status of the prefetch progress with the following information:

• The map region ID
• The number of updated bundles
• The number of bundles to update
• The number of transferred bytes
• An error

If the request is successful, you get the kNone error. If you get one of the following retriable errors, the update request is paused: kTimeOut, kFailedToGetResponse, kTooManyRequests, kServiceUnavailable, and kNetworkConnectionError. Fix the issue that causes the error, and then resume the update request.

• The pause state

If the update request is paused or you get a retriable error, the pause flag is set to true. Otherwise, it is set to false.

Also, the CacheUpdateContext instance is automatically created. You can use it to pause, resume, and cancel your update requests.

7. Wait for the response.

 auto response = promise.get_future( ).get( );
if (!response.IsSuccessful())
{
// process error
return;
}

const auto& result = response.GetResult();
// process update result


## Manage prefetch and update requests

You can pause, resume, or cancel prefetch and update requests after you launch the prefetch or update process using methods of the returned CacheUpdateContext instance:

• To pause a request, run the Pause method, and if you need to optimize cache, set the optimize_cache parameter to true.

  context.Pause( /*optimize_cache =*/ true );


For each region, you get a status where the paused flag is set to true.

The prefetch and update requests are also paused when you get a retriable error or set the DataStoreServer instance to offline mode. For more information, see Offline mode.

• To resume a request:

1. Make sure the DataStoreServer instance is set to online mode, and you have a working network connection.
2. Run the Resume method.

 context.Resume();


For each region, you get a status where the paused flag is set to false.

• To cancel a request, run the Cancel method.

  context.Cancel();


All your prefetch or update requests are canceled. For each region, you get a status with the kRequestCancelled error, and all the prefetched or updated data is deleted.