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