1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
|
// Copyright 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 CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_H_
#define CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_H_
#include <map>
#include <string>
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "content/common/content_export.h"
#include "content/common/dom_storage/dom_storage_types.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
class GURL;
namespace leveldb {
class DB;
struct ReadOptions;
class WriteBatch;
} // namespace leveldb
namespace content {
// SessionStorageDatabase holds the data from multiple namespaces and multiple
// origins. All DOMStorageAreas for session storage share the same
// SessionStorageDatabase.
// Only one thread is allowed to call the public functions other than
// ReadAreaValues and ReadNamespacesAndOrigins. Other threads are allowed to
// call ReadAreaValues and ReadNamespacesAndOrigins.
class CONTENT_EXPORT SessionStorageDatabase :
public base::RefCountedThreadSafe<SessionStorageDatabase> {
public:
explicit SessionStorageDatabase(const base::FilePath& file_path);
// Reads the (key, value) pairs for |namespace_id| and |origin|. |result| is
// assumed to be empty and any duplicate keys will be overwritten. If the
// database exists on disk then it will be opened. If it does not exist then
// it will not be created and |result| will be unmodified.
void ReadAreaValues(const std::string& namespace_id,
const GURL& origin,
DOMStorageValuesMap* result);
// Updates the data for |namespace_id| and |origin|. Will remove all keys
// before updating the database if |clear_all_first| is set. Then all entries
// in |changes| will be examined - keys mapped to a null NullableString16 will
// be removed and all others will be inserted/updated as appropriate. It is
// allowed to write data into a shallow copy created by CloneNamespace, and in
// that case the copy will be made deep before writing the values.
bool CommitAreaChanges(const std::string& namespace_id,
const GURL& origin,
bool clear_all_first,
const DOMStorageValuesMap& changes);
// Creates shallow copies of the areas for |namespace_id| and associates them
// with |new_namespace_id|.
bool CloneNamespace(const std::string& namespace_id,
const std::string& new_namespace_id);
// Deletes the data for |namespace_id| and |origin|.
bool DeleteArea(const std::string& namespace_id, const GURL& origin);
// Deletes the data for |namespace_id|.
bool DeleteNamespace(const std::string& namespace_id);
// Reads the namespace IDs and origins present in the database.
bool ReadNamespacesAndOrigins(
std::map<std::string, std::vector<GURL> >* namespaces_and_origins);
private:
friend class base::RefCountedThreadSafe<SessionStorageDatabase>;
class DBOperation;
friend class SessionStorageDatabase::DBOperation;
friend class SessionStorageDatabaseTest;
~SessionStorageDatabase();
// Opens the database at file_path_ if it exists already and creates it if
// |create_if_needed| is true. Returns true if the database was opened, false
// if the opening failed or was not necessary (the database doesn't exist and
// |create_if_needed| is false). The possible failures are:
// - leveldb cannot open the database.
// - The database is in an inconsistent or errored state.
bool LazyOpen(bool create_if_needed);
// Tries to open the database at file_path_, assigns |db| to point to the
// opened leveldb::DB instance.
leveldb::Status TryToOpen(leveldb::DB** db);
// Returns true if the database is already open, false otherwise.
bool IsOpen() const;
// Helpers for checking caller erros, invariants and database errors. All
// these return |ok|, for chaining.
bool CallerErrorCheck(bool ok) const;
bool ConsistencyCheck(bool ok);
bool DatabaseErrorCheck(bool ok);
// Helper functions. All return true if the operation succeeded, and false if
// it failed (a database error or a consistency error). If the return type is
// void, the operation cannot fail. If they return false, ConsistencyCheck or
// DatabaseErrorCheck have already been called.
// Creates a namespace for |namespace_id| and updates the next namespace id if
// needed. If |ok_if_exists| is false, checks that the namespace didn't exist
// before.
bool CreateNamespace(const std::string& namespace_id,
bool ok_if_exists,
leveldb::WriteBatch* batch);
// Reads the areas assoiated with |namespace_id| and puts the (origin, map_id)
// pairs into |areas|.
bool GetAreasInNamespace(const std::string& namespace_id,
std::map<std::string, std::string>* areas);
// Adds an association between |origin| and |map_id| into the namespace
// |namespace_id|.
void AddAreaToNamespace(const std::string& namespace_id,
const std::string& origin,
const std::string& map_id,
leveldb::WriteBatch* batch);
// Helpers for deleting data for |namespace_id| and |origin|.
bool DeleteAreaHelper(const std::string& namespace_id,
const std::string& origin,
leveldb::WriteBatch* batch);
// Retrieves the map id for |namespace_id| and |origin|. It's not an error if
// the map doesn't exist.
bool GetMapForArea(const std::string& namespace_id,
const std::string& origin,
const leveldb::ReadOptions& options,
bool* exists,
std::string* map_id);
// Creates a new map for |namespace_id| and |origin|. |map_id| will hold the
// id of the created map. If there is a map for |namespace_id| and |origin|,
// this just overwrites the map id. The caller is responsible for decreasing
// the ref count.
bool CreateMapForArea(const std::string& namespace_id,
const GURL& origin,
std::string* map_id,
leveldb::WriteBatch* batch);
// Reads the contents of the map |map_id| into |result|. If |only_keys| is
// true, only keys are aread from the database and the values in |result| will
// be empty.
bool ReadMap(const std::string& map_id,
const leveldb::ReadOptions& options,
DOMStorageValuesMap* result,
bool only_keys);
// Writes |values| into the map |map_id|.
void WriteValuesToMap(const std::string& map_id,
const DOMStorageValuesMap& values,
leveldb::WriteBatch* batch);
bool GetMapRefCount(const std::string& map_id, int64* ref_count);
bool IncreaseMapRefCount(const std::string& map_id,
leveldb::WriteBatch* batch);
// Decreases the ref count of a map by |decrease|. If the ref count goes to 0,
// deletes the map.
bool DecreaseMapRefCount(const std::string& map_id,
int decrease,
leveldb::WriteBatch* batch);
// Deletes all values in |map_id|.
bool ClearMap(const std::string& map_id, leveldb::WriteBatch* batch);
// Breaks the association between (|namespace_id|, |origin|) and |map_id| and
// creates a new map for (|namespace_id|, |origin|). Copies the data from the
// old map if |copy_data| is true.
bool DeepCopyArea(const std::string& namespace_id,
const GURL& origin,
bool copy_data,
std::string* map_id,
leveldb::WriteBatch* batch);
// Helper functions for creating the keys needed for the schema.
static std::string NamespaceStartKey(const std::string& namespace_id);
static std::string NamespaceKey(const std::string& namespace_id,
const std::string& origin);
static const char* NamespacePrefix();
static std::string MapRefCountKey(const std::string& map_id);
static std::string MapKey(const std::string& map_id, const std::string& key);
static const char* NextMapIdKey();
scoped_ptr<leveldb::DB> db_;
base::FilePath file_path_;
// For protecting the database opening code. Also guards the variables below.
base::Lock db_lock_;
// True if a database error has occurred (e.g., cannot read data).
bool db_error_;
// True if the database is in an inconsistent state.
bool is_inconsistent_;
// True if the database is in a failed or inconsistent state, and we have
// already deleted it (as an attempt to recover later).
bool invalid_db_deleted_;
// The number of database operations in progress. We need this so that we can
// delete an inconsistent database at the right moment.
int operation_count_;
DISALLOW_COPY_AND_ASSIGN(SessionStorageDatabase);
};
} // namespace content
#endif // CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_H_
|