| // Copyright 2016 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 "peridot/bin/ledger/app/ledger_repository_impl.h" |
| |
| #include <trace/event.h> |
| |
| #include "peridot/bin/ledger/cloud_sync/impl/ledger_sync_impl.h" |
| #include "peridot/bin/ledger/p2p_sync/public/ledger_communicator.h" |
| #include "peridot/bin/ledger/storage/impl/ledger_storage_impl.h" |
| #include "peridot/bin/ledger/sync_coordinator/public/ledger_sync.h" |
| #include "peridot/lib/convert/convert.h" |
| |
| namespace ledger { |
| |
| LedgerRepositoryImpl::LedgerRepositoryImpl( |
| DetachedPath content_path, Environment* environment, |
| std::unique_ptr<SyncWatcherSet> watchers, |
| std::unique_ptr<sync_coordinator::UserSync> user_sync, |
| std::unique_ptr<DiskCleanupManager> disk_cleanup_manager) |
| : content_path_(std::move(content_path)), |
| environment_(environment), |
| encryption_service_factory_(environment), |
| watchers_(std::move(watchers)), |
| user_sync_(std::move(user_sync)), |
| disk_cleanup_manager_(std::move(disk_cleanup_manager)) { |
| bindings_.set_empty_set_handler([this] { CheckEmpty(); }); |
| ledger_managers_.set_on_empty([this] { CheckEmpty(); }); |
| ledger_repository_debug_bindings_.set_empty_set_handler( |
| [this] { CheckEmpty(); }); |
| disk_cleanup_manager_->set_on_empty([this] { CheckEmpty(); }); |
| } |
| |
| LedgerRepositoryImpl::~LedgerRepositoryImpl() {} |
| |
| void LedgerRepositoryImpl::BindRepository( |
| fidl::InterfaceRequest<ledger_internal::LedgerRepository> |
| repository_request) { |
| bindings_.AddBinding(this, std::move(repository_request)); |
| } |
| |
| void LedgerRepositoryImpl::PageIsClosedAndSynced( |
| fxl::StringView ledger_name, storage::PageIdView page_id, |
| fit::function<void(Status, PagePredicateResult)> callback) { |
| LedgerManager* ledger_manager = |
| GetLedgerManager(ledger_name, CreateIfMissing::YES); |
| FXL_DCHECK(ledger_manager); |
| |
| ledger_manager->PageIsClosedAndSynced(page_id, std::move(callback)); |
| } |
| |
| void LedgerRepositoryImpl::PageIsClosedOfflineAndEmpty( |
| fxl::StringView ledger_name, storage::PageIdView page_id, |
| fit::function<void(Status, PagePredicateResult)> callback) { |
| LedgerManager* ledger_manager = |
| GetLedgerManager(ledger_name, CreateIfMissing::YES); |
| FXL_DCHECK(ledger_manager); |
| |
| ledger_manager->PageIsClosedOfflineAndEmpty(page_id, std::move(callback)); |
| } |
| |
| void LedgerRepositoryImpl::DeletePageStorage( |
| fxl::StringView ledger_name, storage::PageIdView page_id, |
| fit::function<void(Status)> callback) { |
| LedgerManager* ledger_manager = |
| GetLedgerManager(ledger_name, CreateIfMissing::YES); |
| FXL_DCHECK(ledger_manager); |
| return ledger_manager->DeletePageStorage(page_id, std::move(callback)); |
| } |
| |
| std::vector<fidl::InterfaceRequest<ledger_internal::LedgerRepository>> |
| LedgerRepositoryImpl::Unbind() { |
| std::vector<fidl::InterfaceRequest<ledger_internal::LedgerRepository>> |
| handles; |
| for (auto& binding : bindings_.bindings()) { |
| handles.push_back(binding->Unbind()); |
| } |
| bindings_.CloseAll(); |
| return handles; |
| } |
| |
| LedgerManager* LedgerRepositoryImpl::GetLedgerManager( |
| convert::ExtendedStringView ledger_name, |
| CreateIfMissing create_if_missing) { |
| FXL_DCHECK(!ledger_name.empty()); |
| |
| // If the Ledger instance is already open return it directly. |
| auto it = ledger_managers_.find(ledger_name); |
| if (it != ledger_managers_.end()) { |
| return &(it->second); |
| } |
| |
| if (create_if_missing == CreateIfMissing::NO) { |
| return nullptr; |
| } |
| |
| std::string name_as_string = convert::ToString(ledger_name); |
| std::unique_ptr<encryption::EncryptionService> encryption_service = |
| encryption_service_factory_.MakeEncryptionService(name_as_string); |
| auto ledger_storage = std::make_unique<storage::LedgerStorageImpl>( |
| environment_, encryption_service.get(), content_path_, name_as_string); |
| std::unique_ptr<sync_coordinator::LedgerSync> ledger_sync; |
| if (user_sync_) { |
| ledger_sync = |
| user_sync_->CreateLedgerSync(name_as_string, encryption_service.get()); |
| } |
| auto result = ledger_managers_.emplace( |
| std::piecewise_construct, std::forward_as_tuple(name_as_string), |
| std::forward_as_tuple(environment_, std::move(name_as_string), |
| std::move(encryption_service), |
| std::move(ledger_storage), std::move(ledger_sync), |
| disk_cleanup_manager_.get())); |
| FXL_DCHECK(result.second); |
| return &(result.first->second); |
| } |
| |
| void LedgerRepositoryImpl::GetLedger( |
| fidl::VectorPtr<uint8_t> ledger_name, |
| fidl::InterfaceRequest<Ledger> ledger_request, GetLedgerCallback callback) { |
| TRACE_DURATION("ledger", "repository_get_ledger"); |
| if (ledger_name->empty()) { |
| callback(Status::INVALID_ARGUMENT); |
| return; |
| } |
| |
| LedgerManager* ledger_manager = |
| GetLedgerManager(ledger_name, CreateIfMissing::YES); |
| FXL_DCHECK(ledger_manager); |
| ledger_manager->BindLedger(std::move(ledger_request)); |
| callback(Status::OK); |
| } |
| |
| void LedgerRepositoryImpl::Duplicate( |
| fidl::InterfaceRequest<ledger_internal::LedgerRepository> request, |
| DuplicateCallback callback) { |
| BindRepository(std::move(request)); |
| callback(Status::OK); |
| } |
| |
| void LedgerRepositoryImpl::SetSyncStateWatcher( |
| fidl::InterfaceHandle<SyncWatcher> watcher, |
| SetSyncStateWatcherCallback callback) { |
| watchers_->AddSyncWatcher(std::move(watcher)); |
| callback(Status::OK); |
| } |
| |
| void LedgerRepositoryImpl::CheckEmpty() { |
| if (!on_empty_callback_) |
| return; |
| if (ledger_managers_.empty() && bindings_.size() == 0 && |
| ledger_repository_debug_bindings_.size() == 0 && |
| disk_cleanup_manager_->IsEmpty()) { |
| on_empty_callback_(); |
| } |
| } |
| |
| void LedgerRepositoryImpl::GetLedgerRepositoryDebug( |
| fidl::InterfaceRequest<ledger_internal::LedgerRepositoryDebug> request, |
| GetLedgerRepositoryDebugCallback callback) { |
| ledger_repository_debug_bindings_.AddBinding(this, std::move(request)); |
| callback(Status::OK); |
| } |
| |
| void LedgerRepositoryImpl::DiskCleanUp(DiskCleanUpCallback callback) { |
| if (clean_up_in_progress_) { |
| callback(Status::ILLEGAL_STATE); |
| return; |
| } |
| clean_up_in_progress_ = true; |
| disk_cleanup_manager_->TryCleanUp( |
| [this, callback = std::move(callback)](Status status) { |
| FXL_DCHECK(clean_up_in_progress_); |
| |
| clean_up_in_progress_ = false; |
| callback(status); |
| }); |
| } |
| |
| void LedgerRepositoryImpl::GetInstancesList(GetInstancesListCallback callback) { |
| fidl::VectorPtr<fidl::VectorPtr<uint8_t>> result = |
| fidl::VectorPtr<fidl::VectorPtr<uint8_t>>::New(0); |
| for (const auto& key_value : ledger_managers_) { |
| result.push_back(convert::ToArray(key_value.first)); |
| } |
| callback(std::move(result)); |
| } |
| |
| void LedgerRepositoryImpl::GetLedgerDebug( |
| fidl::VectorPtr<uint8_t> ledger_name, |
| fidl::InterfaceRequest<ledger_internal::LedgerDebug> request, |
| GetLedgerDebugCallback callback) { |
| auto it = ledger_managers_.find(ledger_name); |
| if (it == ledger_managers_.end()) { |
| callback(Status::KEY_NOT_FOUND); |
| } else { |
| it->second.BindLedgerDebug(std::move(request)); |
| callback(Status::OK); |
| } |
| } |
| |
| } // namespace ledger |