-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New command used to manage the local fetch cache. Will eventually be automatically invoked during every `cvd fetch` call to keep the cache from growing without end. Bug: 384803921 Test: cvd help # see summary help Test: cvd help cache Test: cvd cache Test: cvd cache where Test: cvd cache size Test: cvd cache empty Test: cvd cache cleanup Test: cvd cache cleanup --allowed_size_GB=<`cvd cache size` - 1> Test: cvd cache cleanup --allowed_size_GB=-1
- Loading branch information
Showing
6 changed files
with
267 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
212 changes: 212 additions & 0 deletions
212
base/cvd/cuttlefish/host/commands/cvd/cli/commands/cache.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
/* | ||
* Copyright (C) 2024 The Android Open Source Project | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#include "host/commands/cvd/cli/commands/cache.h" | ||
|
||
#include <algorithm> | ||
#include <cstddef> | ||
#include <memory> | ||
#include <string> | ||
#include <string_view> | ||
#include <unordered_map> | ||
#include <vector> | ||
|
||
#include <android-base/logging.h> | ||
#include <fmt/format.h> | ||
|
||
#include "common/libs/utils/files.h" | ||
#include "common/libs/utils/flag_parser.h" | ||
#include "common/libs/utils/result.h" | ||
#include "common/libs/utils/tee_logging.h" | ||
#include "host/commands/cvd/cli/commands/server_handler.h" | ||
#include "host/commands/cvd/cli/types.h" | ||
#include "host/commands/cvd/utils/common.h" | ||
|
||
namespace cuttlefish { | ||
|
||
namespace { | ||
constexpr int kDefaultCacheSizeGigabytes = 25; | ||
|
||
constexpr char kDetailedHelpText[] = | ||
R"(usage: cvd cache <action> [<flag>...] | ||
Example usage: | ||
cvd cache where - display the filepath of the cache | ||
cvd cache size - display the approximate size of the cache | ||
cvd cache cleanup - caps the cache at the default size | ||
cvd cache cleanup --allowed_size_GB=<n> - caps the cache at the given size | ||
cvd cache empty - wipes out all files in the cache directory | ||
**Notes**: | ||
- size and cleanup round the cache size up to the nearest gigabyte for calculating | ||
- cleanup uses last modification time to remove oldest files first | ||
)"; | ||
|
||
constexpr char kSummaryHelpText[] = "Used to manage the files cached by cvd"; | ||
|
||
enum class Action { | ||
Cleanup, | ||
Empty, | ||
Size, | ||
Where, | ||
}; | ||
|
||
struct CacheArguments { | ||
Action action = Action::Where; | ||
std::size_t allowed_size_GB = kDefaultCacheSizeGigabytes; | ||
}; | ||
|
||
std::string GetCacheDirectory() { | ||
const std::string cache_base_path = PerUserDir() + "/cache"; | ||
return cache_base_path; | ||
} | ||
|
||
Result<Action> ToAction(const std::string& key) { | ||
const std::unordered_map<std::string, Action> kMapping{ | ||
{"cleanup", Action::Cleanup}, | ||
{"empty", Action::Empty}, | ||
{"size", Action::Size}, | ||
{"where", Action::Where}, | ||
}; | ||
auto lookup = kMapping.find(key); | ||
CF_EXPECTF(lookup != kMapping.end(), "Unable to find action \"{}\"", key); | ||
return lookup->second; | ||
} | ||
|
||
Result<CacheArguments> ProcessArguments( | ||
const std::vector<std::string>& subcommand_arguments) { | ||
CF_EXPECT(!subcommand_arguments.empty(), | ||
"cvd cache requires at least an action argument. Run `cvd help " | ||
"cache` for details."); | ||
std::vector<std::string> cache_arguments = subcommand_arguments; | ||
std::string action = cache_arguments.front(); | ||
cache_arguments.erase(cache_arguments.begin()); | ||
CacheArguments result{ | ||
.action = CF_EXPECTF(ToAction(action), | ||
"Provided \"{}\" is not a valid cache action. (Is " | ||
"there a non-selector flag before the action?)", | ||
action), | ||
}; | ||
|
||
std::vector<Flag> flags; | ||
flags.emplace_back(GflagsCompatFlag("allowed_size_GB", result.allowed_size_GB) | ||
.Help("Allowed size of the cache during cleanup " | ||
"operation, in gigabytes.")); | ||
flags.emplace_back(UnexpectedArgumentGuard()); | ||
CF_EXPECTF(ConsumeFlags(flags, cache_arguments), | ||
"Failure processing arguments and flags: cvd cache {} {}", action, | ||
fmt::join(cache_arguments, " ")); | ||
|
||
return result; | ||
} | ||
|
||
Result<void> RunCleanup(const std::string& cache_directory, | ||
const std::size_t allowed_size_GB) { | ||
std::size_t cache_size = CF_EXPECT(GetDiskUsageGigabytes(cache_directory)); | ||
// Descending because elements are removed from the back | ||
std::vector<std::string> cache_files = | ||
CF_EXPECT(DirectoryContentsByModTimeDesc(cache_directory)); | ||
std::string next; | ||
while (cache_size > allowed_size_GB) { | ||
CF_EXPECTF(!cache_files.empty(), | ||
"No more files found for deletion, but approximate cache size " | ||
"of {}GB is still larger than allowed {}GB", | ||
cache_size, allowed_size_GB); | ||
next = cache_files.back(); | ||
cache_files.pop_back(); | ||
LOG(DEBUG) << fmt::format("Deleting \"{}\" for cleanup", next); | ||
// handles removal of non-directory top-level files as well | ||
CF_EXPECT(RecursivelyRemoveDirectory( | ||
fmt::format("{}/{}", cache_directory, next))); | ||
cache_size = CF_EXPECT(GetDiskUsageGigabytes(cache_directory)); | ||
} | ||
LOG(INFO) << fmt::format("Cache at \"{}\": ~{}GB of allowed {}GB", | ||
cache_directory, cache_size, allowed_size_GB); | ||
return {}; | ||
} | ||
|
||
Result<void> RunEmpty(const std::string& cache_directory) { | ||
CF_EXPECT(RecursivelyRemoveDirectory(cache_directory)); | ||
CF_EXPECT(EnsureDirectoryExists(cache_directory)); | ||
LOG(INFO) << fmt::format("Cache at \"{}\" has been emptied", cache_directory); | ||
return {}; | ||
} | ||
|
||
Result<void> RunSize(const std::string& cache_directory) { | ||
std::size_t cache_size = CF_EXPECT(GetDiskUsageGigabytes(cache_directory)); | ||
LOG(INFO) << fmt::format("Cache at \"{}\": ~{}GB", cache_directory, | ||
cache_size); | ||
return {}; | ||
} | ||
|
||
void RunWhere(std::string_view cache_directory) { | ||
LOG(INFO) << fmt::format("Cache located at: {}", cache_directory); | ||
} | ||
|
||
class CvdCacheCommandHandler : public CvdServerHandler { | ||
public: | ||
Result<void> Handle(const CommandRequest& request) override; | ||
cvd_common::Args CmdList() const override { return {"cache"}; } | ||
Result<std::string> SummaryHelp() const override; | ||
bool ShouldInterceptHelp() const override { return true; } | ||
Result<std::string> DetailedHelp(std::vector<std::string>&) const override; | ||
}; | ||
|
||
Result<void> CvdCacheCommandHandler::Handle(const CommandRequest& request) { | ||
CF_EXPECT(CanHandle(request)); | ||
auto logger = ScopedTeeLogger(LogToStderr()); | ||
|
||
CacheArguments arguments = | ||
CF_EXPECT(ProcessArguments(request.SubcommandArguments())); | ||
std::string cache_directory = GetCacheDirectory(); | ||
switch (arguments.action) { | ||
case Action::Cleanup: | ||
CF_EXPECTF(RunCleanup(cache_directory, arguments.allowed_size_GB), | ||
"Error capping cache at {} to {}GB", cache_directory, | ||
arguments.allowed_size_GB); | ||
break; | ||
case Action::Empty: | ||
CF_EXPECTF(RunEmpty(cache_directory), "Error emptying cache at {}", | ||
cache_directory); | ||
break; | ||
case Action::Size: | ||
CF_EXPECTF(RunSize(cache_directory), | ||
"Error determining size of cache at {}", cache_directory); | ||
break; | ||
case Action::Where: | ||
RunWhere(cache_directory); | ||
break; | ||
} | ||
|
||
return {}; | ||
} | ||
|
||
Result<std::string> CvdCacheCommandHandler::SummaryHelp() const { | ||
return kSummaryHelpText; | ||
} | ||
|
||
Result<std::string> CvdCacheCommandHandler::DetailedHelp( | ||
std::vector<std::string>&) const { | ||
return kDetailedHelpText; | ||
} | ||
|
||
} // namespace | ||
|
||
std::unique_ptr<CvdServerHandler> NewCvdCacheCommandHandler() { | ||
return std::unique_ptr<CvdServerHandler>(new CvdCacheCommandHandler()); | ||
} | ||
|
||
} // namespace cuttlefish |
27 changes: 27 additions & 0 deletions
27
base/cvd/cuttlefish/host/commands/cvd/cli/commands/cache.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* Copyright (C) 2024 The Android Open Source Project | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <memory> | ||
|
||
#include "host/commands/cvd/cli/commands/server_handler.h" | ||
|
||
namespace cuttlefish { | ||
|
||
std::unique_ptr<CvdServerHandler> NewCvdCacheCommandHandler(); | ||
|
||
} // namespace cuttlefish |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters