GeoKnow/Jassa-Core

View on GitHub
lib/service/query_execution/QueryExecutionCacheOld.js

Summary

Maintainability
C
1 day
Test Coverage
var Class = require('../../ext/Class');
var QueryExecution = require('./QueryExecution');
var IteratorArray = require('../../util/collection/IteratorArray');
var ResultSetArrayIteratorBinding = require('../result_set/ResultSetArrayIteratorBinding');
var shared = require('../../util/shared');
var Promise = shared.Promise;

/**
 * A query execution that does simple caching based on the query strings.
 *
 *
 */
var QueryExecutionCache = Class.create(QueryExecution, {
    initialize: function(queryExecution, cacheKey, requestCache) {
        this.queryExecution = queryExecution;

        this.cacheKey = cacheKey;
        this.requestCache = requestCache;

    },

    createResultSetFromCacheData: function(cacheData) {
        var itBinding = new IteratorArray(cacheData.bindings);
        var varNames = cacheData.varNames;
        var rs = new ResultSetArrayIteratorBinding(itBinding, varNames);

        return rs;
    },

    setTimeout: function(timeoutInMillis) {
        this.queryExecution.setTimeout(timeoutInMillis);
    },

    execSelect: function() {
        //var self = this;

        var cacheKey = this.cacheKey;

        var requestCache = this.requestCache;
        var resultCache = requestCache.getResultCache();
        var executionCache = requestCache.getExecutionCache();

        // Check the cache whether the same query is already running
        // Re-use its promise if this is the case

        // TODO Reusing promises must take timeouts into account

        // Check if there is an entry in the result cache
        var executionPromise;
        var cacheData = resultCache.getItem(cacheKey);
        if (cacheData) {
            executionPromise = Promise.resolve(cacheData);
        } else {

            // The data is not cached yet, but a request for it might already be running
            var executionCacheEntry = executionCache[cacheKey];

            if (executionCacheEntry == null) {

                var skipInsert = false;

                var cleanupExecutionCache = function() {
                    skipInsert = true;
                    delete executionCache[cacheKey];
                };

                var promise =
                    this.queryExecution.execSelect()
                        .then(function(rs) {
                            cleanupExecutionCache();

                            var cacheData = {
                                bindings: rs.getBindings(),
                                varNames: rs.getVarNames(),
                            };

                            resultCache.setItem(cacheKey, cacheData);

                            return cacheData;
                        }, function(e) {
                            cleanupExecutionCache();

                            throw e;
                        })
                        ;


                /*
                var fetchResultSet = function() {
                    var r = self.queryExecution.execSelect().disposer(function() {
                        skipInsert = true;
                        delete executionCache[cacheKey];
                    });

                    return r;
                };

                var executionPromise =
                    Promise.using(fetchResultSet, function(rs) {
                         var cacheData = {
                             bindings: rs.getBindings(),
                             varNames: rs.getVarNames(),
                         };

                         resultCache.setItem(cacheKey, cacheData);

                         return cacheData;
                     });
                */

                executionCacheEntry = {
                    promise: promise,
                    clients: {},
                    nextId: 0
                };

                if (!skipInsert) {
                    executionCache[cacheKey] = executionCacheEntry;
                }
            }
//            else {
                // Note: Multiple query execution could happen from angular apply loops that execute too often
                // So this could indicate performance issues
                //console.log('[INFO] Joined query execution for: ' + cacheKey);
//            }

            // Now we need to register ourself as a client of the query execution


            // Create a new promise that will cancel the core promise
            // only if there are no more un-cancelled references
            var corePromise = executionCacheEntry.promise;
            var clients = executionCacheEntry.clients;
            var clientId = 'client_' + (executionCacheEntry.nextId++);

            clients[clientId] = true;

            var cleanupClient = function() {
                if(clientId != null) {
                    var isKnown = clients[clientId];

                    if(!isKnown) {
                        console.log('[ASSERTION ERROR] unknown client ' + clientId);
                    }

                    delete clients[clientId];
                }
            };

            executionPromise = new Promise(function(resolve, reject) {
                    corePromise.then(function(cacheData) {
                        cleanupClient();
                        resolve(cacheData);
                        //return cacheData;
                    }, function(e) {
                        cleanupClient();
                        reject(e);
                        //throw e;
                    });
                })
                .cancellable()
                ['catch'](function(e) {
                    cleanupClient();
                    clientId = null;

                    if(Object.keys(clients).length === 0) {
                        corePromise.cancel();
                    }

                    throw e;
                });
        }

        var self = this;
        var result = executionPromise.then(function(cacheData) {
            var rs = self.createResultSetFromCacheData(cacheData);
            //!!! return Promise.resolve(rs);
            return rs;
        });

        return result;
    },

});

module.exports = QueryExecutionCache;