24
edits
(→Phase 1: add notes about cycle collecting) |
(add references to bugs) |
||
Line 25: | Line 25: | ||
== Abstract use of preferences to dedicated module == | == Abstract use of preferences to dedicated module == | ||
See [https://bugzilla.mozilla.org/show_bug.cgi?id=1186273 bug 1186273]. | |||
Preferences can only be accessed on the main thread. Workers should access a cached, thread safe version of that in a dedicated module. This should merge uses of preferences throughout the code, including GlobalDirs and OverrideRootDir. | Preferences can only be accessed on the main thread. Workers should access a cached, thread safe version of that in a dedicated module. This should merge uses of preferences throughout the code, including GlobalDirs and OverrideRootDir. | ||
Line 47: | Line 49: | ||
The string bundle service can only be accessed on the main thread and should be initialized as part of the preferences. | The string bundle service can only be accessed on the main thread and should be initialized as part of the preferences. | ||
== Observers == | |||
See [https://bugzilla.mozilla.org/show_bug.cgi?id=1186273 bug 1186273]. | |||
The observer service can only be accessed on the main thread. Workers should access a cached, thread safe version of that in a dedicated module. This should merge uses of observers throughout the code, including FileUpdateDispatcher. | |||
This module (ObserverManager) should be a singleton, created by nsLayoutStatics::Initialize and destroyed via ClearOnShutdown. If the singleton is missing, all device storage APIs should fail (rather than attempt to initialize given they may not be on the main thread). | |||
When an nsDOMDeviceStorage object is created/destroyed, it should register/deregister as a listener. Any ObserverManager::Observe notifications should be proxied on the current thread to the nsDOMDeviceStorage objects, after doing any common work such as querying the volume manager. | |||
The following events will need to be pushed to the nsDOMDeviceStorage objects on the worker threads: | |||
* nsPref:changed | |||
* volume-state-changed | |||
* file-watcher-update | |||
* disk-space-watcher | |||
The following events may be processed inside the ObserverManager: | |||
* file-watcher-notify | |||
* download-watcher-notify | |||
There is a special case for event listeners as presently it adds/removes an observer if a system listener is added to nsDOMDeviceStorage (see ::AddSystemEventListener and ::RemoveEventListener). Since nsDOMDeviceStorage (and going forward the ObserverManager) already listen on those events, this code should be removed as there is no need for a special case (additionally, there does not appear to be any system listeners using nsDOMDeviceStorage, so this is dead code.) | |||
Rather than accept nsDOMDeviceStorage objects directly, it should define an interface which it implements so that other objects (i.e. DeviceStorageAreaListener) may reuse the same module to receive volume state change notifications. | |||
== Consolidate and cache use of permissions == | == Consolidate and cache use of permissions == | ||
See [https://bugzilla.mozilla.org/show_bug.cgi?id=1171170 bug 1171170]. | |||
When checking the permissions, we must run on main thread to possibly put up allow/deny dialog and to query the parent process (if a child). To minimize delegating to the main thread from workers, we should cache the permission check result. In addition this should reduce the latency of device storage APIs due to removing an extra round trip between the parent and child processes. | When checking the permissions, we must run on main thread to possibly put up allow/deny dialog and to query the parent process (if a child). To minimize delegating to the main thread from workers, we should cache the permission check result. In addition this should reduce the latency of device storage APIs due to removing an extra round trip between the parent and child processes. | ||
Line 69: | Line 97: | ||
== Cycle collected reference counting == | == Cycle collected reference counting == | ||
See [https://bugzilla.mozilla.org/show_bug.cgi?id=1171170 bug 1171170]. | |||
nsDOMDeviceStorage, nsDOMDeviceStorageCursor, DOMRequest and DeviceStorageRequest are all cycle collected objects. The reference counting for cycle collected objects is not threadsafe (and this is unlikely to change). As such great care must be used when moving references across thread boundaries, in addition to the fact we must guarantee they are freed in the owning thread context. | nsDOMDeviceStorage, nsDOMDeviceStorageCursor, DOMRequest and DeviceStorageRequest are all cycle collected objects. The reference counting for cycle collected objects is not threadsafe (and this is unlikely to change). As such great care must be used when moving references across thread boundaries, in addition to the fact we must guarantee they are freed in the owning thread context. | ||
Line 78: | Line 108: | ||
The alternative is centralize all references to DOM objects in a threadsafe refcounting request manager. The manager would supply the rest of the module with opaque handles identifying the DOMRequest objects. When any other object needs to interact with the DOM objects, the manager would marshal access appropriately. For posting success/error responses, it would post to the owning thread with the desired value, do any necessary JS transforms, trigger the appropriate action (FireSuccess/FireError/FireDone) and if complete, release its reference to the DOM object. The lifecycle of a single class, which is independent of the specific operations being performed, would be much easier to manage and guarantee correctness. | The alternative is centralize all references to DOM objects in a threadsafe refcounting request manager. The manager would supply the rest of the module with opaque handles identifying the DOMRequest objects. When any other object needs to interact with the DOM objects, the manager would marshal access appropriately. For posting success/error responses, it would post to the owning thread with the desired value, do any necessary JS transforms, trigger the appropriate action (FireSuccess/FireError/FireDone) and if complete, release its reference to the DOM object. The lifecycle of a single class, which is independent of the specific operations being performed, would be much easier to manage and guarantee correctness. | ||
== | == Device storage IPC API with child-parent processes == | ||
See [https://bugzilla.mozilla.org/show_bug.cgi?id=1171170 bug 1171170]. | |||
This | PContent is the IPC object which marshalls access to the device storage IPC APIs. This is a singleton and can only be accessed on the main thread. | ||
Sending messages happens in the following functions: | |||
* ContinueCursorEvent::Continue | |||
* nsDOMDeviceStorageCursor::Allow | |||
* DeviceStorageRequest::Allow | |||
* FileUpdateDispatcher::Observe | |||
For FileUpdateDispatcher::Observe, this will always happen on the main thread and can be left as is. For the others, the caller may not be the main thread, in which case it must create a runnable to proxy the call to the main thread. | |||
Receiving the responses happens in DeviceStorageRequestChild::Recv__delete__. This will need to create a runnable to proxy the response to the owning thread of the DeviceStorageRequest. | |||
== Used space cache (DeviceStorageUsedSpaceCache) == | |||
= | See [https://bugzilla.mozilla.org/show_bug.cgi?id=1196321 bug 1196321]. | ||
This is only accessed on parent process, so there is no child process concerns. However since workers can also exist on the parent, it needs to be made thread safe. It may continue to be initialized on demand since it has no dependencies on the main thread. All operations besides initialization appear to run on a dedicated IO thread. As such, only the ::CreateOrGet method needs to be protected via a mutex. | This is only accessed on parent process, so there is no child process concerns. However since workers can also exist on the parent, it needs to be made thread safe. It may continue to be initialized on demand since it has no dependencies on the main thread. All operations besides initialization appear to run on a dedicated IO thread. As such, only the ::CreateOrGet method needs to be protected via a mutex. | ||
== MIME service == | == MIME service == | ||
See [https://bugzilla.mozilla.org/show_bug.cgi?id=1196315 bug 1196315]. | |||
The MIME type of a file is queried for each file when an enumeration operation is requested. The MIME service can only be accessed on the main thread; this is problematic given that this would presently require a context switch to and from each time the user calls continue on our enumeration cursor. nsExternalHelperAppService::GetTypeFromFile extracts the file extension and check then checks that against the numerous sources of MIME information (consistent with the IDL description). We should switch to extracting the file extension ourselves, use nsExternalHelperAppService:::GetTypeFromExtension to get the MIME type on the main thread for unknown extensions as is done today, and cache the result for the duration of the enumeration cursor. This balances worker performance (i.e. very likely that the number of files greatly exceeds the number of unique extensions) with accuracy (i.e. by caching only for a particular cursor request, we allow the underlying service to discover new MIME types by addition of plugins, etc if the enumeration is reattempted). | The MIME type of a file is queried for each file when an enumeration operation is requested. The MIME service can only be accessed on the main thread; this is problematic given that this would presently require a context switch to and from each time the user calls continue on our enumeration cursor. nsExternalHelperAppService::GetTypeFromFile extracts the file extension and check then checks that against the numerous sources of MIME information (consistent with the IDL description). We should switch to extracting the file extension ourselves, use nsExternalHelperAppService:::GetTypeFromExtension to get the MIME type on the main thread for unknown extensions as is done today, and cache the result for the duration of the enumeration cursor. This balances worker performance (i.e. very likely that the number of files greatly exceeds the number of unique extensions) with accuracy (i.e. by caching only for a particular cursor request, we allow the underlying service to discover new MIME types by addition of plugins, etc if the enumeration is reattempted). | ||
Line 110: | Line 138: | ||
It is also queried when a file is added (prior to issuing the request) via nsDOMDeviceStorage::Add in order to determine the correct file extension. This should be moved into the create request itself, after the permission check, and before the file creation itself or sending the request to the parent process (if a child process). Note that while nsDOMDeviceStorage::Add indicates the file will be rejected by nsDOMDeviceStorage::Add(OrAppend)Named if the given extension is empty, the check is actually performed just before creating the WriteFileEvent object in DeviceStorageRequest::Allow. | It is also queried when a file is added (prior to issuing the request) via nsDOMDeviceStorage::Add in order to determine the correct file extension. This should be moved into the create request itself, after the permission check, and before the file creation itself or sending the request to the parent process (if a child process). Note that while nsDOMDeviceStorage::Add indicates the file will be rejected by nsDOMDeviceStorage::Add(OrAppend)Named if the given extension is empty, the check is actually performed just before creating the WriteFileEvent object in DeviceStorageRequest::Allow. | ||
== Device | == Expose Device Storage to workers == | ||
See [https://bugzilla.mozilla.org/show_bug.cgi?id=1196322 bug 1196322]. | |||
The appropriate WebIDL Exposure tags should be added to all device storage interfaces and the Navigator device storage partial interfaces. | The appropriate WebIDL Exposure tags should be added to all device storage interfaces and the Navigator device storage partial interfaces. |
edits