in services/library/src/main/java/com/google/cloud/pso/bq_snapshot_manager/services/scan/ResourceScannerImpl.java [150:206]
public Tuple<String, String> getParentFolderId(String projectId, String runId) throws IOException {
/**
* Resource Manager API has a rate limit of 10 GET operations per second. This means that
* looking up the folder for each table (for thousands of tables) is not scalable.
* For that we use a cache layer to store the project-folder pairs in the scope of each run (to address cache invalidation)
*/
// 1. Lookup the project in the cache
// construct a key including the pro
String keyStr = generateProjectFolderCacheKey(projectId, runId);
Key projectFolderKey = datastore.newKeyFactory().setKind(DATASTORE_KIND).newKey(keyStr);
Entity projectFolderEntity = datastore.get(projectFolderKey);
if(projectFolderEntity == null){
// 2.a project-folder entity doesn't exist in the cache
// 2.a.1. Query the Resource Manager API
String parentFolderFromApi = cloudResourceManager
.projects()
.get(String.format("projects/%s", projectId))
.execute()
.getParent();
// API returns "folders/folder_name" and we just return folder_name
String parentFolderFinal = parentFolderFromApi.startsWith("folders/")?
parentFolderFromApi.substring(8):
null;
Timestamp now = Timestamp.now();
// 2.a.2. Add it to the cache
projectFolderEntity = Entity.newBuilder(projectFolderKey)
.set("project", projectId)
.set("parent_folder", parentFolderFinal)
.set("run_id", runId)
.set("updated_at", now)
.set("expires_at", Utils.addSeconds(now, Utils.SECONDS_IN_DAY)) // TTL 1 day
.build();
datastore.put(projectFolderEntity);
// 2.a.3 return it to the caller
return Tuple.of(parentFolderFinal, PROJECT_FOLDER_LKP_SRC_API);
}else{
String projectFolderFromCache = projectFolderEntity
.getValue("parent_folder")
.get()
.toString();
// project-folder entity exist in the cache
// 2.b.1 Return from cache
return Tuple.of(projectFolderFromCache, PROJECT_FOLDER_LKP_SRC_CACHE);
}
}