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_LSWriteOptimizer_h
8 #define mozilla_dom_localstorage_LSWriteOptimizer_h
9 
10 #include <cstdint>
11 #include <utility>
12 #include "mozilla/Assertions.h"
13 #include "mozilla/CheckedInt.h"
14 #include "mozilla/UniquePtr.h"
15 #include "nsClassHashtable.h"
16 #include "nsHashKeys.h"
17 #include "nsISupports.h"
18 #include "nsStringFwd.h"
19 #include "nsTArrayForwardDeclare.h"
20 
21 namespace mozilla {
22 namespace dom {
23 
24 /**
25  * Base class for coalescing manipulation queue.
26  */
27 class LSWriteOptimizerBase {
28   class WriteInfoComparator;
29 
30  protected:
31   class WriteInfo;
32   class DeleteItemInfo;
33   class TruncateInfo;
34 
35   UniquePtr<WriteInfo> mTruncateInfo;
36   nsClassHashtable<nsStringHashKey, WriteInfo> mWriteInfos;
37   CheckedUint64 mLastSerialNumber;
38   int64_t mTotalDelta;
39 
40   NS_DECL_OWNINGTHREAD
41 
42  public:
LSWriteOptimizerBase()43   LSWriteOptimizerBase() : mLastSerialNumber(0), mTotalDelta(0) {}
44 
LSWriteOptimizerBase(LSWriteOptimizerBase && aWriteOptimizer)45   LSWriteOptimizerBase(LSWriteOptimizerBase&& aWriteOptimizer)
46       : mTruncateInfo(std::move(aWriteOptimizer.mTruncateInfo)) {
47     AssertIsOnOwningThread();
48     MOZ_ASSERT(&aWriteOptimizer != this);
49 
50     mWriteInfos.SwapElements(aWriteOptimizer.mWriteInfos);
51     mTotalDelta = aWriteOptimizer.mTotalDelta;
52     aWriteOptimizer.mTotalDelta = 0;
53   }
54 
AssertIsOnOwningThread()55   void AssertIsOnOwningThread() const {
56     NS_ASSERT_OWNINGTHREAD(LSWriteOptimizerBase);
57   }
58 
59   void DeleteItem(const nsAString& aKey, int64_t aDelta = 0);
60 
61   void Truncate(int64_t aDelta = 0);
62 
HasWrites()63   bool HasWrites() const {
64     AssertIsOnOwningThread();
65 
66     return mTruncateInfo || !mWriteInfos.IsEmpty();
67   }
68 
Reset()69   void Reset() {
70     AssertIsOnOwningThread();
71 
72     mTruncateInfo = nullptr;
73     mWriteInfos.Clear();
74   }
75 
76  protected:
NextSerialNumber()77   uint64_t NextSerialNumber() {
78     AssertIsOnOwningThread();
79 
80     mLastSerialNumber++;
81 
82     MOZ_ASSERT(mLastSerialNumber.isValid());
83 
84     return mLastSerialNumber.value();
85   }
86 
87   /**
88    * This method can be used by derived classes to get a sorted list of write
89    * infos. Write infos are sorted by the serial number.
90    */
91   void GetSortedWriteInfos(nsTArray<NotNull<WriteInfo*>>& aWriteInfos);
92 };
93 
94 /**
95  * Base class for specific mutations.
96  */
97 class LSWriteOptimizerBase::WriteInfo {
98   uint64_t mSerialNumber;
99 
100  public:
WriteInfo(uint64_t aSerialNumber)101   WriteInfo(uint64_t aSerialNumber) : mSerialNumber(aSerialNumber) {}
102 
103   virtual ~WriteInfo() = default;
104 
SerialNumber()105   uint64_t SerialNumber() const { return mSerialNumber; }
106 
107   enum Type { InsertItem = 0, UpdateItem, DeleteItem, Truncate };
108 
109   virtual Type GetType() const = 0;
110 };
111 
112 class LSWriteOptimizerBase::DeleteItemInfo final : public WriteInfo {
113   nsString mKey;
114 
115  public:
DeleteItemInfo(uint64_t aSerialNumber,const nsAString & aKey)116   DeleteItemInfo(uint64_t aSerialNumber, const nsAString& aKey)
117       : WriteInfo(aSerialNumber), mKey(aKey) {}
118 
GetKey()119   const nsAString& GetKey() const { return mKey; }
120 
121  private:
GetType()122   Type GetType() const override { return DeleteItem; }
123 };
124 
125 /**
126  * Truncate mutation.
127  */
128 class LSWriteOptimizerBase::TruncateInfo final : public WriteInfo {
129  public:
TruncateInfo(uint64_t aSerialNumber)130   explicit TruncateInfo(uint64_t aSerialNumber) : WriteInfo(aSerialNumber) {}
131 
132  private:
GetType()133   Type GetType() const override { return Truncate; }
134 };
135 
136 /**
137  * Coalescing manipulation queue.
138  */
139 template <typename T, typename U = T>
140 class LSWriteOptimizer;
141 
142 template <typename T, typename U>
143 class LSWriteOptimizer : public LSWriteOptimizerBase {
144  protected:
145   class InsertItemInfo;
146   class UpdateItemInfo;
147 
148  public:
149   void InsertItem(const nsAString& aKey, const T& aValue, int64_t aDelta = 0);
150 
151   void UpdateItem(const nsAString& aKey, const T& aValue, int64_t aDelta = 0);
152 };
153 
154 /**
155  * Insert mutation (the key did not previously exist).
156  */
157 template <typename T, typename U>
158 class LSWriteOptimizer<T, U>::InsertItemInfo : public WriteInfo {
159   nsString mKey;
160   U mValue;
161 
162  public:
InsertItemInfo(uint64_t aSerialNumber,const nsAString & aKey,const T & aValue)163   InsertItemInfo(uint64_t aSerialNumber, const nsAString& aKey, const T& aValue)
164       : WriteInfo(aSerialNumber), mKey(aKey), mValue(aValue) {}
165 
GetKey()166   const nsAString& GetKey() const { return mKey; }
167 
GetValue()168   const T& GetValue() const { return mValue; }
169 
170  private:
GetType()171   WriteInfo::Type GetType() const override { return InsertItem; }
172 };
173 
174 /**
175  * Update mutation (the key already existed).
176  */
177 template <typename T, typename U>
178 class LSWriteOptimizer<T, U>::UpdateItemInfo final : public InsertItemInfo {
179   bool mUpdateWithMove;
180 
181  public:
UpdateItemInfo(uint64_t aSerialNumber,const nsAString & aKey,const T & aValue,bool aUpdateWithMove)182   UpdateItemInfo(uint64_t aSerialNumber, const nsAString& aKey, const T& aValue,
183                  bool aUpdateWithMove)
184       : InsertItemInfo(aSerialNumber, aKey, aValue),
185         mUpdateWithMove(aUpdateWithMove) {}
186 
UpdateWithMove()187   bool UpdateWithMove() const { return mUpdateWithMove; }
188 
189  private:
GetType()190   WriteInfo::Type GetType() const override { return WriteInfo::UpdateItem; }
191 };
192 
193 }  // namespace dom
194 }  // namespace mozilla
195 
196 #endif  // mozilla_dom_localstorage_LSWriteOptimizer_h
197