Bug 685757 - Document Store API; r=philikon DONTBUILD
authorGregory Szorc <gps@mozilla.com>
Fri, 09 Sep 2011 10:34:58 -0700
changeset 78565 cebcf93501983c32332ef712b32dcf271295b382
parent 78564 5e7a991c8305cc5a2f895923362e2832de5c414d
child 78566 cb70379936f3ecc1e598697400fd6c3b5ffe652a
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersphilikon
bugs685757
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 685757 - Document Store API; r=philikon DONTBUILD
services/sync/modules/engines.js
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -176,19 +176,34 @@ Tracker.prototype = {
     this._log.trace("Clearing changed ID list");
     this.changedIDs = {};
     this.saveChangedIDs();
   }
 };
 
 
 
-/*
- * Data Stores
- * These can wrap, serialize items and apply commands
+/**
+ * The Store serves as the interface between Sync and stored data.
+ *
+ * The name "store" is slightly a misnomer because it doesn't actually "store"
+ * anything. Instead, it serves as a gateway to something that actually does
+ * the "storing."
+ *
+ * The store is responsible for record management inside an engine. It tells
+ * Sync what items are available for Sync, converts items to and from Sync's
+ * record format, and applies records from Sync into changes on the underlying
+ * store.
+ *
+ * Store implementations require a number of functions to be implemented. These
+ * are all documented below.
+ *
+ * For stores that deal with many records or which have expensive store access
+ * routines, it is highly recommended to implement a custom applyIncomingBatch
+ * and/or applyIncoming function on top of the basic APIs.
  */
 
 function Store(name) {
   name = name || "Unnamed";
   this.name = name.toLowerCase();
 
   this._log = Log4Moz.repository.getLogger("Sync.Store." + name);
   let level = Svc.Prefs.get("log.logger.engine." + this.name, "Debug");
@@ -201,16 +216,31 @@ function Store(name) {
 Store.prototype = {
 
   _sleep: function _sleep(delay) {
     let cb = Async.makeSyncCallback();
     this._timer.initWithCallback(cb, delay, Ci.nsITimer.TYPE_ONE_SHOT);
     Async.waitForSyncCallback(cb);
   },
 
+  /**
+   * Apply multiple incoming records against the store.
+   *
+   * This is called with a set of incoming records to process. The function
+   * should look at each record, reconcile with the current local state, and
+   * make the local changes required to bring its state in alignment with the
+   * record.
+   *
+   * The default implementation simply iterates over all records and calls
+   * applyIncoming(). Store implementations may overwrite this function
+   * if desired.
+   *
+   * @param  records Array of records to apply
+   * @return Array of record IDs which did not apply cleanly
+   */
   applyIncomingBatch: function applyIncomingBatch(records) {
     let failed = [];
     for each (let record in records) {
       try {
         this.applyIncoming(record);
       } catch (ex if (ex.code == Engine.prototype.eEngineAbortApplyIncoming)) {
         // This kind of exception should have a 'cause' attribute, which is an
         // originating exception.
@@ -220,55 +250,143 @@ Store.prototype = {
         this._log.warn("Failed to apply incoming record " + record.id);
         this._log.warn("Encountered exception: " + Utils.exceptionStr(ex));
         failed.push(record.id);
       }
     };
     return failed;
   },
 
+  /**
+   * Apply a single record against the store.
+   *
+   * This takes a single record and makes the local changes required so the
+   * local state matches what's in the record.
+   *
+   * The default implementation calls one of remove(), create(), or update()
+   * depending on the state obtained from the store itself. Store
+   * implementations may overwrite this function if desired.
+   *
+   * @param record
+   *        Record to apply
+   */
   applyIncoming: function Store_applyIncoming(record) {
     if (record.deleted)
       this.remove(record);
     else if (!this.itemExists(record.id))
       this.create(record);
     else
       this.update(record);
   },
 
   // override these in derived objects
 
+  /**
+   * Create an item in the store from a record.
+   *
+   * This is called by the default implementation of applyIncoming(). If using
+   * applyIncomingBatch(), this won't be called unless your store calls it.
+   *
+   * @param record
+   *        The store record to create an item from
+   */
   create: function Store_create(record) {
     throw "override create in a subclass";
   },
 
+  /**
+   * Remove an item in the store from a record.
+   *
+   * This is called by the default implementation of applyIncoming(). If using
+   * applyIncomingBatch(), this won't be called unless your store calls it.
+   *
+   * @param record
+   *        The store record to delete an item from
+   */
   remove: function Store_remove(record) {
     throw "override remove in a subclass";
   },
 
+  /**
+   * Update an item from a record.
+   *
+   * This is called by the default implementation of applyIncoming(). If using
+   * applyIncomingBatch(), this won't be called unless your store calls it.
+   *
+   * @param record
+   *        The record to use to update an item from
+   */
   update: function Store_update(record) {
     throw "override update in a subclass";
   },
 
+  /**
+   * Determine whether a record with the specified ID exists.
+   *
+   * Takes a string record ID and returns a booleans saying whether the record
+   * exists.
+   *
+   * @param  id
+   *         string record ID
+   * @return boolean indicating whether record exists locally
+   */
   itemExists: function Store_itemExists(id) {
     throw "override itemExists in a subclass";
   },
 
+  /**
+   * Create a record from the specified ID.
+   *
+   * If the ID is known, the record should be populated with metadata from
+   * the store. If the ID is not known, the record should be created with the
+   * delete field set to true.
+   *
+   * @param  id
+   *         string record ID
+   * @param  collection
+   *         Collection to add record to. This is typically passed into the
+   *         constructor for the newly-created record.
+   * @return record type for this engine
+   */
   createRecord: function Store_createRecord(id, collection) {
     throw "override createRecord in a subclass";
   },
 
+  /**
+   * Change the ID of a record.
+   *
+   * @param  oldID
+   *         string old/current record ID
+   * @param  newID
+   *         string new record ID
+   */
   changeItemID: function Store_changeItemID(oldID, newID) {
     throw "override changeItemID in a subclass";
   },
 
+  /**
+   * Obtain the set of all known record IDs.
+   *
+   * @return Object with ID strings as keys and values of true. The values
+   *         are ignored.
+   */
   getAllIDs: function Store_getAllIDs() {
     throw "override getAllIDs in a subclass";
   },
 
+  /**
+   * Wipe all data in the store.
+   *
+   * This function is called during remote wipes or when replacing local data
+   * with remote data.
+   *
+   * This function should delete all local data that the store is managing. It
+   * can be thought of as clearing out all state and restoring the "new
+   * browser" state.
+   */
   wipe: function Store_wipe() {
     throw "override wipe in a subclass";
   }
 };
 
 
 // Singleton service, holds registered engines