[Persistence] Add persistence cache
Add a decorator to handle the caching of objects stored to and/or read from persistence (bring over from pre-Angular branch.) Supports the WARP Telemetry Adapter; the absence of such a cache has been observed to result in significant latency in instantiating autoflow tabular views for packets. WTD-644. Also, include an empty test file to ensure that the added decorator is included in code coverage estimation (and to provide a location for tests to be written later.)
This commit is contained in:
@@ -8,6 +8,12 @@
|
|||||||
"type": "provider",
|
"type": "provider",
|
||||||
"implementation": "CouchPersistenceProvider.js",
|
"implementation": "CouchPersistenceProvider.js",
|
||||||
"depends": [ "$http", "$q", "PERSISTENCE_SPACE", "COUCHDB_PATH" ]
|
"depends": [ "$http", "$q", "PERSISTENCE_SPACE", "COUCHDB_PATH" ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"provides": "persistenceService",
|
||||||
|
"type": "decorator",
|
||||||
|
"implementation": "CachingPersistenceDecorator.js",
|
||||||
|
"depends": [ "PERSISTENCE_SPACE" ]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"constants": [
|
"constants": [
|
||||||
|
|||||||
100
platform/persistence/src/CachingPersistenceDecorator.js
Normal file
100
platform/persistence/src/CachingPersistenceDecorator.js
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A caching persistence decorator maintains local copies of persistent objects
|
||||||
|
* that have been loaded, and keeps them in sync after writes. This allows
|
||||||
|
* retrievals to occur more quickly after the first load.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {string[]} CACHE_SPACES persistence space names which
|
||||||
|
* should be cached
|
||||||
|
* @param {PersistenceService} persistenceService the service which
|
||||||
|
* implements object persistence, whose inputs/outputs
|
||||||
|
* should be cached.
|
||||||
|
*/
|
||||||
|
function CachingPersistenceDecorator(CACHE_SPACES, persistenceService) {
|
||||||
|
var spaces = CACHE_SPACES || [], // List of spaces to cache
|
||||||
|
cache = {}; // Where objects will be stored
|
||||||
|
|
||||||
|
// Utility function; avoid sharing one instance everywhere.
|
||||||
|
function clone(value) {
|
||||||
|
// Only clone truthy values (no need to clone undefined, false...)
|
||||||
|
return value && JSON.parse(JSON.stringify(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place value in the cache for space, if there is one.
|
||||||
|
function addToCache(space, key, value) {
|
||||||
|
if (cache[space]) {
|
||||||
|
cache[space][key] = { value: clone(value) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a function for putting value into a cache;
|
||||||
|
// useful for then-chaining.
|
||||||
|
function putCache(space, key) {
|
||||||
|
return function (value) {
|
||||||
|
addToCache(space, key, value);
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap as a thenable; used instead of $q.when because that
|
||||||
|
// will resolve on a future tick, which can cause latency
|
||||||
|
// issues (which this decorator is intended to address.)
|
||||||
|
function fastPromise(value) {
|
||||||
|
return {
|
||||||
|
then: function (callback) {
|
||||||
|
return fastPromise(callback(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arrayify list of spaces to cache, if necessary.
|
||||||
|
spaces = Array.isArray(spaces) ? spaces : [ spaces ];
|
||||||
|
|
||||||
|
// Initialize caches
|
||||||
|
spaces.forEach(function (space) {
|
||||||
|
cache[space] = {};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Provide PersistenceService interface; mostly delegate to the
|
||||||
|
// decorated service, intervene and cache where appropriate.
|
||||||
|
return {
|
||||||
|
listSpaces: function () {
|
||||||
|
return persistenceService.listSpaces();
|
||||||
|
},
|
||||||
|
listObjects: function (space) {
|
||||||
|
return persistenceService.listObjects(space);
|
||||||
|
},
|
||||||
|
createObject: function (space, key, value) {
|
||||||
|
addToCache(space, key, value);
|
||||||
|
return persistenceService.createObject(space, key, value);
|
||||||
|
},
|
||||||
|
readObject: function (space, key) {
|
||||||
|
return (cache[space] && cache[space][key]) ?
|
||||||
|
fastPromise(clone(cache[space][key].value)) :
|
||||||
|
persistenceService.readObject(space, key)
|
||||||
|
.then(putCache(space, key));
|
||||||
|
},
|
||||||
|
updateObject: function (space, key, value) {
|
||||||
|
addToCache(space, key, value);
|
||||||
|
return persistenceService.updateObject(space, key, value);
|
||||||
|
},
|
||||||
|
deleteObject: function (space, key, value) {
|
||||||
|
if (cache[space]) {
|
||||||
|
delete cache[space][key];
|
||||||
|
}
|
||||||
|
return persistenceService.deleteObject(space, key, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return CachingPersistenceDecorator;
|
||||||
|
}
|
||||||
|
);
|
||||||
12
platform/persistence/test/CachingPersistenceDecoratorSpec.js
Normal file
12
platform/persistence/test/CachingPersistenceDecoratorSpec.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
["../src/CachingPersistenceDecorator"],
|
||||||
|
function (CachingPersistenceDecorator) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
|
||||||
|
describe("The caching persistence decorator", function () {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
[
|
[
|
||||||
|
"CachingPersistenceDecorator",
|
||||||
"CouchDocument",
|
"CouchDocument",
|
||||||
"CouchIndicator",
|
"CouchIndicator",
|
||||||
"CouchPersistenceProvider"
|
"CouchPersistenceProvider"
|
||||||
|
|||||||
Reference in New Issue
Block a user