| // Copyright 2015 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef COBALT_STORAGE_STORAGE_MANAGER_H_ |
| #define COBALT_STORAGE_STORAGE_MANAGER_H_ |
| |
| #include <vector> |
| |
| #include "base/callback.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/message_loop.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "base/threading/thread.h" |
| #include "base/threading/thread_checker.h" |
| #include "base/timer.h" |
| #include "cobalt/storage/savegame_thread.h" |
| #include "cobalt/storage/store/memory_store.h" |
| #include "cobalt/storage/upgrade/upgrade_reader.h" |
| |
| namespace cobalt { |
| namespace storage { |
| |
| // StorageManager manages a store containing cookies and local |
| // storage data. On most platforms, this is written to disk as a savegame |
| // using platform APIs. On Linux/Windows, it's a regular file. |
| // Internally this runs two threads: one thread to perform blocking I/O, |
| // and one where store operations occur. Users are expected to access the |
| // store via an MemoryStore, which can be obtained with GetReadOnlyMemoryStore() |
| // or WithMemoryStore(). The callback to will run on the store thread. |
| // Operations on MemoryStore will block the store thread until the savegame |
| // is loaded. |
| class StorageManager { |
| public: |
| // Support for "upgrade" of legacy save data that may have been generated by |
| // a platform other than Steel/Cobalt. If save data in the upgrade format is |
| // detected, the |OnUpgrade| method will be called on |upgrade_handler_|. |
| class UpgradeHandler { |
| public: |
| virtual ~UpgradeHandler() {} |
| virtual void OnUpgrade(StorageManager* storage, const char* data, |
| int size) = 0; |
| }; |
| |
| struct Options { |
| Savegame::Options savegame_options; |
| }; |
| |
| typedef base::Callback<void(const MemoryStore&)> ReadOnlyMemoryStoreCallback; |
| typedef base::Callback<void(MemoryStore*)> MemoryStoreCallback; |
| |
| StorageManager(scoped_ptr<UpgradeHandler> upgrade_handler, |
| const Options& options); |
| virtual ~StorageManager(); |
| |
| void WithReadOnlyMemoryStore(const ReadOnlyMemoryStoreCallback& callback); |
| void WithMemoryStore(const MemoryStoreCallback& callback); |
| |
| // Schedule a write of our memory store to disk to happen at some point in the |
| // future after a change occurs. Multiple calls to Flush() do not necessarily |
| // result in multiple writes to disk. |
| // This call returns immediately. |
| void FlushOnChange(); |
| |
| // Triggers a write to disk to happen immediately. Each call to FlushNow() |
| // will result in a write to disk. |
| // |callback|, if provided, will be called when the I/O has completed, |
| // and will be run on the storage manager's IO thread. |
| // This call returns immediately. |
| void FlushNow(const base::Closure& callback); |
| |
| const Options& options() const { return options_; } |
| |
| UpgradeHandler* upgrade_handler() const { return upgrade_handler_.get(); } |
| |
| protected: |
| // Queues a flush to be executed as soon as possible. As soon as possible |
| // will be as soon as any existing flush completes, or right away if no |
| // existing flush is happening. Note that it is protected and virtual for |
| // white box testing purposes. |
| virtual void QueueFlush(const base::Closure& callback); |
| |
| private: |
| // Give StorageManagerTest access, so we can more easily test some internals. |
| friend class StorageManagerTest; |
| |
| // Flushes all queued flushes to the savegame thread. |
| void FlushInternal(); |
| |
| // Initialize the store. This blocks until the savegame load is |
| // complete. |
| void FinishInit(); |
| |
| // Stops any timers that are currently running. |
| void StopFlushOnChangeTimers(); |
| |
| // Callback when flush timer has elapsed. |
| void OnFlushOnChangeTimerFired(); |
| |
| // Logic to be executed on the store thread when a flush completes. Will |
| // dispatch |flush_processing_callbacks_| callbacks and execute a new flush |
| // if |flush_requested_| is true. |
| void OnFlushIOCompletedCallback(); |
| |
| // This function will not return until all queued I/O is completed. Since |
| // it will require the store message loop to process, it must be called from |
| // outside the store message loop (such as from StorageManager's destructor). |
| void FinishIO(); |
| |
| // This function will immediately the on change timers if they are running. |
| void FireRunningOnChangeTimers(); |
| |
| // Called by the destructor, to ensure we destroy certain objects on the |
| // store thread |
| void OnDestroy(); |
| |
| // Upgrade handler used if upgrade save data is detected. |
| scoped_ptr<UpgradeHandler> upgrade_handler_; |
| |
| // Configuration options for the Storage Manager. |
| Options options_; |
| |
| // Storage manager runs on its own thread. This is where store |
| // operations are done. |
| scoped_ptr<base::Thread> storage_thread_; |
| scoped_refptr<base::MessageLoopProxy> storage_message_loop_; |
| |
| scoped_ptr<MemoryStore> memory_store_; |
| |
| // When the savegame is loaded at startup, we keep the raw data around |
| // until we can initialize the store on the correct thread. |
| scoped_ptr<Savegame::ByteVector> loaded_raw_bytes_; |
| |
| // Timers that start running when FlushOnChange() is called. When the time |
| // elapses, we actually perform the write. This is a simple form of rate |
| // limiting I/O writes. |
| // |flush_on_last_change_timer_| is re-started on each change, enabling |
| // changes to collect if several happen within a short period of time. |
| // |flush_on_change_max_delay_timer_| starts on the first change and is never |
| // re-started, ensuring that the flush always occurs within its delay and |
| // cannot be pushed back indefinitely. |
| scoped_ptr<base::OneShotTimer<StorageManager> > flush_on_last_change_timer_; |
| scoped_ptr<base::OneShotTimer<StorageManager> > |
| flush_on_change_max_delay_timer_; |
| |
| // See comments for for kDatabaseUserVersion. |
| int loaded_database_version_; |
| // false until the store is fully configured. |
| bool initialized_; |
| |
| // True if a flush is currently being processed on the storage message loop. |
| // In this case, we should not issue more flushes, but instead set |
| // |flush_requested_| to true to ensure that a new flush is submitted as |
| // soon as we are done processing the current one. |
| bool flush_processing_; |
| |
| // The queue of callbacks that are should be called when the current flush |
| // completes. If this is not empty, then |flush_processing_| must be true. |
| std::vector<base::Closure> flush_processing_callbacks_; |
| |
| // True if |flush_processing_| is true, but we would like to perform a new |
| // flush as soon as it completes. |
| bool flush_pending_; |
| |
| // The queue of callbacks that will be called when the flush that follows |
| // the current flush completes. If this is non-empty, then |flush_pending_| |
| // must be true. |
| std::vector<base::Closure> flush_pending_callbacks_; |
| |
| base::WaitableEvent no_flushes_pending_; |
| |
| // An object that wraps Savegame inside of an I/O thread so that we can |
| // flush data asynchronously. |
| scoped_ptr<SavegameThread> savegame_thread_; |
| |
| DISALLOW_COPY_AND_ASSIGN(StorageManager); |
| }; |
| |
| } // namespace storage |
| } // namespace cobalt |
| |
| #endif // COBALT_STORAGE_STORAGE_MANAGER_H_ |