Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / dom / localstorage / LocalStorageCommon.h
blob408f7106a2113647d6e44266beb4f7003dac8aaf
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/. */
7 #ifndef mozilla_dom_localstorage_LocalStorageCommon_h
8 #define mozilla_dom_localstorage_LocalStorageCommon_h
10 #include <cstdint>
11 #include "ErrorList.h"
12 #include "mozilla/Attributes.h"
13 #include "mozilla/dom/quota/QuotaCommon.h"
14 #include "nsLiteralString.h"
15 #include "nsStringFwd.h"
18 * Local storage
19 * ~~~~~~~~~~~~~
21 * Implementation overview
22 * ~~~~~~~~~~~~~~~~~~~~~~~
24 * The implementation is based on a per principal/origin cache (datastore)
25 * living in the main process and synchronous calls initiated from content
26 * processes.
27 * The IPC communication is managed by database actors which link to the
28 * datastore.
29 * The synchronous blocking of the main thread is done by using a special
30 * technique or by using standard synchronous IPC calls.
32 * General architecture
33 * ~~~~~~~~~~~~~~~~~~~~
34 * The current browser architecture consists of one main process and multiple
35 * content processes (there are other processes but for simplicity's sake, they
36 * are not mentioned here). The processes use the IPC communication to talk to
37 * each other. Local storage implementation uses the client-server model, so
38 * the main process manages all the data and content processes then request
39 * particular data from the main process. The main process is also called the
40 * parent or the parent side, the content process is then called the child or
41 * the child side.
43 * Datastores
44 * ~~~~~~~~~~
46 * A datastore provides a convenient way to access data for given origin. The
47 * data is always preloaded into memory and indexed using a hash table. This
48 * enables very fast access to particular stored items. There can be only one
49 * datastore per origin and exists solely on the parent side. It is represented
50 * by the "Datastore" class. A datastore instance is a ref counted object and
51 * lives on the PBackground thread, it is kept alive by database objects. When
52 * the last database object for given origin is destroyed, the associated
53 * datastore object is destroyed too.
55 * Databases
56 * ~~~~~~~~~
58 * A database allows direct access to a datastore from a content process. There
59 * can be multiple databases for the same origin, but they all share the same
60 * datastore.
61 * Databases use the PBackgroundLSDatabase IPDL protocol for IPC communication.
62 * Given the nature of local storage, most of PBackgroundLSDatabase messages
63 * are synchronous.
65 * On the parent side, the database is represented by the "Database" class that
66 * is a parent actor as well (implements the "PBackgroundLSDatabaseParent"
67 * interface). A database instance is a ref counted object and lives on the
68 * PBackground thread.
69 * All live database actors are tracked in an array.
71 * On the child side, the database is represented by the "LSDatabase" class
72 * that provides indirect access to a child actor. An LSDatabase instance is a
73 * ref counted object and lives on the main thread.
74 * The actual child actor is represented by the "LSDatabaseChild" class that
75 * implements the "PBackgroundLSDatabaseChild" interface. An "LSDatabaseChild"
76 * instance is not ref counted and lives on the main thread too.
78 * Synchronous blocking
79 * ~~~~~~~~~~~~~~~~~~~~
81 * Local storage is synchronous in nature which means the execution can't move
82 * forward until there's a reply for given method call.
83 * Since we have to use IPC anyway, we could just always use synchronous IPC
84 * messages for all local storage method calls. Well, there's a problem with
85 * that approach.
86 * If the main process needs to do some off PBackground thread stuff like
87 * getting info from principals on the main thread or some asynchronous stuff
88 * like directory locking before sending a reply to a synchronous message, then
89 * we would have to block the thread or spin the event loop which is usually a
90 * bad idea, especially in the main process.
91 * Instead, we can use a special thread in the content process called
92 * RemoteLazyInputStream thread for communication with the main process using
93 * asynchronous messages and synchronously block the main thread until the DOM
94 * File thread is done (the main thread blocking is a bit more complicated, see
95 * the comment in RequestHelper::StartAndReturnResponse for more details).
96 * Anyway, the extra hop to the RemoteLazyInputStream thread brings another
97 * overhead and latency. The final solution is to use a combination of the
98 * special thread for complex stuff like datastore preparation and synchronous
99 * IPC messages sent directly from the main thread for database access when data
100 * is already loaded from disk into memory.
102 * Requests
103 * ~~~~~~~~
105 * Requests are used to handle asynchronous high level datastore operations
106 * which are initiated in a content process and then processed in the parent
107 * process (for example, preparation of a datastore).
108 * Requests use the "PBackgroundLSRequest" IPDL protocol for IPC communication.
110 * On the parent side, the request is represented by the "LSRequestBase" class
111 * that is a parent actor as well (implements the "PBackgroundLSRequestParent"
112 * interface). It's an abstract class (contains pure virtual functions) so it
113 * can't be used to create instances.
114 * It also inherits from the "DatastoreOperationBase" class which is a generic
115 * base class for all datastore operations. The "DatastoreOperationsBase" class
116 * inherits from the "Runnable" class, so derived class instances are ref
117 * counted, can be dispatched to multiple threads and thus they are used on
118 * multiple threads. However, derived class instances can be created on the
119 * PBackground thread only.
121 * On the child side, the request is represented by the "RequestHelper" class
122 * that covers all the complexity needed to start a new request, handle
123 * responses and do safe main thread blocking at the same time.
124 * It inherits from the "Runnable" class, so instances are ref counted and
125 * they are internally used on multiple threads (specifically on the main
126 * thread and on the RemoteLazyInputStream thread). Anyway, users should create
127 * and use instances of this class only on the main thread.
128 * The actual child actor is represented by the "LSRequestChild" class that
129 * implements the "PBackgroundLSRequestChild" interface. An "LSRequestChild"
130 * instance is not ref counted and lives on the RemoteLazyInputStream thread.
131 * Request responses are passed using the "LSRequestChildCallback" interface.
133 * Preparation of a datastore
134 * ~~~~~~~~~~~~~~~~~~~~~~~~~~
136 * The datastore preparation is needed to make sure a datastore is fully loaded
137 * into memory. Every datastore preparation produces a unique id (even if the
138 * datastore for given origin already exists).
139 * On the parent side, the preparation is handled by the "PrepareDatastoreOp"
140 * class which inherits from the "LSRequestBase" class. The preparation process
141 * on the parent side is quite complicated, it happens sequentially on multiple
142 * threads and is managed by a state machine.
143 * On the child side, the preparation is done in the LSObject::EnsureDatabase
144 * method using the "RequestHelper" class. The method starts a new preparation
145 * request and obtains a unique id produced by the parent (or an error code if
146 * the requested failed to complete).
148 * Linking databases to a datastore
149 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
151 * A datastore exists only on the parent side, but it can be accessed from the
152 * content via database actors. Database actors are initiated on the child side
153 * and they need to be linked to a datastore on the parent side via an id. The
154 * datastore preparation process gives us the required id.
155 * The linking is initiated on the child side in the LSObject::EnsureDatabase
156 * method by calling SendPBackgroundLSDatabaseConstructor and finished in
157 * RecvPBackgroundLSDatabaseConstructor on the parent side.
159 * Actor migration
160 * ~~~~~~~~~~~~~~~
162 * In theory, the datastore preparation request could return a database actor
163 * directly (instead of returning an id intended for database linking to a
164 * datastore). However, as it was explained above, the preparation must be done
165 * on the RemoteLazyInputStream thread and database objects are used on the main
166 * thread. The returned actor would have to be migrated from the
167 * RemoteLazyInputStream thread to the main thread and that's something which
168 * our IPDL doesn't support yet.
170 * Exposing local storage
171 * ~~~~~~~~~~~~~~~~~~~~~~
173 * The implementation is exposed to the DOM via window.localStorage attribute.
174 * Local storage's sibling, session storage shares the same WebIDL interface
175 * for exposing it to web content, therefore there's an abstract class called
176 * "Storage" that handles some of the common DOM bindings stuff. Local storage
177 * specific functionality is defined in the "LSObject" derived class.
178 * The "LSObject" class is also a starting point for the datastore preparation
179 * and database linking.
181 * Local storage manager
182 * ~~~~~~~~~~~~~~~~~~~~~
184 * The local storage manager exposes some of the features that need to be
185 * available only in the chrome code or tests. The manager is represented by
186 * the "LocalStorageManager2" class that implements the "nsIDOMStorageManager"
187 * interface.
190 namespace mozilla {
192 class LogModule;
194 namespace ipc {
196 class PrincipalInfo;
198 } // namespace ipc
200 namespace dom {
202 extern const char16_t* kLocalStorageType;
205 * Convenience data-structure to make it easier to track whether a value has
206 * changed and what its previous value was for notification purposes. Instances
207 * are created on the stack by LSObject and passed to LSDatabase which in turn
208 * passes them onto LSSnapshot for final updating/population. LSObject then
209 * generates an event, if appropriate.
211 class MOZ_STACK_CLASS LSNotifyInfo {
212 bool mChanged;
213 nsString mOldValue;
215 public:
216 LSNotifyInfo() : mChanged(false) {}
218 bool changed() const { return mChanged; }
220 bool& changed() { return mChanged; }
222 const nsString& oldValue() const { return mOldValue; }
224 nsString& oldValue() { return mOldValue; }
228 * A check of LSNG being enabled, the value is latched once initialized so
229 * changing the preference during runtime has no effect. May be called on any
230 * thread in the parent process, but you should call
231 * CachedNextGenLocalStorageEnabled if you know that NextGenLocalStorageEnabled
232 * was already called because it is faster. May be called on any thread in
233 * content processes, but you should call CachedNextGenLocalStorageEnabled
234 * directly if you know you are in a content process because it is slightly
235 * faster.
237 bool NextGenLocalStorageEnabled();
240 * Called by ContentChild during content process initialization to initialize
241 * the global variable in the content process with the latched value in the
242 * parent process."
244 void RecvInitNextGenLocalStorageEnabled(const bool aEnabled);
247 * Cached any-thread version of NextGenLocalStorageEnabled().
249 bool CachedNextGenLocalStorageEnabled();
252 * Returns a success value containing a pair of origin attribute suffix and
253 * origin key.
255 Result<std::pair<nsCString, nsCString>, nsresult> GenerateOriginKey2(
256 const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
258 LogModule* GetLocalStorageLogger();
260 } // namespace dom
261 } // namespace mozilla
263 #endif // mozilla_dom_localstorage_LocalStorageCommon_h