// Copyright (c) 2013 The Chromium 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 NET_DISK_CACHE_SIMPLE_SIMPLE_INDEX_H_
#define NET_DISK_CACHE_SIMPLE_SIMPLE_INDEX_H_
#include <list>
#include <vector>
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/containers/hash_tables.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "net/base/cache_type.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
#if defined(OS_ANDROID)
#include "base/android/application_status_listener.h"
#endif
class Pickle;
class PickleIterator;
namespace disk_cache {
class SimpleIndexDelegate;
class SimpleIndexFile;
struct SimpleIndexLoadResult;
class NET_EXPORT_PRIVATE EntryMetadata {
public:
EntryMetadata();
EntryMetadata(base::Time last_used_time, int entry_size);
base::Time GetLastUsedTime() const;
void SetLastUsedTime(const base::Time& last_used_time);
int GetEntrySize() const { return entry_size_; }
void SetEntrySize(int entry_size) { entry_size_ = entry_size; }
// Serialize the data into the provided pickle.
void Serialize(Pickle* pickle) const;
bool Deserialize(PickleIterator* it);
static base::TimeDelta GetLowerEpsilonForTimeComparisons() {
return base::TimeDelta::FromSeconds(1);
}
static base::TimeDelta GetUpperEpsilonForTimeComparisons() {
return base::TimeDelta();
}
private:
friend class SimpleIndexFileTest;
// When adding new members here, you should update the Serialize() and
// Deserialize() methods.
uint32 last_used_time_seconds_since_epoch_;
int32 entry_size_; // Storage size in bytes.
};
COMPILE_ASSERT(sizeof(EntryMetadata) == 8, metadata_size);
// This class is not Thread-safe.
class NET_EXPORT_PRIVATE SimpleIndex
: public base::SupportsWeakPtr<SimpleIndex> {
public:
typedef std::vector<uint64> HashList;
SimpleIndex(base::SingleThreadTaskRunner* io_thread,
SimpleIndexDelegate* delegate,
net::CacheType cache_type,
scoped_ptr<SimpleIndexFile> simple_index_file);
virtual ~SimpleIndex();
void Initialize(base::Time cache_mtime);
bool SetMaxSize(int max_bytes);
int max_size() const { return max_size_; }
void Insert(uint64 entry_hash);
void Remove(uint64 entry_hash);
// Check whether the index has the entry given the hash of its key.
bool Has(uint64 entry_hash) const;
// Update the last used time of the entry with the given key and return true
// iff the entry exist in the index.
bool UseIfExists(uint64 entry_hash);
void WriteToDisk();
// Update the size (in bytes) of an entry, in the metadata stored in the
// index. This should be the total disk-file size including all streams of the
// entry.
bool UpdateEntrySize(uint64 entry_hash, int entry_size);
typedef base::hash_map<uint64, EntryMetadata> EntrySet;
static void InsertInEntrySet(uint64 entry_hash,
const EntryMetadata& entry_metadata,
EntrySet* entry_set);
// Executes the |callback| when the index is ready. Allows multiple callbacks.
int ExecuteWhenReady(const net::CompletionCallback& callback);
// Returns entries from the index that have last accessed time matching the
// range between |initial_time| and |end_time| where open intervals are
// possible according to the definition given in |DoomEntriesBetween()| in the
// disk cache backend interface.
scoped_ptr<HashList> GetEntriesBetween(const base::Time initial_time,
const base::Time end_time);
// Returns the list of all entries key hash.
scoped_ptr<HashList> GetAllHashes();
// Returns number of indexed entries.
int32 GetEntryCount() const;
// Returns whether the index has been initialized yet.
bool initialized() const { return initialized_; }
private:
friend class SimpleIndexTest;
FRIEND_TEST_ALL_PREFIXES(SimpleIndexTest, IndexSizeCorrectOnMerge);
FRIEND_TEST_ALL_PREFIXES(SimpleIndexTest, DiskWriteQueued);
FRIEND_TEST_ALL_PREFIXES(SimpleIndexTest, DiskWriteExecuted);
FRIEND_TEST_ALL_PREFIXES(SimpleIndexTest, DiskWritePostponed);
void StartEvictionIfNeeded();
void EvictionDone(int result);
void PostponeWritingToDisk();
void UpdateEntryIteratorSize(EntrySet::iterator* it, int entry_size);
// Must run on IO Thread.
void MergeInitializingSet(scoped_ptr<SimpleIndexLoadResult> load_result);
#if defined(OS_ANDROID)
void OnApplicationStateChange(base::android::ApplicationState state);
scoped_ptr<base::android::ApplicationStatusListener> app_status_listener_;
#endif
// The owner of |this| must ensure the |delegate_| outlives |this|.
SimpleIndexDelegate* delegate_;
EntrySet entries_set_;
const net::CacheType cache_type_;
uint64 cache_size_; // Total cache storage size in bytes.
uint64 max_size_;
uint64 high_watermark_;
uint64 low_watermark_;
bool eviction_in_progress_;
base::TimeTicks eviction_start_time_;
// This stores all the entry_hash of entries that are removed during
// initialization.
base::hash_set<uint64> removed_entries_;
bool initialized_;
scoped_ptr<SimpleIndexFile> index_file_;
scoped_refptr<base::SingleThreadTaskRunner> io_thread_;
// All nonstatic SimpleEntryImpl methods should always be called on the IO
// thread, in all cases. |io_thread_checker_| documents and enforces this.
base::ThreadChecker io_thread_checker_;
// Timestamp of the last time we wrote the index to disk.
// PostponeWritingToDisk() may give up postponing and allow the write if it
// has been a while since last time we wrote.
base::TimeTicks last_write_to_disk_;
base::OneShotTimer<SimpleIndex> write_to_disk_timer_;
base::Closure write_to_disk_cb_;
typedef std::list<net::CompletionCallback> CallbackList;
CallbackList to_run_when_initialized_;
// Set to true when the app is on the background. When the app is in the
// background we can write the index much more frequently, to insure fresh
// index on next startup.
bool app_on_background_;
};
} // namespace disk_cache
#endif // NET_DISK_CACHE_SIMPLE_SIMPLE_INDEX_H_