blob: c19a6460f23cb070c84b20f710659f8b58305f7a [file] [log] [blame]
// 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.
#ifndef SRC_LEDGER_BIN_APP_LEDGER_MANAGER_H_
#define SRC_LEDGER_BIN_APP_LEDGER_MANAGER_H_
#include <fuchsia/ledger/internal/cpp/fidl.h>
#include <lib/callback/auto_cleanable.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fit/function.h>
#include <lib/inspect/inspect.h>
#include <functional>
#include <map>
#include <memory>
#include <type_traits>
#include "peridot/lib/convert/convert.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_manager.h"
#include "src/ledger/bin/app/page_manager_container.h"
#include "src/ledger/bin/app/page_usage_listener.h"
#include "src/ledger/bin/app/types.h"
#include "src/ledger/bin/encryption/public/encryption_service.h"
#include "src/ledger/bin/environment/environment.h"
#include "src/ledger/bin/fidl/error_notifier.h"
#include "src/ledger/bin/fidl/error_notifier/error_notifier_binding.h"
#include "src/ledger/bin/storage/public/types.h"
#include "src/ledger/bin/sync_coordinator/public/ledger_sync.h"
#include "src/lib/fxl/macros.h"
#include "src/lib/fxl/memory/weak_ptr.h"
#include "src/lib/fxl/strings/string_view.h"
namespace ledger {
// Manages a ledger instance. A ledger instance represents the data scoped to a
// particular user and a particular client app.
//
// LedgerManager owns all per-ledger-instance objects: LedgerStorage and a FIDL
// LedgerImpl. It is safe to delete it at any point - this closes all channels,
// deletes the LedgerImpl and tears down the storage.
class LedgerManager : public LedgerImpl::Delegate {
public:
LedgerManager(
Environment* environment, std::string ledger_name,
inspect::Node inspect_node,
std::unique_ptr<encryption::EncryptionService> encryption_service,
std::unique_ptr<storage::LedgerStorage> storage,
std::unique_ptr<sync_coordinator::LedgerSync> ledger_sync,
PageUsageListener* page_usage_listener);
~LedgerManager() override;
// Creates a new proxy for the LedgerImpl managed by this LedgerManager.
void BindLedger(fidl::InterfaceRequest<Ledger> ledger_request);
// 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(
storage::PageIdView page_id,
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(
storage::PageIdView page_id,
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(convert::ExtendedStringView page_id,
fit::function<void(storage::Status)> callback);
// LedgerImpl::Delegate:
void GetPage(convert::ExtendedStringView page_id, PageState page_state,
fidl::InterfaceRequest<Page> page_request,
fit::function<void(storage::Status)> callback) override;
void SetConflictResolverFactory(
fidl::InterfaceHandle<ConflictResolverFactory> factory) override;
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 InitPageManagerContainer(PageManagerContainer* container,
convert::ExtendedStringView page_id,
fit::function<void(storage::Status)> callback);
// Creates a page storage for the given |page_id| and completes the
// PageManagerContainer.
void CreatePageStorage(storage::PageId page_id, PageState page_state,
PageManagerContainer* container);
// Adds a new PageManagerContainer for |page_id| and configures it so that it
// is automatically deleted from |page_managers_| when the last local client
// disconnects from the page. Returns the container.
PageManagerContainer* AddPageManagerContainer(storage::PageIdView page_id);
// Creates a new page manager for the given storage.
std::unique_ptr<PageManager> NewPageManager(
std::unique_ptr<storage::PageStorage> page_storage,
PageManager::PageStorageState state);
// Checks whether the given page is closed and staisfies the given
// |predicate|. 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
// predicate is satisfied.
void PageIsClosedAndSatisfiesPredicate(
storage::PageIdView page_id,
fit::function<void(PageManager*,
fit::function<void(storage::Status, bool)>)>
predicate,
fit::function<void(storage::Status, PagePredicateResult)> callback);
// Returns a tracking Callable object for the given page. When called, returns
// |true| if the page has not been opened until now, and stops tracking the
// page.
PageTracker NewPageTracker(storage::PageIdView page_id);
// If the page is among the ones whose usage is being tracked, marks this page
// as opened. See also |page_was_opened_map_|.
void MaybeMarkPageOpened(storage::PageIdView page_id);
void CheckEmpty();
Environment* const environment_;
std::string ledger_name_;
std::unique_ptr<encryption::EncryptionService> encryption_service_;
// |storage_| must outlive objects containing CommitWatchers, which includes
// |ledger_sync_| and |page_managers_|.
std::unique_ptr<storage::LedgerStorage> storage_;
std::unique_ptr<sync_coordinator::LedgerSync> ledger_sync_;
LedgerImpl ledger_impl_;
// |merge_manager_| must be destructed after |page_managers_| to ensure it
// outlives any page-specific merge resolver.
LedgerMergeManager merge_manager_;
callback::AutoCleanableSet<
ErrorNotifierBinding<fuchsia::ledger::LedgerErrorNotifierDelegate>>
bindings_;
// Mapping from each page id to the manager of that page.
callback::AutoCleanableMap<storage::PageId, PageManagerContainer,
convert::StringViewComparator>
page_managers_;
PageUsageListener* page_usage_listener_;
fit::closure on_empty_callback_;
PageAvailabilityManager page_availability_manager_;
// |page_was_opened_map_| is used to track whether certain pages were opened
// during a given operation. When |PageIsClosedAndSatisfiesPredicate()| is
// called, an entry is added in this map, with the given page_id as key, while
// a unique operation id is added in the corresponding value. That entry will
// be deleted 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 entry is still present
// in the map, the page was not opened during that operation. Otherwise, it
// was, and |PAGE_OPENED| should be returned.
std::map<storage::PageId, std::vector<uint64_t>> page_was_opened_map_;
uint64_t page_was_opened_id_ = 0;
// |tracked_pages_| counts the number of active page-tracking operations. The
// manager is not empty until all operations have completed.
uint64_t tracked_pages_ = 0;
// The static Inspect object maintaining in Inspect a representation of this
// LedgerManager.
inspect::Node inspect_node_;
// Must be the last member.
fxl::WeakPtrFactory<LedgerManager> weak_factory_;
FXL_DISALLOW_COPY_AND_ASSIGN(LedgerManager);
};
} // namespace ledger
#endif // SRC_LEDGER_BIN_APP_LEDGER_MANAGER_H_