Labs/Jetpack/Reboot/JEP/104
Contents
JEP 104 - Simple Storage
- Champion: Drew Willcoxon - adw at mozilla.com
- Status: Accepted/Initial implementation introduced in Jetpack SDK 0.4
- Bug Ticket: bug 548589
- Type: API
Proposal
Provide a simple, persistent object data store that is private to each extension.
Simple storage is implemented as a module named simple-storage. The object referred to by the storage property of the module is persistent and private to each extension. To persistently store a value, an extension assigns it to a property on the storage object. Extensions do not cause any data to be written to disk until they import the module and create a property on the storage object.
All values placed into storage must be serializable. Strings, numbers, booleans, null, arrays, and objects are serialized automatically. Array members and object properties are serialized recursively. Functions are not serialized automatically. Consumers are responsible for serializing and deserializing values that are not automatically serialized. This proposal does not define or require consumers to implement any particular serialization scheme. Placing non-serializable items into storage results in undefined behavior, but doing so is a logical error, and such items will not be persistently stored.
DOM Storage provides a similar facility. However, as implemented by Gecko, it supports storing only strings, which forces an extension to manually serialize and deserialize its data. This proposal effectively abstracts away the serialization for the common data types, allowing extensions to store values directly and simply. It should also be noted that this proposal can be implemented on the Web using DOM Storage and therefore does not "break" the Web.
Reliability Guarantees
Define an extension's session to be the period from its load into the browser to its unload out of the browser.
Within a Session
The guarantees that arise within a session are the guarantees of normal JavaScript objects, since the storage object is a normal JavaScript object.
Session to Session
At the start of any session, the graph of the storage object is a tree: There are no cycles. Cyclical references to objects in the previous session are broken by duplicating the objects.
By the end of any session, either all the data placed into storage in the current session and every previous session will be on disk, or no data will be on disk.
Use Cases
Simple storage should be sufficient for the vast majority of cases where an extension needs to store arbitrary data persistently.
Non-Use Cases
- Extensions requiring a relational database.
- Extensions requiring access to arbitrary files on disk.
Dependencies & Requirements
- If implemented as JSON on disk like the prototype, requires:
- A generic JSON storage module. It's possible to bake the JSON storage code into simple storage, but there are two separate tasks: 1) shuttling JSON to and from disk, 2) exposing the store as a single persistent object private to each extension. A JSON storage module requires:
- The ability to read and write files. Writing should be done off the main thread.
- Probably a timer mechanism to sync to disk.
- A canonical place to save user data and mechanism to access it, probably a handle to the user's profile directory.
- A generic JSON storage module. It's possible to bake the JSON storage code into simple storage, but there are two separate tasks: 1) shuttling JSON to and from disk, 2) exposing the store as a single persistent object private to each extension. A JSON storage module requires:
- If implemented on top of DOM Storage (localStorage or globalStorage), requires some scheme for mapping extensions to origins and providing that mapping to Gecko's DOM Storage facilities.
- Life cycle and extension ID mechanisms.
Internal Methods
This JEP doesn't export anything into the Jetpack Platform Library.
API Methods
None.
Example Usage
var myStorage = require("simple-storage").storage; myStorage.foo = "foo!"; myStorage.bar = ["a", 2, null, { baz: 1337 }];
Issues
- Atomic commit of local storage. (Saying no ACID guarantees isn't enough.)
- adw: I think I addressed this OK in #Reliability Guarantees.
- Quotas? If so, how? What happens when quotas are hit?
- adw: A quota would affect this API only insofar as what to do when the quota is hit. (The management of quotas is external to this proposal.) Forcing people to wrap every property set in a try-catch is bad. Instead, allow the extension to set an error callback that's called when the quota is hit.
- We should probably enforce a quota from the outset, since it's easier to raise or abolish a quota than enforce one after people start using the API. What's a good size? What can consumers do when they're over quota? They'll have to delete properties until they're under, so they'll need a method that returns quota usage. Adw 17:28, 16 February 2010 (UTC)
- DOM Storage is adequate.
- jjb The proposal suggests implementations as JSON. So its just strings. So we can just use DOM storage right?
- adw: 1) Implementation of the API is outside the scope of the API's proposal. It's noted here, as in all other JEPs, to surface potential dependencies in Cuddlefish. 2) Extensions are free as always to use DOM Storage if they wish.