Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(398)

Side by Side Diff: third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h

Issue 2822453003: Wrap large IndexedDB values into Blobs before writing to LevelDB. (Closed)
Patch Set: Rebased. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 "bindings/core/v8/serialization/SerializedScriptValue.h"
10 #include "platform/SharedBuffer.h"
11 #include "platform/wtf/Allocator.h"
12 #include "platform/wtf/RefPtr.h"
13 #include "platform/wtf/Vector.h"
14 #include "public/platform/WebBlobInfo.h"
15 #include "v8/include/v8.h"
16
17 namespace blink {
18
19 class Blob;
20 class BlobDataHandle;
21 class ExceptionState;
22 class IDBValue;
23 class ScriptState;
24 class ScriptValue;
25 class SerializedScriptValue;
26 class SharedBuffer;
27
28 // Logic for serializing V8 values for storage in IndexedDB.
29 //
30 // V8 values are stored on disk using the format implemented in
31 // SerializedScriptValue (SSV). For "normal" (not too large) V8 values, the SSV
32 // output is stored directly in IndexedDB's backing store. "Large" V8 values are
33 // wrapped in Blobs, in order to avoid operating the backing store in a
34 // sub-optimal region. In this case, the SSV output is stored using the Blob
35 // storage system, and IndexedDB's backing store only holds references to the
36 // 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 STACK_ALLOCATED();
44
45 public:
46 // Wrapper for an IndexedDB value.
47 //
48 // The serialization process can throw an exception. The caller is responsible
49 // for checking exception_state.
50 IDBValueWrapper(
51 v8::Isolate*,
52 v8::Local<v8::Value>,
53 SerializedScriptValue::SerializeOptions::WasmSerializationPolicy,
54 ExceptionState&);
55
56 // Creates a clone of the serialized value.
57 //
58 // This method is used to fulfill the IndexedDB specification requirement that
59 // a value's key and index keys are extracted from a structured clone of the
60 // value, which avoids the issue of side-effects in custom getters.
61 //
62 // This method cannot be called after WrapIfBiggerThan().
63 void Clone(ScriptState*, ScriptValue* clone);
64
65 // Wraps the serialized value into a Blob if it exceeds the given size.
66 //
67 // In production, the threshold is currently always kWrapThreshold.
68 //
69 // This method must be called before ExtractWireBytes() and cannot be called
70 // after ExtractWireBytes().
71 bool WrapIfBiggerThan(unsigned max_bytes);
72
73 void ExtractBlobDataHandles(
74 Vector<RefPtr<BlobDataHandle>>* blob_data_handles);
75
76 RefPtr<SharedBuffer> ExtractWireBytes();
77
78 inline Vector<WebBlobInfo>& WrappedBlobInfo() {
79 #if DCHECK_IS_ON()
80 DCHECK(!had_exception_)
81 << "WrapBlobInfo() called on wrapper with serialization exception";
82 #endif // DCHECK_IS_ON()
83 return blob_info_;
84 }
85
86 // Default threshold for WrapIfBiggerThan().
87 //
88 // This should be tuned to achieve a compromise between short-term IndexedDB
89 // throughput and long-term I/O load and memory usage. LevelDB, the underlying
90 // storage for IndexedDB, was not designed with large values in mind. At the
91 // very least, large values will slow down compaction, causing occasional I/O
92 // spikes.
93 static constexpr unsigned kWrapThreshold = 64 * 1024;
94
95 // MIME type used for Blobs that wrap IDBValues.
96 static constexpr const char* kWrapMimeType =
97 "application/x-blink-idb-value-wrapper";
jbroman 2017/05/23 20:13:11 IIUC, IANA no longer recommends deploying unregist
pwnall 2017/05/25 13:27:12 I submitted an application for "application/vnd.bl
98
99 private:
100 // Used to serialize the wrapped value.
101 static void WriteVarint(unsigned value, Vector<char>& output);
102
103 RefPtr<SerializedScriptValue> serialized_value_;
104 RefPtr<BlobDataHandle> wrapper_handle_;
105 Vector<WebBlobInfo> blob_info_;
106 Vector<BlobDataHandle> blob_handles_;
107 Vector<char> wire_bytes_;
108 #if DCHECK_IS_ON()
109 bool had_exception_ = false;
110 bool wrap_called_ = false;
111 #endif // DCHECK_IS_ON()
112 };
113
114 // State and logic for unwrapping large IndexedDB values from Blobs.
115 //
116 // See IDBValueWrapper for an explanation of the wrapping concept.
117 //
118 // Once created, an IDBValueUnwrapper instance can be used to unwrap multiple
119 // Blobs. For each Blob to be unwrapped, the caller should first call Parse().
120 // If the method succeeds, the IDBValueUnwrapper will store the parse state,
121 // which can be obtained using WrapperBlobSize() and WrapperBlobHandle().
122 class IDBValueUnwrapper {
123 STACK_ALLOCATED();
124
125 public:
126 IDBValueUnwrapper();
127
128 // True if the IDBValue's data was wrapped in a Blob.
129 static bool IsWrapped(IDBValue*);
130
131 // True if at least one of the IDBValues' data was wrapped in a Blob.
132 static bool IsWrapped(const Vector<RefPtr<IDBValue>>&);
133
134 // Pieces together an unwrapped IDBValue from a wrapped value and Blob data.
135 static RefPtr<IDBValue> CreateUnwrapped(
136 IDBValue* wrapped_value,
137 RefPtr<SharedBuffer>&& wrapper_blob_content);
138
139 // Parses the wrapper Blob information from a wrapped IDBValue.
140 //
141 // Returns true for success, and false for failure. Failure can mean that the
142 // given value was not a wrapped IDBValue, or that the value bytes were
143 // corrupted.
144 bool Parse(IDBValue*);
145
146 // Returns the size of the Blob obtained by the last Unwrap() call.
147 //
148 // Should only be called after a successful result from Unwrap().
149 inline unsigned WrapperBlobSize() const {
150 DCHECK(end_);
151 return blob_size_;
152 }
153
154 // Returns a handle to the Blob obtained by the last Unwrap() call.
155 //
156 // Should only be called exactly once after a successful result from Unwrap().
157 RefPtr<BlobDataHandle> WrapperBlobHandle();
158
159 private:
160 // Used to deserialize the wrapped value.
161 bool ReadVarint(unsigned& value);
162
163 // Resets the parsing state.
164 inline bool Reset() {
165 #if DCHECK_IS_ON()
166 blob_handle_.Clear();
167 current_ = nullptr;
168 end_ = nullptr;
169 #endif // DCHECK_IS_ON()
170 return false;
171 }
172
173 // Deserialization cursor in the SharedBuffer of the IDBValue being unwrapped.
174 const uint8_t* current_;
175
176 // Smallest invalid position_ value.
177 const uint8_t* end_;
178
179 // The size of the Blob holding the data for the last unwrapped IDBValue.
180 unsigned blob_size_;
181
182 // Handle to the Blob holding the data for the last unwrapped IDBValue.
183 RefPtr<BlobDataHandle> blob_handle_;
184 };
185
186 } // namespace blink
187
188 #endif // IDBValueWrapping_h
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698