LP#1727557 Offline data stored in separate DB user/berick/lp1727557-offline-block-list-load-speed
authorBill Erickson <berickxx@gmail.com>
Mon, 4 Jun 2018 18:45:11 +0000 (14:45 -0400)
committerBill Erickson <berickxx@gmail.com>
Mon, 4 Jun 2018 18:45:13 +0000 (14:45 -0400)
Store the offline block list and transaction data in a separate
database.  IndexDB database initialization results in reading the tables
on every page, so limiting this data set to just the offline UI means
those (sometimes quite large) data sets don't have to be read by the
browser on every page.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/web/js/ui/default/staff/offline.js
Open-ILS/web/js/ui/default/staff/services/lovefield.js

index c75a140..02d737b 100644 (file)
@@ -849,7 +849,7 @@ function($routeProvider , $locationProvider , $compileProvider) {
                         return egLovefield.reconstituteList('asva');
                     }).then(function() {
                         angular.forEach(egCore.env.asv.list, function (s) {
-                            s.questions( egCore.env.asva.list.filter( function (a) {
+                            s.questions( egCore.env.asvq.list.filter( function (q) {
                                 return q.survey().id == s.id();
                             }));
                         });
index e211744..d063304 100644 (file)
@@ -1,4 +1,5 @@
 var osb = lf.schema.create('offline', 2);
+var osb2; // initialized in offline UI only
 
 // Leaving here as an example.  Note this had no impact
 // on load speed for large offline block lists.
@@ -25,15 +26,26 @@ osb.createTable('StatCat').
     addColumn('value', lf.Type.OBJECT).
     addPrimaryKey(['id']);
 
-osb.createTable('OfflineXact').
-    addColumn('seq', lf.Type.INTEGER).
-    addColumn('value', lf.Type.OBJECT).
-    addPrimaryKey(['seq'], true);
+// Limit the creation of the offline transaction and blocks tables to
+// the offline interface for speed.  Lovefield prevents creation of tables
+// after the database has been initialized, which is why we can't simply
+// add new tables to the exsting database.  This is kind of hacky.
+if (window.location.pathname.match(/\/staff\/offline-interface/)) {
+    console.debug('initializing secondary offline database');
+
+    osb2 = lf.schema.create('offline_data', 2);
+
+    osb2.createTable('OfflineXact').
+        addColumn('seq', lf.Type.INTEGER).
+        addColumn('value', lf.Type.OBJECT).
+        addPrimaryKey(['seq'], true);
+
+    osb2.createTable('OfflineBlocks').
+        addColumn('barcode', lf.Type.STRING).
+        addColumn('reason', lf.Type.STRING).
+        addPrimaryKey(['barcode']);
+}
 
-osb.createTable('OfflineBlocks').
-    addColumn('barcode', lf.Type.STRING).
-    addColumn('reason', lf.Type.STRING).
-    addPrimaryKey(['barcode']);
 
 /**
  * Core Service - egLovefield
@@ -50,7 +62,7 @@ angular.module('egCoreMod')
 
     function connectOrGo() {
 
-        if (lf.offlineDB) { // offline DB connected
+        if (lf.offlineCacheDb) { // offline DB connected
             return $q.when();
         }
 
@@ -68,18 +80,14 @@ angular.module('egCoreMod')
 
         //console.debug('attempting offline DB connection');
         try {
-            osb.connect().then(
-                function(db) {
-                    console.debug('successfully connected to offline DB');
+            service.connectToDatabases().then(
+                function() {
                     service.connectPromise = null;
-                    lf.offlineDB = db;
                     deferred.resolve();
                 },
-                function(err) {
-                    // assumes that a single connection failure means
-                    // a connection will never succeed.
+                function() {
                     service.cannotConnect = true;
-                    console.error('Cannot connect to offline DB: ' + err);
+                    deferred.reject();
                 }
             );
         } catch (e) {
@@ -93,12 +101,45 @@ angular.module('egCoreMod')
         return service.connectPromise;
     }
 
+    service.connectToDatabases = function(db) {
+
+        var promises = [
+
+            osb.connect().then(
+                function(db) {
+                    console.debug('successfully connected to main offline DB');
+                    lf.offlineCacheDb = db;
+                },
+                function(err) {
+                    console.error('Cannot connect to main offline DB: ' + err);
+                }
+            )
+        ];
+
+        if (osb2) {
+            // Connect to the secondary offline database in the offline UI.
+            var p2 = osb2.connect().then(
+                function(db2) {
+                    console.debug('successfully connected to 2ndry offline DB');
+                    lf.offlineDataDB = db2;
+                },
+                function(err) {
+                    console.error('Cannot connect to 2ndry offline DB: ' + err);
+                }
+            )
+
+            promises.push(p2);
+        }
+
+        return $q.all(promises);
+    }
+
     service.isCacheGood = function (type) {
 
         return connectOrGo().then(function() {
-            var cacheDate = lf.offlineDB.getSchema().table('CacheDate');
+            var cacheDate = lf.offlineCacheDb.getSchema().table('CacheDate');
 
-            return lf.offlineDB.
+            return lf.offlineCacheDb.
                 select(cacheDate.cachedate).
                 from(cacheDate).
                 where(cacheDate.type.eq(type)).
@@ -117,8 +158,8 @@ angular.module('egCoreMod')
 
     service.destroyPendingOfflineXacts = function () {
         return connectOrGo().then(function() {
-            var table = lf.offlineDB.getSchema().table('OfflineXact');
-            return lf.offlineDB.
+            var table = lf.offlineDataDB.getSchema().table('OfflineXact');
+            return lf.offlineDataDB.
                 delete().
                 from(table).
                 exec();
@@ -127,8 +168,8 @@ angular.module('egCoreMod')
 
     service.havePendingOfflineXacts = function () {
         return connectOrGo().then(function() {
-            var table = lf.offlineDB.getSchema().table('OfflineXact');
-            return lf.offlineDB.
+            var table = lf.offlineDataDB.getSchema().table('OfflineXact');
+            return lf.offlineDataDB.
                 select(table.reason).
                 from(table).
                 exec().
@@ -140,8 +181,8 @@ angular.module('egCoreMod')
 
     service.retrievePendingOfflineXacts = function () {
         return connectOrGo().then(function() {
-            var table = lf.offlineDB.getSchema().table('OfflineXact');
-            return lf.offlineDB.
+            var table = lf.offlineDataDB.getSchema().table('OfflineXact');
+            return lf.offlineDataDB.
                 select(table.value).
                 from(table).
                 exec().
@@ -153,9 +194,9 @@ angular.module('egCoreMod')
 
     service.destroyOfflineBlocks = function () {
         return connectOrGo().then(function() {
-            var table = lf.offlineDB.getSchema().table('OfflineBlocks');
+            var table = lf.offlineDataDB.getSchema().table('OfflineBlocks');
             return $q.when(
-                lf.offlineDB.
+                lf.offlineDataDB.
                     delete().
                     from(table).
                     exec()
@@ -165,9 +206,9 @@ angular.module('egCoreMod')
 
     service.addOfflineBlock = function (barcode, reason) {
         return connectOrGo().then(function() {
-            var table = lf.offlineDB.getSchema().table('OfflineBlocks');
+            var table = lf.offlineDataDB.getSchema().table('OfflineBlocks');
             return $q.when(
-                lf.offlineDB.
+                lf.offlineDataDB.
                     insertOrReplace().
                     into(table).
                     values([ table.createRow({ barcode : barcode, reason : reason }) ]).
@@ -180,7 +221,7 @@ angular.module('egCoreMod')
         return connectOrGo().then(function() {
 
             var rows = [];
-            var table = lf.offlineDB.getSchema().table('OfflineBlocks');
+            var table = lf.offlineDataDB.getSchema().table('OfflineBlocks');
             console.debug('compiling offline block rows');
 
             lines.forEach(function(line) {
@@ -192,7 +233,7 @@ angular.module('egCoreMod')
             })
 
             console.debug('inserting ' + rows.length + ' offline block rows');
-            return lf.offlineDB.
+            return lf.offlineDataDB.
                 insertOrReplace().
                 into(table).
                 values(rows).
@@ -208,8 +249,8 @@ angular.module('egCoreMod')
     // Returns a promise with true for blocked, false for not blocked
     service.testOfflineBlock = function (barcode) {
         return connectOrGo().then(function() {
-            var table = lf.offlineDB.getSchema().table('OfflineBlocks');
-            return lf.offlineDB.
+            var table = lf.offlineDataDB.getSchema().table('OfflineBlocks');
+            return lf.offlineDataDB.
                 select(table.reason).
                 from(table).
                 where(table.barcode.eq(barcode)).
@@ -222,9 +263,9 @@ angular.module('egCoreMod')
 
     service.addOfflineXact = function (obj) {
         return connectOrGo().then(function() {
-            var table = lf.offlineDB.getSchema().table('OfflineXact');
+            var table = lf.offlineDataDB.getSchema().table('OfflineXact');
             return $q.when(
-                lf.offlineDB.
+                lf.offlineDataDB.
                     insertOrReplace().
                     into(table).
                     values([ table.createRow({ value : obj }) ]).
@@ -237,7 +278,7 @@ angular.module('egCoreMod')
         if (lf.isOffline) return $q.when();
 
         return connectOrGo().then(function() {
-            var table = lf.offlineDB.getSchema().table('StatCat');
+            var table = lf.offlineCacheDb.getSchema().table('StatCat');
             var rlist = [];
 
             angular.forEach(statcats, function (val) {
@@ -246,7 +287,7 @@ angular.module('egCoreMod')
                     value : egCore.idl.toHash(val)
                 }));
             });
-            return lf.offlineDB.
+            return lf.offlineCacheDb.
                 insertOrReplace().
                 into(table).
                 values(rlist).
@@ -257,9 +298,9 @@ angular.module('egCoreMod')
     service.getStatCatsCache = function () {
         return connectOrGo().then(function() {
 
-            var table = lf.offlineDB.getSchema().table('StatCat');
+            var table = lf.offlineCacheDb.getSchema().table('StatCat');
             var result = [];
-            return lf.offlineDB.
+            return lf.offlineCacheDb.
                 select(table.value).
                 from(table).
                 exec().then(function(list) {
@@ -295,7 +336,7 @@ angular.module('egCoreMod')
 
         return connectOrGo().then(function() {
 
-            var table = lf.offlineDB.getSchema().table('Setting');
+            var table = lf.offlineCacheDb.getSchema().table('Setting');
             var rlist = [];
 
             angular.forEach(settings, function (val, key) {
@@ -307,7 +348,7 @@ angular.module('egCoreMod')
                 );
             });
 
-            return lf.offlineDB.
+            return lf.offlineCacheDb.
                 insertOrReplace().
                 into(table).
                 values(rlist).
@@ -318,14 +359,14 @@ angular.module('egCoreMod')
     service.getSettingsCache = function (settings) {
         return connectOrGo().then(function() {
 
-            var table = lf.offlineDB.getSchema().table('Setting');
+            var table = lf.offlineCacheDb.getSchema().table('Setting');
 
             var search_pred = table.name.isNotNull();
             if (settings && settings.length) {
                 search_pred = table.name.in(settings);
             }
                 
-            return lf.offlineDB.
+            return lf.offlineCacheDb.
                 select(table.name, table.value).
                 from(table).
                 where(search_pred).
@@ -345,8 +386,8 @@ angular.module('egCoreMod')
 
             service.isCacheGood(type).then(function(good) {
                 if (!good) {
-                    var object = lf.offlineDB.getSchema().table('Object');
-                    var cacheDate = lf.offlineDB.getSchema().table('CacheDate');
+                    var object = lf.offlineCacheDb.getSchema().table('Object');
+                    var cacheDate = lf.offlineCacheDb.getSchema().table('CacheDate');
                     var pkey = egCore.idl.classes[type].pkey;
         
                     angular.forEach(list, function(item) {
@@ -355,7 +396,7 @@ angular.module('egCoreMod')
                             id      : '' + item[pkey](),
                             object  : egCore.idl.toHash(item)
                         });
-                        lf.offlineDB.insertOrReplace().into(object).values([row]).exec();
+                        lf.offlineCacheDb.insertOrReplace().into(object).values([row]).exec();
                     });
         
                     var row = cacheDate.createRow({
@@ -364,7 +405,7 @@ angular.module('egCoreMod')
                     });
         
                     console.log('egLovefield saving ' + type + ' list');
-                    lf.offlineDB.insertOrReplace().into(cacheDate).values([row]).exec();
+                    lf.offlineCacheDb.insertOrReplace().into(cacheDate).values([row]).exec();
                 }
             })
         });
@@ -373,9 +414,9 @@ angular.module('egCoreMod')
     service.getListFromOfflineCache = function(type) {
         return connectOrGo().then(function() {
 
-            var object = lf.offlineDB.getSchema().table('Object');
+            var object = lf.offlineCacheDb.getSchema().table('Object');
 
-            return lf.offlineDB.
+            return lf.offlineCacheDb.
                 select(object.object).
                 from(object).
                 where(object.type.eq(type)).
@@ -446,7 +487,9 @@ angular.module('egCoreMod')
                     }
                 });
 
-                egCore.env.absorbTree(top, type, true)
+                if (top) {
+                    egCore.env.absorbTree(top, type, true);
+                }
                 return $q.when(true)
             });
         }