File: session_storage_impl.h

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (314 lines) | stat: -rw-r--r-- 12,434 bytes parent folder | download | duplicates (3)
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_SERVICES_STORAGE_DOM_STORAGE_SESSION_STORAGE_IMPL_H_
#define COMPONENTS_SERVICES_STORAGE_DOM_STORAGE_SESSION_STORAGE_IMPL_H_

#include <stdint.h>

#include <map>
#include <memory>
#include <string>
#include <vector>

#include "base/files/file_path.h"
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/sequence_bound.h"
#include "base/trace_event/memory_allocator_dump.h"
#include "base/trace_event/memory_dump_provider.h"
#include "components/services/storage/dom_storage/async_dom_storage_database.h"
#include "components/services/storage/dom_storage/dom_storage_database.h"
#include "components/services/storage/dom_storage/session_storage_data_map.h"
#include "components/services/storage/dom_storage/session_storage_metadata.h"
#include "components/services/storage/dom_storage/session_storage_namespace_impl.h"
#include "components/services/storage/public/mojom/session_storage_control.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "third_party/blink/public/mojom/dom_storage/session_storage_namespace.mojom.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"

namespace base {
class SequencedTaskRunner;
}  // namespace base

namespace blink {
class StorageKey;
}  // namespace blink

namespace storage {

class StorageServiceImpl;
// The Session Storage implementation. An instance of this class exists for each
// profile directory (within the user data directory) that is using Session
// Storage. It manages storage for all StorageKeys and namespaces within that
// partition.
class SessionStorageImpl : public base::trace_event::MemoryDumpProvider,
                           public mojom::SessionStorageControl,
                           public SessionStorageDataMap::Listener,
                           public SessionStorageNamespaceImpl::Delegate {
 public:
  enum class BackingMode {
    // Use an in-memory leveldb database to store our state.
    kNoDisk,
    // Use disk for the leveldb database, but clear its contents before we open
    // it. This is used for platforms like Android where the session restore
    // code is never used, ScavengeUnusedNamespace is never called, and old
    // session storage data will never be reused.
    kClearDiskStateOnOpen,
    // Use disk for the leveldb database, restore all saved namespaces from
    // disk. This assumes that ScavengeUnusedNamespace will eventually be called
    // to clean up unused namespaces on disk.
    kRestoreDiskState
  };

  using DestructSessionStorageCallback =
      base::OnceCallback<void(SessionStorageImpl*)>;
  SessionStorageImpl(
      const base::FilePath& partition_directory,
      scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
      scoped_refptr<base::SequencedTaskRunner> memory_dump_task_runner,
      BackingMode backing_option,
      std::string database_name,
      DestructSessionStorageCallback destruct_callback,
      mojo::PendingReceiver<mojom::SessionStorageControl> receiver);

  ~SessionStorageImpl() override;

  // mojom::SessionStorageControl implementation:
  void BindNamespace(
      const std::string& namespace_id,
      mojo::PendingReceiver<blink::mojom::SessionStorageNamespace> receiver,
      BindNamespaceCallback callback) override;
  void BindStorageArea(
      const blink::StorageKey& storage_key,
      const std::string& namespace_id,
      mojo::PendingReceiver<blink::mojom::StorageArea> receiver,
      BindStorageAreaCallback callback) override;
  void GetUsage(GetUsageCallback callback) override;
  void DeleteStorage(const blink::StorageKey& storage_key,
                     const std::string& namespace_id,
                     DeleteStorageCallback callback) override;
  void CleanUpStorage(CleanUpStorageCallback callback) override;
  void ScavengeUnusedNamespaces(
      ScavengeUnusedNamespacesCallback callback) override;
  void Flush() override;
  void PurgeMemory() override;
  void CreateNamespace(const std::string& namespace_id) override;
  void CloneNamespace(const std::string& namespace_id_to_clone,
                      const std::string& clone_namespace_id,
                      mojom::SessionStorageCloneType clone_type) override;
  void DeleteNamespace(const std::string& namespace_id,
                       bool should_persist) override;

  // Called when the client (i.e. the corresponding browser storage partition)
  // disconnects. Schedules the commit of any unsaved changes. All data on disk
  // (where there was no call to DeleteNamespace will stay on disk for later
  // restoring. `callback` is invoked when shutdown is complete, which may
  // happen even before ShutDown returns.
  void ShutDown(base::OnceClosure callback);

  // Clears unused storage areas, when thresholds are reached.
  void PurgeUnusedAreasIfNeeded();

  // base::trace_event::MemoryDumpProvider implementation:
  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                    base::trace_event::ProcessMemoryDump* pmd) override;

  const base::FilePath& GetStoragePath() const { return partition_directory_; }

  void PretendToConnectForTesting();

  AsyncDomStorageDatabase* DatabaseForTesting() { return database_.get(); }

  void FlushAreaForTesting(const std::string& namespace_id,
                           const blink::StorageKey& storage_key);

  // Access the underlying DomStorageDatabase. May be null if the database is
  // not yet open.
  base::SequenceBound<DomStorageDatabase>& GetDatabaseForTesting() {
    return database_->database();
  }

  const SessionStorageMetadata& GetMetadataForTesting() const {
    return metadata_;
  }

  SessionStorageNamespaceImpl* GetNamespaceForTesting(const std::string& id) {
    auto it = namespaces_.find(id);
    if (it == namespaces_.end())
      return nullptr;
    return it->second.get();
  }

  // Wait for the database to be opened, or for opening to fail. If the database
  // is already opened, |callback| is invoked immediately.
  void SetDatabaseOpenCallbackForTesting(base::OnceClosure callback);

 private:
  friend class DOMStorageBrowserTest;

  // These values are written to logs.  New enum values can be added, but
  // existing enums must never be renumbered or deleted and reused.
  enum class OpenResult {
    kDirectoryOpenFailed = 0,
    kDatabaseOpenFailed = 1,
    kInvalidVersion = 2,
    kVersionReadError = 3,
    kNamespacesReadError = 4,
    kSuccess = 6,
    kMaxValue = kSuccess
  };

  scoped_refptr<SessionStorageMetadata::MapData> RegisterNewAreaMap(
      SessionStorageMetadata::NamespaceEntry namespace_entry,
      const blink::StorageKey& storage_key);

  // SessionStorageAreaImpl::Listener implementation:
  void OnDataMapCreation(const std::vector<uint8_t>& map_prefix,
                         SessionStorageDataMap* map) override;
  void OnDataMapDestruction(const std::vector<uint8_t>& map_prefix) override;
  void OnCommitResult(leveldb::Status status) override;
  void OnCommitResultWithCallback(base::OnceClosure callback,
                                  leveldb::Status status);

  // SessionStorageNamespaceImpl::Delegate implementation:
  scoped_refptr<SessionStorageDataMap> MaybeGetExistingDataMapForId(
      const std::vector<uint8_t>& map_number_as_bytes) override;
  void RegisterShallowClonedNamespace(
      SessionStorageMetadata::NamespaceEntry source_namespace_entry,
      const std::string& new_namespace_id,
      const SessionStorageNamespaceImpl::StorageKeyAreas&
          clone_from_storage_keys) override;

  std::unique_ptr<SessionStorageNamespaceImpl>
  CreateSessionStorageNamespaceImpl(std::string namespace_id);

  void DoDatabaseDelete(const std::string& namespace_id);

  // Runs |callback| immediately if already connected to a database, otherwise
  // delays running |callback| untill after a connection has been established.
  // Initiates connecting to the database if no connection is in progress yet.
  void RunWhenConnected(base::OnceClosure callback);

  // Part of our asynchronous directory opening called from RunWhenConnected().
  void InitiateConnection(bool in_memory_only = false);
  void OnDatabaseOpened(leveldb::Status status);

  struct ValueAndStatus {
    ValueAndStatus();
    ValueAndStatus(ValueAndStatus&&);
    ~ValueAndStatus();
    leveldb::Status status;
    DomStorageDatabase::Value value;
  };

  struct KeyValuePairsAndStatus {
    KeyValuePairsAndStatus();
    KeyValuePairsAndStatus(KeyValuePairsAndStatus&&);
    ~KeyValuePairsAndStatus();
    leveldb::Status status;
    std::vector<DomStorageDatabase::KeyValuePair> key_value_pairs;
  };

  void OnGotDatabaseMetadata(ValueAndStatus version,
                             KeyValuePairsAndStatus namespaces,
                             ValueAndStatus next_map_id);

  struct MetadataParseResult {
    OpenResult open_result;
    const char* histogram_name;
  };
  MetadataParseResult ParseDatabaseVersion(
      ValueAndStatus version,
      std::vector<AsyncDomStorageDatabase::BatchDatabaseTask>* migration_tasks);
  MetadataParseResult ParseNamespaces(
      KeyValuePairsAndStatus namespaces,
      std::vector<AsyncDomStorageDatabase::BatchDatabaseTask> migration_tasks);
  MetadataParseResult ParseNextMapId(ValueAndStatus next_map_id);

  void OnConnectionFinished();
  void PurgeAllNamespaces();
  void DeleteAndRecreateDatabase(const char* histogram_name);
  void OnDBDestroyed(bool recreate_in_memory, leveldb::Status status);

  void OnShutdownComplete();

  void GetStatistics(size_t* total_cache_size, size_t* unused_areas_count);

  void LogDatabaseOpenResult(OpenResult result);

  void OnReceiverDisconnected();

  // Passed in by the StorageServiceImpl that owns this object. Used to signal
  // that this SessionStorageImpl can be destructed when the Receiver is
  // disconnected.
  DestructSessionStorageCallback destruct_callback_;
  // Since the session storage object hierarchy references iterators owned by
  // the metadata, make sure it is destroyed last on destruction.
  SessionStorageMetadata metadata_;

  BackingMode backing_mode_;
  std::string database_name_;

  enum ConnectionState {
    NO_CONNECTION,
    CONNECTION_IN_PROGRESS,
    CONNECTION_FINISHED,
    CONNECTION_SHUTDOWN
  } connection_state_ = NO_CONNECTION;
  bool database_initialized_ = false;

  const base::FilePath partition_directory_;
  const scoped_refptr<base::SequencedTaskRunner> database_task_runner_;

  base::trace_event::MemoryAllocatorDumpGuid memory_dump_id_;

  mojo::Receiver<mojom::SessionStorageControl> receiver_;

  std::unique_ptr<AsyncDomStorageDatabase> database_;
  bool in_memory_ = false;
  bool tried_to_recreate_during_open_ = false;

  std::vector<base::OnceClosure> on_database_opened_callbacks_;

  // The removal of items from this map is managed by the refcounting in
  // SessionStorageDataMap.
  // Populated after the database is connected.
  std::map<std::vector<uint8_t>,
           raw_ptr<SessionStorageDataMap, CtnExperimental>>
      data_maps_;
  // Populated in CreateNamespace, CloneNamespace, and sometimes
  // RegisterShallowClonedNamespace. Items are removed in
  // DeleteNamespace.
  std::map<std::string, std::unique_ptr<SessionStorageNamespaceImpl>>
      namespaces_;

  // Scavenging only happens once.
  bool has_scavenged_ = false;
  // When namespaces are destroyed but marked as persistent, a scavenge should
  // not delete them. Cleared after ScavengeUnusedNamespaces is called.
  std::set<std::string> protected_namespaces_from_scavenge_;

  bool is_low_end_mode_;
  // Counts consecutive commit errors. If this number reaches a threshold, the
  // whole database is thrown away.
  int commit_error_count_ = 0;
  bool tried_to_recover_from_commit_errors_ = false;

  // Name of an extra histogram to log open results to, if not null.
  const char* open_result_histogram_ = nullptr;

  base::OnceClosure shutdown_complete_callback_;

  base::WeakPtrFactory<SessionStorageImpl> weak_ptr_factory_{this};
};

}  // namespace storage

#endif  // COMPONENTS_SERVICES_STORAGE_DOM_STORAGE_SESSION_STORAGE_IMPL_H_