| // Copyright 2019 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. |
| |
| #ifndef SRC_LEDGER_BIN_APP_PAGE_MANAGER_H_ |
| #define SRC_LEDGER_BIN_APP_PAGE_MANAGER_H_ |
| |
| #include <lib/fidl/cpp/interface_request.h> |
| #include <lib/fit/function.h> |
| #include <lib/inspect/inspect.h> |
| |
| #include <optional> |
| #include <string> |
| #include <vector> |
| |
| #include "src/ledger/bin/app/active_page_manager_container.h" |
| #include "src/ledger/bin/app/ledger_impl.h" |
| #include "src/ledger/bin/app/merging/ledger_merge_manager.h" |
| #include "src/ledger/bin/app/page_availability_manager.h" |
| #include "src/ledger/bin/app/page_connection_notifier.h" |
| #include "src/ledger/bin/app/page_impl.h" |
| #include "src/ledger/bin/app/page_usage_listener.h" |
| #include "src/ledger/bin/app/types.h" |
| #include "src/ledger/bin/environment/environment.h" |
| #include "src/ledger/bin/storage/public/ledger_storage.h" |
| #include "src/ledger/bin/storage/public/types.h" |
| #include "src/ledger/bin/sync_coordinator/public/ledger_sync.h" |
| |
| namespace ledger { |
| // Manages a ledger page. |
| // |
| // PageManager owns all page-level objects related to a single page: page |
| // storage, and a set of FIDL PageImpls backed by the page storage. It is safe |
| // to delete it at any point - this closes all channels, deletes PageImpls and |
| // tears down the storage. |
| // |
| // When a PageManager becomes empty, client is notified through |
| // |on_empty_callback|. |
| class PageManager { |
| public: |
| PageManager(Environment* environment, std::string ledger_name, |
| storage::PageId page_id, PageUsageListener* page_usage_listener, |
| storage::LedgerStorage* ledger_storage, |
| sync_coordinator::LedgerSync* ledger_sync, |
| LedgerMergeManager* ledger_merge_manager, |
| inspect::Node inspect_node); |
| ~PageManager(); |
| |
| // Checks whether the given page is closed and synced. The result returned in |
| // the callback will be |PAGE_OPENED| if the page is opened after calling this |
| // method and before the callback is called. Otherwise it will be |YES| or |
| // |NO| depending on whether the page is synced or not. |
| void PageIsClosedAndSynced( |
| fit::function<void(storage::Status, PagePredicateResult)> callback); |
| |
| // Checks whether the given page is closed, offline and empty. The result |
| // returned in the callback will be |PAGE_OPENED| if the page is opened after |
| // calling this method and before the callback is called. Otherwise it will be |
| // |YES| or |NO| depending on whether the page is offline and empty or not. |
| void PageIsClosedOfflineAndEmpty( |
| fit::function<void(storage::Status, PagePredicateResult)> callback); |
| |
| // Deletes the local copy of the page. If the page is currently open, the |
| // callback will be called with |ILLEGAL_STATE|. |
| void DeletePageStorage(fit::function<void(storage::Status)> callback); |
| |
| // Keeps track of |callback|. Binds |page| and fires |callback| when a |
| // PageManager is available or an error occurs. |
| void GetPage(LedgerImpl::Delegate::PageState page_state, |
| fidl::InterfaceRequest<Page> page_request, |
| fit::function<void(storage::Status)> callback); |
| |
| // Registers "interest" in this |PageManager| for which this |PageManager| |
| // will remain non-empty and returns a closure that when called will |
| // deregister the "interest" in this |PageManager| (and potentially cause this |
| // |PageManager|'s on_empty_callback_ to be called). |
| fit::closure CreateDetacher(); |
| |
| void set_on_empty(fit::closure on_empty_callback) { |
| on_empty_callback_ = std::move(on_empty_callback); |
| } |
| |
| private: |
| using PageTracker = fit::function<bool()>; |
| |
| // Requests a PageStorage object for the given |container|. If the page is not |
| // locally available, the |callback| is called with |PAGE_NOT_FOUND|. |
| void InitActivePageManagerContainer( |
| ActivePageManagerContainer* container, |
| fit::function<void(storage::Status)> callback); |
| |
| // Creates a page storage for the given |page_id| and completes the |
| // ActivePageManagerContainer. |
| void CreatePageStorage(LedgerImpl::Delegate::PageState page_state, |
| ActivePageManagerContainer* container); |
| |
| // Creates the |ActivePageManagerContainer| for this super manager. |
| ActivePageManagerContainer* CreateActivePageManagerContainer(); |
| |
| // Creates a new |ActivePageManager| for the given storage. |
| std::unique_ptr<ActivePageManager> NewActivePageManager( |
| std::unique_ptr<storage::PageStorage> page_storage, |
| ActivePageManager::PageStorageState state); |
| |
| // Checks whether the page is closed and satisfies the given |predicate|. The |
| // |PagePredicateResult| passed to the given callback will be |PAGE_OPENED| if |
| // the page is opened after calling this method and before the callback is |
| // called. Otherwise it will be |YES| or |NO| depending on whether the |
| // predicate is satisfied. |
| void PageIsClosedAndSatisfiesPredicate( |
| fit::function<void(ActivePageManager*, |
| fit::function<void(storage::Status, bool)>)> |
| predicate, |
| fit::function<void(storage::Status, PagePredicateResult)> callback); |
| |
| // Returns a tracking Callable object for the page. When called, returns |
| // |true| if the page has not been opened until now, and stops tracking the |
| // page. |
| PageTracker NewPageTracker(); |
| |
| // If this page is among those whose usage is being tracked, marks this page |
| // as opened. See also |was_opened_|. |
| void MaybeMarkPageOpened(); |
| |
| void CheckEmpty(); |
| |
| Environment* const environment_; |
| const std::string ledger_name_; |
| const storage::PageId page_id_; |
| PageUsageListener* page_usage_listener_; |
| storage::LedgerStorage* ledger_storage_; |
| sync_coordinator::LedgerSync* ledger_sync_; |
| LedgerMergeManager* ledger_merge_manager_; |
| |
| fit::closure on_empty_callback_; |
| |
| PageAvailabilityManager page_availability_manager_; |
| |
| std::optional<ActivePageManagerContainer> active_page_manager_container_; |
| |
| // TODO(https://fuchsia.atlassian.net/browse/LE-769): Based on the way |
| // was_opened_ is used there may be opportunities to simplify the state that |
| // is maintained in the following fields. |
| // |was_opened_| is used to track whether the page was opened during a given |
| // operation. When |IsClosedAndSatisfiesPredicate| is called, a unique |
| // operation id is added to this vector. The operation id will be deleted from |
| // the vector either when that operation is done, or when the page is opened |
| // because of an external request. This guarantees that if before calling the |
| // callback of |PageIsClosedAndSatisfiesPredicate|, the operation id is still |
| // present in the vector, the page was not opened during that operation. |
| // Otherwise, the page was opened, and |PAGE_OPENED| should be returned. |
| std::vector<uint64_t> was_opened_; |
| uint64_t was_opened_id_ = 0; |
| // |outstanding_operations_| counts the number of active tracking operations. |
| // The super manager is not empty until all operations have completed. |
| uint64_t outstanding_operations_ = 0; |
| |
| // The static Inspect object maintaining in Inspect a representation of this |
| // |PageManager|. |
| inspect::Node inspect_node_; |
| // The static Inspect object to which this |PageManager|'s commits are |
| // attached. |
| inspect::Node commits_node_; |
| fit::deferred_callback children_manager_retainer_; |
| |
| // A nonnegative count of the number of "registered interests" for this |
| // |PageManager|. This field is incremented by calls to |CreateDetacher| and |
| // decremented by calls to the closures returned by calls to |CreateDetacher|. |
| // This |PageManager| is not considered empty while this number is positive. |
| int64_t outstanding_detachers_ = 0; |
| |
| // Must be the last member. |
| fxl::WeakPtrFactory<PageManager> weak_factory_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(PageManager); |
| }; |
| |
| } // namespace ledger |
| |
| #endif // SRC_LEDGER_BIN_APP_PAGE_MANAGER_H_ |