1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_dom_localstorage_LSSnapshot_h
8 #define mozilla_dom_localstorage_LSSnapshot_h
9 
10 #include <cstdint>
11 #include <cstdlib>
12 #include "ErrorList.h"
13 #include "mozilla/Assertions.h"
14 #include "mozilla/RefPtr.h"
15 #include "mozilla/UniquePtr.h"
16 #include "nsCOMPtr.h"
17 #include "nsTHashMap.h"
18 #include "nsHashKeys.h"
19 #include "nsIRunnable.h"
20 #include "nsISupports.h"
21 #include "nsStringFwd.h"
22 #include "nsTArrayForwardDeclare.h"
23 #include "nsTHashSet.h"
24 
25 class nsITimer;
26 
27 namespace mozilla {
28 namespace dom {
29 
30 class LSDatabase;
31 class LSNotifyInfo;
32 class LSSnapshotChild;
33 class LSSnapshotInitInfo;
34 class LSWriteAndNotifyInfo;
35 class SnapshotWriteOptimizer;
36 
37 template <typename>
38 class Optional;
39 
40 class LSSnapshot final : public nsIRunnable {
41  public:
42   /**
43    * The LoadState expresses what subset of information a snapshot has from the
44    * authoritative Datastore in the parent process.  The initial snapshot is
45    * populated heuristically based on the size of the keys and size of the items
46    * (inclusive of the key value; item is key+value, not just value) of the
47    * entire datastore relative to the configured prefill limit (via pref
48    * "dom.storage.snapshot_prefill" exposed as gSnapshotPrefill in bytes).
49    *
50    * If there's less data than the limit, we send both keys and values and end
51    * up as AllOrderedItems.  If there's enough room for all the keys but not
52    * all the values, we end up as AllOrderedKeys with as many values present as
53    * would fit.  If there's not enough room for all the keys, then we end up as
54    * Partial with as many key-value pairs as will fit.
55    *
56    * The state AllUnorderedItems can only be reached by code getting items one
57    * by one.
58    */
59   enum class LoadState {
60     /**
61      * Class constructed, Init(LSSnapshotInitInfo) has not been invoked yet.
62      */
63     Initial,
64     /**
65      * Some keys and their values are known.
66      */
67     Partial,
68     /**
69      * All the keys are known in order, but some values are unknown.
70      */
71     AllOrderedKeys,
72     /**
73      * All keys and their values are known, but in an arbitrary order.
74      */
75     AllUnorderedItems,
76     /**
77      * All keys and their values are known and are present in their canonical
78      * order.  This is everything, and is the preferred case.  The initial
79      * population will send this info when the size of all items is less than
80      * the prefill threshold.
81      *
82      * mValues will contain all keys and values, mLoadedItems and mUnknownItems
83      * are unused.
84      */
85     AllOrderedItems,
86     EndGuard
87   };
88 
89  private:
90   RefPtr<LSSnapshot> mSelfRef;
91 
92   RefPtr<LSDatabase> mDatabase;
93 
94   nsCOMPtr<nsITimer> mTimer;
95 
96   LSSnapshotChild* mActor;
97 
98   nsTHashSet<nsString> mLoadedItems;
99   nsTHashSet<nsString> mUnknownItems;
100   nsTHashMap<nsStringHashKey, nsString> mValues;
101   UniquePtr<SnapshotWriteOptimizer> mWriteOptimizer;
102   UniquePtr<nsTArray<LSWriteAndNotifyInfo>> mWriteAndNotifyInfos;
103 
104   uint32_t mInitLength;
105   uint32_t mLength;
106   int64_t mExactUsage;
107   int64_t mPeakUsage;
108 
109   LoadState mLoadState;
110 
111   bool mHasOtherProcessObservers;
112   bool mExplicit;
113   bool mHasPendingStableStateCallback;
114   bool mHasPendingTimerCallback;
115   bool mDirty;
116 
117 #ifdef DEBUG
118   bool mInitialized;
119   bool mSentFinish;
120 #endif
121 
122  public:
123   explicit LSSnapshot(LSDatabase* aDatabase);
124 
AssertIsOnOwningThread()125   void AssertIsOnOwningThread() const { NS_ASSERT_OWNINGTHREAD(LSSnapshot); }
126 
127   void SetActor(LSSnapshotChild* aActor);
128 
ClearActor()129   void ClearActor() {
130     AssertIsOnOwningThread();
131     MOZ_ASSERT(mActor);
132 
133     mActor = nullptr;
134   }
135 
Explicit()136   bool Explicit() const { return mExplicit; }
137 
138   nsresult Init(const nsAString& aKey, const LSSnapshotInitInfo& aInitInfo,
139                 bool aExplicit);
140 
141   nsresult GetLength(uint32_t* aResult);
142 
143   nsresult GetKey(uint32_t aIndex, nsAString& aResult);
144 
145   nsresult GetItem(const nsAString& aKey, nsAString& aResult);
146 
147   nsresult GetKeys(nsTArray<nsString>& aKeys);
148 
149   nsresult SetItem(const nsAString& aKey, const nsAString& aValue,
150                    LSNotifyInfo& aNotifyInfo);
151 
152   nsresult RemoveItem(const nsAString& aKey, LSNotifyInfo& aNotifyInfo);
153 
154   nsresult Clear(LSNotifyInfo& aNotifyInfo);
155 
156   void MarkDirty();
157 
158   nsresult End();
159 
160  private:
161   ~LSSnapshot();
162 
163   void ScheduleStableStateCallback();
164 
165   void MaybeScheduleStableStateCallback();
166 
167   nsresult GetItemInternal(const nsAString& aKey,
168                            const Optional<nsString>& aValue,
169                            nsAString& aResult);
170 
171   nsresult EnsureAllKeys();
172 
173   nsresult UpdateUsage(int64_t aDelta);
174 
175   nsresult Checkpoint();
176 
177   nsresult Finish();
178 
179   void CancelTimer();
180 
181   static void TimerCallback(nsITimer* aTimer, void* aClosure);
182 
183   NS_DECL_ISUPPORTS
184   NS_DECL_NSIRUNNABLE
185 };
186 
187 }  // namespace dom
188 }  // namespace mozilla
189 
190 #endif  // mozilla_dom_localstorage_LSSnapshot_h
191