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