mirror of
https://github.com/nasa/openmct.git
synced 2025-04-14 22:46:44 +00:00
parent
00bf05c929
commit
ffd5faf9a2
2
platform/persistence/cache/README.md
vendored
2
platform/persistence/cache/README.md
vendored
@ -1,2 +0,0 @@
|
||||
This bundle introduces a persistence cache to Open MCT Web to
|
||||
limit the number of persistence requests issued by the platform.
|
49
platform/persistence/cache/bundle.js
vendored
49
platform/persistence/cache/bundle.js
vendored
@ -1,49 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
define([
|
||||
"./src/CachingPersistenceDecorator",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
CachingPersistenceDecorator,
|
||||
legacyRegistry
|
||||
) {
|
||||
"use strict";
|
||||
|
||||
legacyRegistry.register("platform/persistence/cache", {
|
||||
"name": "Persistence cache",
|
||||
"description": "Cache to improve availability of persisted objects.",
|
||||
"extensions": {
|
||||
"components": [
|
||||
{
|
||||
"provides": "persistenceService",
|
||||
"type": "decorator",
|
||||
"implementation": CachingPersistenceDecorator,
|
||||
"depends": [
|
||||
"PERSISTENCE_SPACE"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
@ -1,163 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
/**
|
||||
* This bundle decorates the persistence service to maintain a local cache
|
||||
* of persisted documents.
|
||||
* @namespace platform/persistence/cache
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @memberof platform/persistence/cache
|
||||
* @constructor
|
||||
* @param {string[]} cacheSpaces persistence space names which
|
||||
* should be cached
|
||||
* @param {PersistenceService} persistenceService the service which
|
||||
* implements object persistence, whose inputs/outputs
|
||||
* should be cached.
|
||||
* @implements {PersistenceService}
|
||||
*/
|
||||
function CachingPersistenceDecorator(cacheSpaces, persistenceService) {
|
||||
var spaces = cacheSpaces || [], // List of spaces to cache
|
||||
cache = {}; // Where objects will be stored
|
||||
|
||||
// Arrayify list of spaces to cache, if necessary.
|
||||
spaces = Array.isArray(spaces) ? spaces : [ spaces ];
|
||||
|
||||
// Initialize caches
|
||||
spaces.forEach(function (space) {
|
||||
cache[space] = {};
|
||||
});
|
||||
|
||||
this.spaces = spaces;
|
||||
this.cache = cache;
|
||||
this.persistenceService = persistenceService;
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Update the cached instance of an object to a new value
|
||||
function replaceValue(valueHolder, newValue) {
|
||||
var v = valueHolder.value;
|
||||
|
||||
// If it's a JS object, we want to replace contents, so that
|
||||
// everybody gets the same instance.
|
||||
if (typeof v === 'object' && v !== null) {
|
||||
// Only update contents if these are different instances
|
||||
if (v !== newValue) {
|
||||
// Clear prior contents
|
||||
Object.keys(v).forEach(function (k) {
|
||||
delete v[k];
|
||||
});
|
||||
// Shallow-copy contents
|
||||
Object.keys(newValue).forEach(function (k) {
|
||||
v[k] = newValue[k];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Otherwise, just store the new value
|
||||
valueHolder.value = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Place value in the cache for space, if there is one.
|
||||
CachingPersistenceDecorator.prototype.addToCache = function (space, key, value) {
|
||||
var cache = this.cache;
|
||||
if (cache[space]) {
|
||||
if (cache[space][key]) {
|
||||
replaceValue(cache[space][key], value);
|
||||
} else {
|
||||
cache[space][key] = { value: value };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Create a function for putting value into a cache;
|
||||
// useful for then-chaining.
|
||||
CachingPersistenceDecorator.prototype.putCache = function (space, key) {
|
||||
var self = this;
|
||||
return function (value) {
|
||||
self.addToCache(space, key, value);
|
||||
return value;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
CachingPersistenceDecorator.prototype.listSpaces = function () {
|
||||
return this.persistenceService.listSpaces();
|
||||
};
|
||||
|
||||
CachingPersistenceDecorator.prototype.listObjects = function (space) {
|
||||
return this.persistenceService.listObjects(space);
|
||||
};
|
||||
|
||||
CachingPersistenceDecorator.prototype.createObject = function (space, key, value) {
|
||||
this.addToCache(space, key, value);
|
||||
return this.persistenceService.createObject(space, key, value);
|
||||
};
|
||||
|
||||
CachingPersistenceDecorator.prototype.readObject = function (space, key) {
|
||||
var cache = this.cache;
|
||||
return (cache[space] && cache[space][key]) ?
|
||||
fastPromise(cache[space][key].value) :
|
||||
this.persistenceService.readObject(space, key)
|
||||
.then(this.putCache(space, key));
|
||||
};
|
||||
|
||||
CachingPersistenceDecorator.prototype.updateObject = function (space, key, value) {
|
||||
var self = this;
|
||||
return this.persistenceService.updateObject(space, key, value)
|
||||
.then(function (result) {
|
||||
self.addToCache(space, key, value);
|
||||
return result;
|
||||
});
|
||||
};
|
||||
|
||||
CachingPersistenceDecorator.prototype.deleteObject = function (space, key, value) {
|
||||
if (this.cache[space]) {
|
||||
delete this.cache[space][key];
|
||||
}
|
||||
return this.persistenceService.deleteObject(space, key, value);
|
||||
};
|
||||
|
||||
return CachingPersistenceDecorator;
|
||||
}
|
||||
);
|
@ -1,144 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
define(
|
||||
["../src/CachingPersistenceDecorator"],
|
||||
function (CachingPersistenceDecorator) {
|
||||
"use strict";
|
||||
|
||||
var PERSISTENCE_METHODS = [
|
||||
"listSpaces",
|
||||
"listObjects",
|
||||
"createObject",
|
||||
"readObject",
|
||||
"updateObject",
|
||||
"deleteObject"
|
||||
];
|
||||
|
||||
describe("The caching persistence decorator", function () {
|
||||
var testSpace,
|
||||
mockPersistence,
|
||||
mockCallback,
|
||||
decorator;
|
||||
|
||||
function mockPromise(value) {
|
||||
return {
|
||||
then: function (callback) {
|
||||
return mockPromise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
|
||||
|
||||
testSpace = "TEST";
|
||||
mockPersistence = jasmine.createSpyObj(
|
||||
"persistenceService",
|
||||
PERSISTENCE_METHODS
|
||||
);
|
||||
mockCallback = jasmine.createSpy("callback");
|
||||
|
||||
PERSISTENCE_METHODS.forEach(function (m) {
|
||||
mockPersistence[m].andReturn(mockPromise({
|
||||
method: m
|
||||
}));
|
||||
});
|
||||
|
||||
decorator = new CachingPersistenceDecorator(
|
||||
testSpace,
|
||||
mockPersistence
|
||||
);
|
||||
});
|
||||
|
||||
it("delegates all methods", function () {
|
||||
PERSISTENCE_METHODS.forEach(function (m) {
|
||||
// Reset the callback
|
||||
mockCallback = jasmine.createSpy("callback");
|
||||
// Invoke the method; avoid using a key that will be cached
|
||||
decorator[m](testSpace, "testKey" + m, "testValue")
|
||||
.then(mockCallback);
|
||||
// Should have gotten that method's plain response
|
||||
expect(mockCallback).toHaveBeenCalledWith({ method: m });
|
||||
});
|
||||
});
|
||||
|
||||
it("does not repeat reads of cached objects", function () {
|
||||
// Perform two reads
|
||||
decorator.readObject(testSpace, "someKey", "someValue")
|
||||
.then(mockCallback);
|
||||
decorator.readObject(testSpace, "someKey", "someValue")
|
||||
.then(mockCallback);
|
||||
|
||||
// Should have only delegated once
|
||||
expect(mockPersistence.readObject.calls.length).toEqual(1);
|
||||
|
||||
// But both promises should have resolved
|
||||
expect(mockCallback.calls.length).toEqual(2);
|
||||
|
||||
});
|
||||
|
||||
it("gives a single instance of cached objects", function () {
|
||||
// Perform two reads
|
||||
decorator.readObject(testSpace, "someKey", "someValue")
|
||||
.then(mockCallback);
|
||||
decorator.readObject(testSpace, "someKey", "someValue")
|
||||
.then(mockCallback);
|
||||
|
||||
// Results should have been pointer-identical
|
||||
expect(mockCallback.calls[0].args[0])
|
||||
.toBe(mockCallback.calls[1].args[0]);
|
||||
});
|
||||
|
||||
it("maintains the same cached instance between reads/writes", function () {
|
||||
var testObject = { abc: "XYZ!" };
|
||||
|
||||
// Perform two reads with a write in between
|
||||
decorator.readObject(testSpace, "someKey", "someValue")
|
||||
.then(mockCallback);
|
||||
decorator.updateObject(testSpace, "someKey", testObject);
|
||||
decorator.readObject(testSpace, "someKey", "someValue")
|
||||
.then(mockCallback);
|
||||
|
||||
// Results should have been pointer-identical
|
||||
expect(mockCallback.calls[0].args[0])
|
||||
.toBe(mockCallback.calls[1].args[0]);
|
||||
|
||||
// But contents should have been equal to the written object
|
||||
expect(mockCallback).toHaveBeenCalledWith(testObject);
|
||||
});
|
||||
|
||||
it("is capable of reading/writing strings", function () {
|
||||
// Efforts made to keep cached objects pointer-identical
|
||||
// would break on strings - so make sure cache isn't
|
||||
// breaking when we read/write strings.
|
||||
decorator.createObject(testSpace, "someKey", "someValue");
|
||||
decorator.updateObject(testSpace, "someKey", "someOtherValue");
|
||||
decorator.readObject(testSpace, "someKey").then(mockCallback);
|
||||
expect(mockCallback).toHaveBeenCalledWith("someOtherValue");
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
Loading…
x
Reference in New Issue
Block a user