/* 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
#include "ErrorList.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/quota/QuotaCommon.h"
#include "nsLiteralString.h"
#include "nsStringFwd.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
* RemoteLazyInputStream 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 RemoteLazyInputStream 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 RemoteLazyInputStream thread ) . Anyway , users should create
* and use instances of this class only on the main thread .
* 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 RemoteLazyInputStream 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 RemoteLazyInputStream thread and database objects are used on the main
* thread . The returned actor would have to be migrated from the
* RemoteLazyInputStream 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 .
*/
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 any thread in
* content processes , but you should call CachedNextGenLocalStorageEnabled
* directly if you know you are in a content process because it is slightly
* faster .
*/
bool NextGenLocalStorageEnabled();
/**
* Called by ContentChild during content process initialization to initialize
* the global variable in the content process with the latched value in the
* parent process . "
*/
void RecvInitNextGenLocalStorageEnabled(
const bool aEnabled);
/**
* Cached any - thread version of NextGenLocalStorageEnabled ( ) .
*/
bool CachedNextGenLocalStorageEnabled();
/**
* Returns a success value containing a pair of origin attribute suffix and
* origin key .
*/
Result<std::pair<nsCString, nsCString>, nsresult> GenerateOriginKey2(
const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
LogModule* GetLocalStorageLogger();
}
// namespace dom
}
// namespace mozilla
#endif // mozilla_dom_localstorage_LocalStorageCommon_h
Messung V0.5 in Prozent C=96 H=100 G=97
¤ Dauer der Verarbeitung: 0.39 Sekunden
¤
*© Formatika GbR, Deutschland