blob: adc1a1b058e84fdec0ab16e8b0c6aa37ba585433 [file] [log] [blame]
// Copyright 2018 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/page_eviction_manager.h"
#include <memory>
#include <utility>
#include <lib/fit/defer.h>
#include <lib/fit/function.h>
#include <lib/fxl/memory/weak_ptr.h>
#include "peridot/bin/ledger/app/page_usage_db.h"
#include "peridot/bin/ledger/app/page_utils.h"
#include "peridot/bin/ledger/coroutine/coroutine.h"
#include "peridot/bin/ledger/coroutine/coroutine_manager.h"
#include "peridot/bin/ledger/environment/environment.h"
#include "peridot/bin/ledger/storage/public/db_factory.h"
namespace ledger {
class PageEvictionManagerImpl : public PageEvictionManager,
public PageEvictionDelegate {
PageEvictionManagerImpl(Environment* environment,
storage::DbFactory* db_factory, DetachedPath db_path);
~PageEvictionManagerImpl() override;
// Initializes this PageEvictionManager. |IO_ERROR| will be returned in case
// of an error while initializing the underlying database.
Status Init();
// Sets the delegate for this PageEvictionManagerImpl. The delegate should
// outlive this object.
void SetDelegate(PageEvictionManager::Delegate* delegate);
// PageEvictionManager:
void set_on_empty(fit::closure on_empty_callback) override;
bool IsEmpty() override;
void TryEvictPages(PageEvictionPolicy* policy,
fit::function<void(Status)> callback) override;
void MarkPageOpened(fxl::StringView ledger_name,
storage::PageIdView page_id) override;
void MarkPageClosed(fxl::StringView ledger_name,
storage::PageIdView page_id) override;
// PageEvictionDelegate:
void TryEvictPage(
fxl::StringView ledger_name, storage::PageIdView page_id,
PageEvictionCondition condition,
fit::function<void(Status, PageWasEvicted)> callback) override;
// A token that performs a given action on destruction. ExpiringToken objects
// are used to keep track of pending operations.
using ExpiringToken = fit::deferred_action<fit::closure>;
// A Completer allowing waiting until the target operation is completed.
class Completer {
// Completes the operation with the given status and unblocks all pending
// |WaitUntilDone| calls. |Complete| can only be called once.
void Complete(Status status);
// Blocks execution until |Complete| is called, and then returns its status.
// If the operation is already completed, |WaitUntilDone| returns
// immediately with the result status.
Status WaitUntilDone(coroutine::CoroutineHandler* handler);
// Marks the Completer as completed with the given status and calls the
// pending callbacks.
void CallCallbacks(Status status);
bool completed_ = false;
Status status_;
// Closures invoked upon completion to unblock the waiting coroutines.
std::vector<fit::closure> callbacks_;
// Removes the page from the local storage.
void EvictPage(fxl::StringView ledger_name, storage::PageIdView page_id,
fit::function<void(Status)> callback);
// Checks whether a page can be evicted. A page can be evicted if it is
// currently closed and either:
// - has no unsynced commits or objects, or
// - is empty and offline, i.e. was never synced to the cloud or a peer.
Status CanEvictPage(coroutine::CoroutineHandler* handler,
fxl::StringView ledger_name, storage::PageIdView page_id,
bool* can_evict);
// Checks whether a page is closed, offline and empty, and thus can be
// evicted.
Status CanEvictEmptyPage(coroutine::CoroutineHandler* handler,
fxl::StringView ledger_name,
storage::PageIdView page_id, bool* can_evict);
// Marks the given page as evicted in the page usage database.
void MarkPageEvicted(std::string ledger_name, storage::PageId page_id);
Status SynchronousTryEvictPage(coroutine::CoroutineHandler* handler,
std::string ledger_name,
storage::PageId page_id,
PageEvictionCondition condition,
PageWasEvicted* was_evicted);
ExpiringToken NewExpiringToken();
Environment* environment_;
// The initialization completer. |Init| method starts marking pages as closed,
// and returns before that operation is done. This completer makes sure that
// all methods accessing the page usage database wait until the initialization
// has finished, before reading or updating information.
Completer initialization_completer_;
// A closure to be called every time all pending operations are completed.
fit::closure on_empty_callback_;
ssize_t pending_operations_ = 0;
PageEvictionManager::Delegate* delegate_ = nullptr;
// |db_factory_| and |db_path_| should only be used during initialization.
// After Init() has been called their contents are no longer valid.
storage::DbFactory* db_factory_;
DetachedPath db_path_;
std::unique_ptr<PageUsageDb> db_;
coroutine::CoroutineManager coroutine_manager_;
// Must be the last member.
fxl::WeakPtrFactory<PageEvictionManagerImpl> weak_factory_;
} // namespace ledger