changeset 47:7664a4e099b5

Factored-out map-reduce implementation into a new interface, which currently has one implementation, SingleThreadedMapReducer.
author Atul Varma <varmaa@toolness.com>
date Tue, 14 Apr 2009 12:45:44 -0700
parents 6da7638d056f
children b0d5bc990a80
files browser-couch.js
diffstat 1 files changed, 91 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/browser-couch.js	Tue Apr 14 11:57:12 2009 -0700
+++ b/browser-couch.js	Tue Apr 14 12:45:44 2009 -0700
@@ -93,6 +93,84 @@
   }
 };
 
+var SingleThreadedMapReducer = {
+  map: function STMR_map(map, dict, progress,
+                         chunkSize, finished) {
+    var mapDict = {};
+    var keys = dict.getKeys();
+    var currDoc;
+
+    function emit(key, value) {
+      // TODO: This assumes that the key will always be
+      // an indexable value. We may have to hash the value,
+      // though, if it's e.g. an Object.
+      var item = mapDict[key];
+      if (!item)
+        item = mapDict[key] = {keys: [], values: []};
+      item.keys.push(currDoc.id);
+      item.values.push(value);
+    }
+
+    var i = 0;
+
+    function continueMap() {
+      var iAtStart = i;
+
+      do {
+        currDoc = dict.get(keys[i]);
+        map(currDoc, emit);
+        i++;
+      } while (i - iAtStart < chunkSize &&
+               i < keys.length)
+
+      if (i == keys.length) {
+        var mapKeys = [];
+        for (name in mapDict)
+          mapKeys.push(name);
+        mapKeys.sort();
+        finished({dict: mapDict, keys: mapKeys});
+      } else
+        progress("map", i / keys.length, continueMap);
+    }
+
+    continueMap();
+  },
+
+  reduce: function STMR_reduce(reduce, mapResult, progress,
+                                chunkSize, finished) {
+    var rows = [];
+    var mapDict = mapResult.dict;
+    var mapKeys = mapResult.keys;
+
+    var i = 0;
+
+    function continueReduce() {
+      var iAtStart = i;
+
+      do {
+        var key = mapKeys[i];
+        var item = mapDict[key];
+
+        // TODO: The map() method is only available on JS 1.6.
+        var keys = item.keys.map(function pairKeyWithDocId(docId) {
+                                   return [key, docId];
+                                 });
+        rows.push({key: key,
+                   value: reduce(keys, item.values)});
+        i++;
+      } while (i - iAtStart < chunkSize &&
+               i < mapKeys.length)
+
+      if (i == mapKeys.length)
+        finished(rows);
+      else
+        progress("reduce", i / mapKeys.length, continueReduce);
+    }
+
+    continueReduce();
+  }
+};
+
 function FakeStorage() {
   var db = {};
 
@@ -273,8 +351,6 @@
     };
 
     this.view = function DB_view(options) {
-      // TODO: Add support for worker threads.
-
       if (!options.map)
         throw new Error('map function not provided');
       if (!options.finished)
@@ -299,23 +375,27 @@
           window.setTimeout(resume, DEFAULT_UI_BREATHE_TIME);
         };
 
-      BrowserCouch._map(
+      var mapReducer = options.mapReducer;
+      if (!mapReducer)
+        mapReducer = SingleThreadedMapReducer;
+
+      mapReducer.map(
         options.map,
         dict,
         progress,
         chunkSize,
-        function(mapDict) {
+        function(mapResult) {
           if (options.reduce)
-            BrowserCouch._reduce(
+            mapReducer.reduce(
               options.reduce,
-              mapDict,
+              mapResult,
               progress,
               chunkSize,
               function(rows) {
                 options.finished(new BrowserCouch._View(rows));
               });
           else
-            options.finished(new BrowserCouch._MapView(mapDict));
+            options.finished(new BrowserCouch._MapView(mapResult));
         });
     };
 
@@ -328,85 +408,6 @@
       });
   },
 
-  _map: function BC__map(map, dict, progress,
-                         chunkSize, finished) {
-    var mapDict = {};
-    var keys = dict.getKeys();
-    var currDoc;
-
-    function emit(key, value) {
-      // TODO: This assumes that the key will always be
-      // an indexable value. We may have to hash the value,
-      // though, if it's e.g. an Object.
-      var item = mapDict[key];
-      if (!item)
-        item = mapDict[key] = {keys: [], values: []};
-      item.keys.push(currDoc.id);
-      item.values.push(value);
-    }
-
-    var i = 0;
-
-    function continueMap() {
-      var iAtStart = i;
-
-      do {
-        currDoc = dict.get(keys[i]);
-        map(currDoc, emit);
-        i++;
-      } while (i - iAtStart < chunkSize &&
-               i < keys.length)
-
-      if (i == keys.length)
-        finished(mapDict);
-      else
-        progress("map", i / keys.length, continueMap);
-    }
-
-    continueMap();
-  },
-
-  _reduce: function BC__reduce(reduce, mapDict, progress,
-                               chunkSize, finished) {
-    var rows = [];
-    var mapKeys = this._makeMapKeys(mapDict);
-
-    var i = 0;
-
-    function continueReduce() {
-      var iAtStart = i;
-
-      do {
-        var key = mapKeys[i];
-        var item = mapDict[key];
-
-        // TODO: The map() method is only available on JS 1.6.
-        var keys = item.keys.map(function pairKeyWithDocId(docId) {
-                                   return [key, docId];
-                                 });
-        rows.push({key: key,
-                   value: reduce(keys, item.values)});
-        i++;
-      } while (i - iAtStart < chunkSize &&
-               i < mapKeys.length)
-
-      if (i == mapKeys.length)
-        finished(rows);
-      else
-        progress("reduce", i / mapKeys.length, continueReduce);
-    }
-
-    continueReduce();
-  },
-
-  _makeMapKeys: function BC__makeMapKeys(mapDict) {
-    var mapKeys = [];
-    for (name in mapDict)
-      mapKeys.push(name);
-    mapKeys.sort();
-    return mapKeys;
-  },
-
   _View: function BC__View(rows) {
     this.rows = rows;
 
@@ -428,12 +429,14 @@
     };
   },
 
-  _MapView: function BC__MapView(mapDict) {
+  _MapView: function BC__MapView(mapResult) {
     var rows = [];
     var keyRows = [];
     this.rows = rows;
 
-    var mapKeys = BrowserCouch._makeMapKeys(mapDict);
+    var mapKeys = mapResult.keys;
+    var mapDict = mapResult.dict;
+
     for (var i = 0; i < mapKeys.length; i++) {
       var key = mapKeys[i];
       var item = mapDict[key];