| // 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. |
| |
| #ifndef PERIDOT_BIN_LEDGER_APP_PAGE_EVICTION_MANAGER_IMPL_H_ |
| #define PERIDOT_BIN_LEDGER_APP_PAGE_EVICTION_MANAGER_IMPL_H_ |
| |
| #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 { |
| public: |
| 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; |
| |
| private: |
| // 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 { |
| public: |
| Completer(); |
| |
| ~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); |
| |
| private: |
| // 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_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(Completer); |
| }; |
| |
| // 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_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(PageEvictionManagerImpl); |
| }; |
| |
| } // namespace ledger |
| |
| #endif // PERIDOT_BIN_LEDGER_APP_PAGE_EVICTION_MANAGER_IMPL_H_ |