summaryrefslogtreecommitdiffstats
path: root/dom/localstorage/LSSnapshot.h
blob: c12a4efce2c71373c6020a9d435a361ce9d52196 (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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_localstorage_LSSnapshot_h
#define mozilla_dom_localstorage_LSSnapshot_h

#include <cstdint>
#include <cstdlib>
#include "ErrorList.h"
#include "mozilla/Assertions.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "nsCOMPtr.h"
#include "nsTHashMap.h"
#include "nsHashKeys.h"
#include "nsIRunnable.h"
#include "nsISupports.h"
#include "nsStringFwd.h"
#include "nsTArrayForwardDeclare.h"
#include "nsTHashSet.h"

class nsITimer;

namespace mozilla::dom {

class LSDatabase;
class LSNotifyInfo;
class LSSnapshotChild;
class LSSnapshotInitInfo;
class LSWriteAndNotifyInfo;
class SnapshotWriteOptimizer;

template <typename>
class Optional;

class LSSnapshot final : public nsIRunnable {
 public:
  /**
   * The LoadState expresses what subset of information a snapshot has from the
   * authoritative Datastore in the parent process.  The initial snapshot is
   * populated heuristically based on the size of the keys and size of the items
   * (inclusive of the key value; item is key+value, not just value) of the
   * entire datastore relative to the configured prefill limit (via pref
   * "dom.storage.snapshot_prefill" exposed as gSnapshotPrefill in bytes).
   *
   * If there's less data than the limit, we send both keys and values and end
   * up as AllOrderedItems.  If there's enough room for all the keys but not
   * all the values, we end up as AllOrderedKeys with as many values present as
   * would fit.  If there's not enough room for all the keys, then we end up as
   * Partial with as many key-value pairs as will fit.
   *
   * The state AllUnorderedItems can only be reached by code getting items one
   * by one.
   */
  enum class LoadState {
    /**
     * Class constructed, Init(LSSnapshotInitInfo) has not been invoked yet.
     */
    Initial,
    /**
     * Some keys and their values are known.
     */
    Partial,
    /**
     * All the keys are known in order, but some values are unknown.
     */
    AllOrderedKeys,
    /**
     * All keys and their values are known, but in an arbitrary order.
     */
    AllUnorderedItems,
    /**
     * All keys and their values are known and are present in their canonical
     * order.  This is everything, and is the preferred case.  The initial
     * population will send this info when the size of all items is less than
     * the prefill threshold.
     *
     * mValues will contain all keys and values, mLoadedItems and mUnknownItems
     * are unused.
     */
    AllOrderedItems,
    EndGuard
  };

 private:
  RefPtr<LSSnapshot> mSelfRef;

  RefPtr<LSDatabase> mDatabase;

  nsCOMPtr<nsITimer> mIdleTimer;

  LSSnapshotChild* mActor;

  nsTHashSet<nsString> mLoadedItems;
  nsTHashSet<nsString> mUnknownItems;
  nsTHashMap<nsStringHashKey, nsString> mValues;
  UniquePtr<SnapshotWriteOptimizer> mWriteOptimizer;
  UniquePtr<nsTArray<LSWriteAndNotifyInfo>> mWriteAndNotifyInfos;

  uint32_t mInitLength;
  uint32_t mLength;
  int64_t mUsage;
  int64_t mPeakUsage;

  LoadState mLoadState;

  bool mHasOtherProcessDatabases;
  bool mHasOtherProcessObservers;
  bool mExplicit;
  bool mHasPendingStableStateCallback;
  bool mHasPendingIdleTimerCallback;
  bool mDirty;

#ifdef DEBUG
  bool mInitialized;
  bool mSentFinish;
#endif

 public:
  explicit LSSnapshot(LSDatabase* aDatabase);

  void AssertIsOnOwningThread() const { NS_ASSERT_OWNINGTHREAD(LSSnapshot); }

  void SetActor(LSSnapshotChild* aActor);

  void ClearActor() {
    AssertIsOnOwningThread();
    MOZ_ASSERT(mActor);

    mActor = nullptr;
  }

  bool Explicit() const { return mExplicit; }

  nsresult Init(const nsAString& aKey, const LSSnapshotInitInfo& aInitInfo,
                bool aExplicit);

  nsresult GetLength(uint32_t* aResult);

  nsresult GetKey(uint32_t aIndex, nsAString& aResult);

  nsresult GetItem(const nsAString& aKey, nsAString& aResult);

  nsresult GetKeys(nsTArray<nsString>& aKeys);

  nsresult SetItem(const nsAString& aKey, const nsAString& aValue,
                   LSNotifyInfo& aNotifyInfo);

  nsresult RemoveItem(const nsAString& aKey, LSNotifyInfo& aNotifyInfo);

  nsresult Clear(LSNotifyInfo& aNotifyInfo);

  void MarkDirty();

  nsresult ExplicitCheckpoint();

  nsresult ExplicitEnd();

  int64_t GetUsage() const;

 private:
  ~LSSnapshot();

  void ScheduleStableStateCallback();

  void MaybeScheduleStableStateCallback();

  nsresult GetItemInternal(const nsAString& aKey,
                           const Optional<nsString>& aValue,
                           nsAString& aResult);

  nsresult EnsureAllKeys();

  nsresult UpdateUsage(int64_t aDelta);

  nsresult Checkpoint(bool aSync = false);

  nsresult Finish(bool aSync = false);

  void CancelIdleTimer();

  static void IdleTimerCallback(nsITimer* aTimer, void* aClosure);

  NS_DECL_ISUPPORTS
  NS_DECL_NSIRUNNABLE
};

}  // namespace mozilla::dom

#endif  // mozilla_dom_localstorage_LSSnapshot_h