Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef IDBValueWrapping_h | |
| 6 #define IDBValueWrapping_h | |
| 7 | |
| 8 #include "bindings/core/v8/ExceptionState.h" | |
| 9 #include "platform/SharedBuffer.h" | |
| 10 #include "platform/wtf/RefPtr.h" | |
| 11 #include "platform/wtf/Vector.h" | |
| 12 #include "public/platform/WebBlobInfo.h" | |
| 13 #include "v8/include/v8.h" | |
| 14 | |
| 15 namespace WTF { | |
| 16 class String; | |
| 17 } | |
| 18 | |
| 19 namespace blink { | |
| 20 | |
| 21 class Blob; | |
| 22 class BlobDataHandle; | |
| 23 class ExceptionState; | |
| 24 class IDBValue; | |
| 25 class ScriptState; | |
| 26 class ScriptValue; | |
| 27 class SerializedScriptValue; | |
| 28 class SharedBuffer; | |
| 29 | |
| 30 // Logic for serializing V8 values for storage in IndexedDB. | |
| 31 // | |
| 32 // "Normal" V8 values are stored on disk using the format implemented in | |
|
jsbell
2017/05/15 23:37:39
nit: this first sentence is true whether we wrap o
pwnall
2017/05/19 18:27:35
Done.
| |
| 33 // SerializedScriptValue. In order to avoid operating IndexedDB's backing store | |
| 34 // in a sub-optimal region, "large" V8 values are wrapped in Blobs. In this | |
| 35 // case, the SSV output is stored using the Blob storage system, and IndexedDB's | |
| 36 // backing store only holds references to the Blobs. | |
| 37 // | |
| 38 // In summary: | |
| 39 // "normal" v8::Value -> SSV -> IDBValue (stores SSV output) -> LevelDB | |
| 40 // "large" v8::Value -> SSV -> IDBValue (stores SSV output) -> | |
| 41 // Blob (stores SSV output) + IDBValue (stores Blob reference) -> LevelDB | |
| 42 class IDBValueWrapper { | |
| 43 public: | |
| 44 // Wrapper for an IndexedDB value. | |
| 45 // | |
| 46 // The serialization process can throw an exception. The caller is responsible | |
| 47 // for checking exception_state. | |
| 48 IDBValueWrapper(v8::Isolate*, | |
| 49 v8::Local<v8::Value>, | |
| 50 bool write_wasm_to_stream, | |
| 51 ExceptionState&); | |
| 52 | |
| 53 // Creates a clone of the serialized value. | |
| 54 // | |
| 55 // This method is necessary because the IndexedDB specification demands that a | |
| 56 // value's key and index keys are extracted from a structured clone of the | |
| 57 // value. | |
|
jsbell
2017/05/15 23:37:39
Add "... to avoid side effects."
(We didn't spec
pwnall
2017/05/19 18:27:35
Done.
Yikes, I didn't mean to criticize the spec,
| |
| 58 // | |
| 59 // This method cannot be called after WrapIfBiggerThan(). | |
| 60 void Clone(ScriptState*, ScriptValue* clone); | |
| 61 | |
| 62 // Wraps the serialized value into a Blob if it exceeds the given size. | |
| 63 // | |
| 64 // In production, the threshold is currently always kWrapThreshold. | |
| 65 // | |
| 66 // This method must be called before ExtractWireBytes() and cannot be called | |
| 67 // after ExtractWireBytes(). | |
| 68 bool WrapIfBiggerThan(unsigned max_bytes); | |
| 69 | |
| 70 void ExtractBlobDataHandles( | |
| 71 Vector<RefPtr<BlobDataHandle>>* blob_data_handles); | |
| 72 | |
| 73 RefPtr<SharedBuffer> ExtractWireBytes(); | |
| 74 | |
| 75 inline Vector<WebBlobInfo>& WrappedBlobInfo() { | |
| 76 #if DCHECK_IS_ON() | |
| 77 DCHECK(!had_exception_) | |
| 78 << "WrapBlobInfo() called on wrapper with serialization exception"; | |
| 79 #endif // DCHECK_IS_ON() | |
| 80 return blob_info_; | |
| 81 } | |
| 82 | |
| 83 // Default threshold for WrapIfBiggerThan(). | |
| 84 // | |
| 85 // This should be tuned to achieve a compromise between short-term IndexedDB | |
| 86 // throughput and long-term I/O load and memory usage. LevelDB, the underlying | |
| 87 // storage for IndexedDB, was not designed with large values in mind. At the | |
| 88 // very least, large values will slow down compaction, causing occasional I/O | |
| 89 // spikes. | |
| 90 static constexpr unsigned kWrapThreshold = 64 * 1024; | |
| 91 | |
| 92 // MIME type used for Blobs that wrap IDBValues. | |
| 93 static constexpr const char* kWrapMimeType = | |
| 94 "application/x-blink-idb-value-wrapper"; | |
| 95 | |
| 96 private: | |
| 97 // Used to serialize the wrapped value. | |
| 98 static void WriteVarint(unsigned value, Vector<char>& output); | |
| 99 static void WriteAsciiString(const String& value, Vector<char>& output); | |
| 100 | |
| 101 RefPtr<SerializedScriptValue> serialized_value_; | |
| 102 RefPtr<BlobDataHandle> wrapper_handle_; | |
| 103 Vector<WebBlobInfo> blob_info_; | |
| 104 Vector<BlobDataHandle> blob_handles_; | |
| 105 Vector<char> wire_bytes_; | |
| 106 #if DCHECK_IS_ON() | |
| 107 bool had_exception_ = false; | |
| 108 bool wrap_called_ = false; | |
| 109 #endif // DCHECK_IS_ON() | |
| 110 }; | |
| 111 | |
| 112 // State and logic for unwrapping large IndexedDB values from Blobs. | |
| 113 // | |
| 114 // See IDBValueWrapper for an explanation of the wrapping concept. | |
| 115 // | |
| 116 // Once created, an IDBValueUnwrapper instance can be used to unwrap multiple | |
| 117 // Blobs. For each Blob to be unwrapped, the caller should first call Parse(). | |
| 118 // If the method succeeds, the IDBValueUnwrapper will store the parse state, | |
| 119 // which can be obtained using WrapperBlobSize() and WrapperBlobHandle(). | |
| 120 class IDBValueUnwrapper { | |
| 121 public: | |
| 122 IDBValueUnwrapper(); | |
| 123 | |
| 124 // Checks whether a IDBValue's data was wrapped in a Blob. | |
| 125 static bool IsWrapped(IDBValue*); | |
| 126 | |
| 127 // Pieces together an unwrapped IDBValue from a wrapped value and Blob data. | |
| 128 static RefPtr<IDBValue> CreateUnwrapped( | |
| 129 IDBValue* wrapped_value, | |
| 130 RefPtr<SharedBuffer>&& wrapper_blob_content); | |
| 131 | |
| 132 // Parses the wrapper Blob information from a wrapped IDBValue. | |
| 133 // | |
| 134 // Returns true for success, and false for failure. Failure can mean that the | |
| 135 // given value was not a wrapped IDBValue, or that the value bytes were | |
| 136 // corrupted. | |
| 137 bool Parse(IDBValue*); | |
| 138 | |
| 139 // Returns the size of the Blob obtained by the last Unwrap() call. | |
| 140 // | |
| 141 // Should only be called after a successful result from Unwrap(). | |
| 142 inline unsigned WrapperBlobSize() const { | |
| 143 DCHECK(end_); | |
| 144 return blob_size_; | |
| 145 } | |
| 146 | |
| 147 // Returns a handle to the Blob obtained by the last Unwrap() call. | |
| 148 // | |
| 149 // Should only be called exactly once after a successful result from Unwrap(). | |
| 150 RefPtr<BlobDataHandle> WrapperBlobHandle(); | |
| 151 | |
| 152 private: | |
| 153 // Used to deserialize the wrapped value. | |
| 154 bool ReadVarint(unsigned& value); | |
| 155 bool ReadAsciiString(String& value); | |
| 156 | |
| 157 // Resets the parsing state. | |
| 158 inline bool Reset() { | |
| 159 #if DCHECK_IS_ON() | |
| 160 blob_handle_.Clear(); | |
| 161 current_ = nullptr; | |
| 162 end_ = nullptr; | |
| 163 #endif // DCHECK_IS_ON() | |
| 164 return false; | |
| 165 } | |
| 166 | |
| 167 // Deserialization cursor in the SharedBuffer of the IDBValue being unwrapped. | |
| 168 const uint8_t* current_; | |
| 169 | |
| 170 // Smallest invalid position_ value. | |
| 171 const uint8_t* end_; | |
| 172 | |
| 173 // The size of the Blob holding the data for the last unwrapped IDBValue. | |
| 174 unsigned blob_size_; | |
| 175 | |
| 176 // Handle to the Blob holding the data for the last unwrapped IDBValue. | |
| 177 RefPtr<BlobDataHandle> blob_handle_; | |
| 178 }; | |
| 179 | |
| 180 } // namespace blink | |
| 181 | |
| 182 #endif // IDBValueWrapping_h | |
| OLD | NEW |