DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (e9d6d0965bc6)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_localstorage_LocalStorageCommon_h
#define mozilla_dom_localstorage_LocalStorageCommon_h

/*
 * Local storage
 * ~~~~~~~~~~~~~
 *
 * Implementation overview
 * ~~~~~~~~~~~~~~~~~~~~~~~
 *
 * The implementation is based on a per principal/origin cache (datastore)
 * living in the main process and synchronous calls initiated from content
 * processes.
 * The IPC communication is managed by database actors which link to the
 * datastore.
 * The synchronous blocking of the main thread is done by using a special
 * technique or by using standard synchronous IPC calls.
 *
 * General architecture
 * ~~~~~~~~~~~~~~~~~~~~
 * The current browser architecture consists of one main process and multiple
 * content processes (there are other processes but for simplicity's sake, they
 * are not mentioned here). The processes use the IPC communication to talk to
 * each other. Local storage implementation uses the client-server model, so
 * the main process manages all the data and content processes then request
 * particular data from the main process. The main process is also called the
 * parent or the parent side, the content process is then called the child or
 * the child side.
 *
 * Datastores
 * ~~~~~~~~~~
 *
 * A datastore provides a convenient way to access data for given origin. The
 * data is always preloaded into memory and indexed using a hash table. This
 * enables very fast access to particular stored items. There can be only one
 * datastore per origin and exists solely on the parent side. It is represented
 * by the "Datastore" class. A datastore instance is a ref counted object and
 * lives on the PBackground thread, it is kept alive by database objects. When
 * the last database object for given origin is destroyed, the associated
 * datastore object is destroyed too.
 *
 * Databases
 * ~~~~~~~~~
 *
 * A database allows direct access to a datastore from a content process. There
 * can be multiple databases for the same origin, but they all share the same
 * datastore.
 * Databases use the PBackgroundLSDatabase IPDL protocol for IPC communication.
 * Given the nature of local storage, most of PBackgroundLSDatabase messages
 * are synchronous.
 *
 * On the parent side, the database is represented by the "Database" class that
 * is a parent actor as well (implements the "PBackgroundLSDatabaseParent"
 * interface). A database instance is a ref counted object and lives on the
 * PBackground thread.
 * All live database actors are tracked in an array.
 *
 * On the child side, the database is represented by the "LSDatabase" class
 * that provides indirect access to a child actor. An LSDatabase instance is a
 * ref counted object and lives on the main thread.
 * The actual child actor is represented by the "LSDatabaseChild" class that
 * implements the "PBackgroundLSDatabaseChild" interface. An "LSDatabaseChild"
 * instance is not ref counted and lives on the main thread too.
 *
 * Synchronous blocking
 * ~~~~~~~~~~~~~~~~~~~~
 *
 * Local storage is synchronous in nature which means the execution can't move
 * forward until there's a reply for given method call.
 * Since we have to use IPC anyway, we could just always use synchronous IPC
 * messages for all local storage method calls. Well, there's a problem with
 * that approach.
 * If the main process needs to do some off PBackground thread stuff like
 * getting info from principals on the main thread or some asynchronous stuff
 * like directory locking before sending a reply to a synchronous message, then
 * we would have to block the thread or spin the event loop which is usually a
 * bad idea, especially in the main process.
 * Instead, we can use a special thread in the content process called DOM File
 * thread for communication with the main process using asynchronous messages
 * and synchronously block the main thread until the DOM File thread is done
 * (the main thread blocking is a bit more complicated, see the comment in
 * RequestHelper::StartAndReturnResponse for more details).
 * Anyway, the extra hop to the DOM File thread brings another overhead and
 * latency. The final solution is to use a combination of the special thread
 * for complex stuff like datastore preparation and synchronous IPC messages
 * sent directly from the main thread for database access when data is already
 * loaded from disk into memory.
 *
 * Requests
 * ~~~~~~~~
 *
 * Requests are used to handle asynchronous high level datastore operations
 * which are initiated in a content process and then processed in the parent
 * process (for example, preparation of a datastore).
 * Requests use the "PBackgroundLSRequest" IPDL protocol for IPC communication.
 *
 * On the parent side, the request is represented by the "LSRequestBase" class
 * that is a parent actor as well (implements the "PBackgroundLSRequestParent"
 * interface). It's an abstract class (contains pure virtual functions) so it
 * can't be used to create instances.
 * It also inherits from the "DatastoreOperationBase" class which is a generic
 * base class for all datastore operations. The "DatastoreOperationsBase" class
 * inherits from the "Runnable" class, so derived class instances are ref
 * counted, can be dispatched to multiple threads and thus they are used on
 * multiple threads. However, derived class instances can be created on the
 * PBackground thread only.
 *
 * On the child side, the request is represented by the "RequestHelper" class
 * that covers all the complexity needed to start a new request, handle
 * responses and do safe main thread blocking at the same time.
 * It inherits from the "Runnable" class, so instances are ref counted and
 * they are internally used on multiple threads (specifically on the main
 * thread and on the DOM File thread). Anyway, users should create and use
 * instances of this class only on the main thread (apart from a special case
 * when we need to cancel the request from an internal chromium IPC thread to
 * prevent a dead lock involving CPOWs).
 * The actual child actor is represented by the "LSRequestChild" class that
 * implements the "PBackgroundLSRequestChild" interface. An "LSRequestChild"
 * instance is not ref counted and lives on the DOM File thread.
 * Request responses are passed using the "LSRequestChildCallback" interface.
 *
 * Preparation of a datastore
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * The datastore preparation is needed to make sure a datastore is fully loaded
 * into memory. Every datastore preparation produces a unique id (even if the
 * datastore for given origin already exists).
 * On the parent side, the preparation is handled by the "PrepareDatastoreOp"
 * class which inherits from the "LSRequestBase" class. The preparation process
 * on the parent side is quite complicated, it happens sequentially on multiple
 * threads and is managed by a state machine.
 * On the child side, the preparation is done in the LSObject::EnsureDatabase
 * method using the "RequestHelper" class. The method starts a new preparation
 * request and obtains a unique id produced by the parent (or an error code if
 * the requested failed to complete).
 *
 * Linking databases to a datastore
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * A datastore exists only on the parent side, but it can be accessed from the
 * content via database actors. Database actors are initiated on the child side
 * and they need to be linked to a datastore on the parent side via an id. The
 * datastore preparation process gives us the required id.
 * The linking is initiated on the child side in the LSObject::EnsureDatabase
 * method by calling SendPBackgroundLSDatabaseConstructor and finished in
 * RecvPBackgroundLSDatabaseConstructor on the parent side.
 *
 * Actor migration
 * ~~~~~~~~~~~~~~~
 *
 * In theory, the datastore preparation request could return a database actor
 * directly (instead of returning an id intended for database linking to a
 * datastore). However, as it was explained above, the preparation must be done
 * on the DOM File thread and database objects are used on the main thread. The
 * returned actor would have to be migrated from the DOM File thread to the
 * main thread and that's something which our IPDL doesn't support yet.
 *
 * Exposing local storage
 * ~~~~~~~~~~~~~~~~~~~~~~
 *
 * The implementation is exposed to the DOM via window.localStorage attribute.
 * Local storage's sibling, session storage shares the same WebIDL interface
 * for exposing it to web content, therefore there's an abstract class called
 * "Storage" that handles some of the common DOM bindings stuff. Local storage
 * specific functionality is defined in the "LSObject" derived class.
 * The "LSObject" class is also a starting point for the datastore preparation
 * and database linking.
 *
 * Local storage manager
 * ~~~~~~~~~~~~~~~~~~~~~
 *
 * The local storage manager exposes some of the features that need to be
 * available only in the chrome code or tests. The manager is represented by
 * the "LocalStorageManager2" class that implements the "nsIDOMStorageManager"
 * interface.
 */

#include "mozilla/Attributes.h"
#include "nsString.h"

namespace mozilla {

class LogModule;

namespace ipc {

class PrincipalInfo;

}  // namespace ipc

namespace dom {

extern const char16_t* kLocalStorageType;

/**
 * Convenience data-structure to make it easier to track whether a value has
 * changed and what its previous value was for notification purposes.  Instances
 * are created on the stack by LSObject and passed to LSDatabase which in turn
 * passes them onto LSSnapshot for final updating/population.  LSObject then
 * generates an event, if appropriate.
 */
class MOZ_STACK_CLASS LSNotifyInfo {
  bool mChanged;
  nsString mOldValue;

 public:
  LSNotifyInfo() : mChanged(false) {}

  bool changed() const { return mChanged; }

  bool& changed() { return mChanged; }

  const nsString& oldValue() const { return mOldValue; }

  nsString& oldValue() { return mOldValue; }
};

/**
 * A check of LSNG being enabled, the value is latched once initialized so
 * changing the preference during runtime has no effect.
 * May be called on any thread in the parent process, but you should call
 * CachedNextGenLocalStorageEnabled if you know that NextGenLocalStorageEnabled
 * was already called because it is faster.
 * May be called on the main thread only in a content process.
 */
bool NextGenLocalStorageEnabled();

/**
 * Cached any-thread version of NextGenLocalStorageEnabled().
 */
bool CachedNextGenLocalStorageEnabled();

nsresult GenerateOriginKey2(const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
                            nsACString& aOriginAttrSuffix,
                            nsACString& aOriginKey);

LogModule* GetLocalStorageLogger();

}  // namespace dom
}  // namespace mozilla

#endif  // mozilla_dom_localstorage_LocalStorageCommon_h