blob: 7d8fcd6a5cd951f9018c2b0f0c50ab1eae0b7d77 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/forensics/crash_reports/snapshot_persistence_metadata.h"
#include <lib/syslog/cpp/macros.h>
#include <filesystem>
#include <string>
#include <utility>
#include "src/developer/forensics/utils/storage_size.h"
#include "src/lib/files/directory.h"
#include "src/lib/files/path.h"
namespace forensics::crash_reports {
namespace fs = std::filesystem;
SnapshotPersistenceMetadata::SnapshotPersistenceMetadata(std::string snapshot_store_root,
StorageSize max_size)
: snapshot_store_root_(std::move(snapshot_store_root)),
max_size_(max_size),
is_directory_usable_(false) {
RecreateFromFilesystem();
}
bool SnapshotPersistenceMetadata::Contains(const std::string& uuid) const {
return snapshot_metadata_.find(uuid) != snapshot_metadata_.end();
}
bool SnapshotPersistenceMetadata::RecreateFromFilesystem() {
current_size_ = StorageSize::Bytes(0);
snapshot_metadata_.clear();
if (!files::IsDirectory(snapshot_store_root_) && !files::CreateDirectory(snapshot_store_root_)) {
FX_LOGS(WARNING) << "Failed to create " << snapshot_store_root_;
is_directory_usable_ = false;
return false;
}
for (const auto& snapshot_dir : fs::directory_iterator(snapshot_store_root_)) {
const auto& snapshot_path = snapshot_dir.path();
const std::string uuid = snapshot_path.filename();
for (const auto& file : fs::directory_iterator(snapshot_dir)) {
const auto& filename = file.path().filename();
if (filename == ".") {
continue;
}
if (snapshot_metadata_.find(uuid) != snapshot_metadata_.end()) {
FX_LOGS(ERROR) << "Found more than 1 file stored in snapshot directory '" << snapshot_dir
<< "'";
continue;
}
std::error_code ec;
const auto snapshot_size = StorageSize::Bytes(fs::file_size(file.path(), ec));
if (ec) {
FX_LOGS(ERROR) << "Failed to read filesize for snapshot uuid '" << uuid << "'";
}
current_size_ += snapshot_size;
snapshot_metadata_[uuid].size = snapshot_size;
snapshot_metadata_[uuid].dir = snapshot_path;
snapshot_metadata_[uuid].snapshot_key = filename;
}
}
is_directory_usable_ = true;
return true;
}
bool SnapshotPersistenceMetadata::IsDirectoryUsable() const { return is_directory_usable_; }
StorageSize SnapshotPersistenceMetadata::CurrentSize() const { return current_size_; }
StorageSize SnapshotPersistenceMetadata::RemainingSpace() const {
return max_size_ - current_size_;
}
const std::string& SnapshotPersistenceMetadata::RootDir() const { return snapshot_store_root_; }
void SnapshotPersistenceMetadata::Add(const std::string& uuid, StorageSize size,
std::string_view archive_key) {
FX_CHECK(IsDirectoryUsable());
current_size_ += size;
snapshot_metadata_[uuid].size = size;
snapshot_metadata_[uuid].dir = files::JoinPath(snapshot_store_root_, uuid);
snapshot_metadata_[uuid].snapshot_key = archive_key;
}
void SnapshotPersistenceMetadata::Delete(const std::string& uuid) {
FX_CHECK(IsDirectoryUsable());
FX_CHECK(Contains(uuid)) << "Contains() should be called before any Delete()";
current_size_ -= snapshot_metadata_[uuid].size;
snapshot_metadata_.erase(uuid);
}
std::vector<std::string> SnapshotPersistenceMetadata::SnapshotUuids() const {
std::vector<std::string> uuids;
for (const auto& [uuid, _] : snapshot_metadata_) {
uuids.push_back(uuid);
}
return uuids;
}
StorageSize SnapshotPersistenceMetadata::SnapshotSize(const std::string& uuid) const {
FX_CHECK(Contains(uuid));
return snapshot_metadata_.at(uuid).size;
}
std::string SnapshotPersistenceMetadata::SnapshotDirectory(const std::string& uuid) const {
FX_CHECK(Contains(uuid));
return snapshot_metadata_.at(uuid).dir;
}
std::string SnapshotPersistenceMetadata::SnapshotKey(const std::string& uuid) const {
FX_CHECK(Contains(uuid));
return snapshot_metadata_.at(uuid).snapshot_key;
}
} // namespace forensics::crash_reports