summaryrefslogtreecommitdiffstats
path: root/chromium/content/browser/dom_storage/session_storage_database.h
blob: 09d4773fea154994ba33859f294f22d83a9c44b8 (plain)
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
// 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>;
  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.
  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_;

  DISALLOW_COPY_AND_ASSIGN(SessionStorageDatabase);
};

}  // namespace content

#endif  // CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_H_