mirror of
https://github.com/nasa/openmct.git
synced 2025-06-26 19:12:02 +00:00
Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
ab4d73dba6 | |||
92755f040c | |||
551f95363f | |||
7f5ce2e712 | |||
e0c5cb099d |
32
platform/persistence/multi/bundle.json
Normal file
32
platform/persistence/multi/bundle.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"extensions": {
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"type": "decorator",
|
||||||
|
"provides": "persistenceService",
|
||||||
|
"implementation": "MultiPersistenceDecorator.js",
|
||||||
|
"depends": [
|
||||||
|
"persistenceService",
|
||||||
|
"$q",
|
||||||
|
"MULTI_PERSISTENCE_SPACE_MAPPINGS",
|
||||||
|
"MULTI_PERSISTENCE_DEFAULT_SPACE",
|
||||||
|
"PERSISTENCE_SPACE"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"constants": [
|
||||||
|
{
|
||||||
|
"key": "MULTI_PERSISTENCE_SPACE_MAPPINGS",
|
||||||
|
"value": {},
|
||||||
|
"priority": "fallback",
|
||||||
|
"comment": "Maps identifiers to persistence spaces (statically.)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "MULTI_PERSISTENCE_DEFAULT_SPACE",
|
||||||
|
"value": "mct",
|
||||||
|
"priority": "fallback",
|
||||||
|
"comment": "Should be overridden with a reasonable default."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
73
platform/persistence/multi/src/AsyncMutex.js
Normal file
73
platform/persistence/multi/src/AsyncMutex.js
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function AsyncMutex($q) {
|
||||||
|
this.queue = [];
|
||||||
|
this.$q = $q;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncMutex.prototype.acquire = function (callback) {
|
||||||
|
var deferred = this.$q.defer(),
|
||||||
|
queue = this.queue;
|
||||||
|
|
||||||
|
function advance() {
|
||||||
|
if (queue.length > 0) {
|
||||||
|
queue.shift()();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function release(result) {
|
||||||
|
deferred.resolve(result);
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
function next() {
|
||||||
|
try {
|
||||||
|
callback(release);
|
||||||
|
} catch (e) {
|
||||||
|
deferred.reject(e);
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.push(next);
|
||||||
|
if (queue.length === 1) {
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
AsyncMutex.prototype.use = function (callback) {
|
||||||
|
return this.acquire(function (release) {
|
||||||
|
release(callback);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
125
platform/persistence/multi/src/MultiPersistenceDecorator.js
Normal file
125
platform/persistence/multi/src/MultiPersistenceDecorator.js
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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 implements a persistence service which uses ElasticSearch to
|
||||||
|
* store documents.
|
||||||
|
* @namespace platform/persistence/elastic
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
['./PersistenceTable'],
|
||||||
|
function (PersistenceTable) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function MultiPersistenceDecorator(
|
||||||
|
persistenceService,
|
||||||
|
$q,
|
||||||
|
spaceMappings,
|
||||||
|
defaultSpace,
|
||||||
|
spaceToRemap
|
||||||
|
) {
|
||||||
|
this.table = new PersistenceTable(
|
||||||
|
persistenceService,
|
||||||
|
$q,
|
||||||
|
spaceMappings,
|
||||||
|
defaultSpace
|
||||||
|
);
|
||||||
|
this.spaceToRemap = spaceToRemap;
|
||||||
|
this.persistenceService = persistenceService;
|
||||||
|
this.$q = $q;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public API
|
||||||
|
MultiPersistenceDecorator.prototype.listSpaces = function () {
|
||||||
|
var spaceToRemap = this.spaceToRemap,
|
||||||
|
mappedSpaces = this.table.getSpaces();
|
||||||
|
|
||||||
|
return this.persistenceService.listSpaces.then(function (spaces) {
|
||||||
|
// Hide the existence of alternate spaces; make them
|
||||||
|
// appear as the one global space for storing domain objects.
|
||||||
|
return spaces.filter(function (space) {
|
||||||
|
return mappedSpaces.indexOf(space) === -1;
|
||||||
|
}).concat([spaceToRemap]);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
MultiPersistenceDecorator.prototype.listObjects = function (space) {
|
||||||
|
var persistenceService = this.persistenceService;
|
||||||
|
if (space === this.spaceToRemap) {
|
||||||
|
return this.$q.all(this.mappedSpaces.map(function (s) {
|
||||||
|
return persistenceService.listObjects(s);
|
||||||
|
})).then(function (lists) {
|
||||||
|
return lists.reduce(function (a, b) {
|
||||||
|
return a.concat(b);
|
||||||
|
}, []);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return persistenceService.listObjects(space);
|
||||||
|
};
|
||||||
|
|
||||||
|
MultiPersistenceDecorator.prototype.createObject = function (space, key, value) {
|
||||||
|
var persistenceService = this.persistenceService,
|
||||||
|
table = this.table;
|
||||||
|
if (space === this.spaceToRemap) {
|
||||||
|
return table.getSpace(value.location).then(function (s) {
|
||||||
|
return table.setSpace(key, s).then(function () {
|
||||||
|
return persistenceService.createObject(s, key, value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return persistenceService.createObject(space, key, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
MultiPersistenceDecorator.prototype.readObject = function (space, key) {
|
||||||
|
var persistenceService = this.persistenceService;
|
||||||
|
if (space === this.spaceToRemap) {
|
||||||
|
return this.table.getSpace(key).then(function (s) {
|
||||||
|
return persistenceService.readObject(s, key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return persistenceService.readObject(space, key);
|
||||||
|
};
|
||||||
|
|
||||||
|
MultiPersistenceDecorator.prototype.updateObject = function (space, key, value) {
|
||||||
|
var persistenceService = this.persistenceService,
|
||||||
|
table = this.table,
|
||||||
|
self = this;
|
||||||
|
if (space === this.spaceToRemap) {
|
||||||
|
return this.table.getSpace(key).then(function (currentSpace) {
|
||||||
|
return this.table.getSpace(value.location).then(function (newSpace) {
|
||||||
|
// TODO: Also move children when space change happens?
|
||||||
|
return (newSpace === currentSpace) ?
|
||||||
|
persistenceService.updateObject(newSpace, key, value) :
|
||||||
|
self.createObject(space, key, value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return persistenceService.createObject(space, key, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
MultiPersistenceDecorator.prototype.deleteObject = function (space, key, value) {
|
||||||
|
};
|
||||||
|
|
||||||
|
return MultiPersistenceDecorator;
|
||||||
|
}
|
||||||
|
);
|
77
platform/persistence/multi/src/PersistenceTable.js
Normal file
77
platform/persistence/multi/src/PersistenceTable.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['./AsyncMutex', './PersistenceTableInitializer'],
|
||||||
|
function (AsyncMutex, PersistenceTableInitializer) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function PersistenceTable(
|
||||||
|
persistenceService,
|
||||||
|
$q,
|
||||||
|
spaceMappings,
|
||||||
|
defaultSpace
|
||||||
|
) {
|
||||||
|
var spaces = Object.keys(spaceMappings).map(function (id) {
|
||||||
|
return spaceMappings[id];
|
||||||
|
}).sort().filter(function (item, i, arr) {
|
||||||
|
return i === 0 || arr[i - 1] !== item;
|
||||||
|
}),
|
||||||
|
initializer =
|
||||||
|
new PersistenceTableInitializer($q, persistenceService),
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
|
||||||
|
this.mutex = new AsyncMutex($q);
|
||||||
|
this.$q = $q;
|
||||||
|
this.staticSpaceMappings = spaceMappings;
|
||||||
|
this.defaultSpace = defaultSpace;
|
||||||
|
this.spaces = spaces;
|
||||||
|
|
||||||
|
this.mutex.acquire(function (release) {
|
||||||
|
initializer.initialTable(spaces).then(function (table) {
|
||||||
|
self.observedSpaceMappings = table;
|
||||||
|
}).then(release);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistenceTable.prototype.setSpace = function (id, space) {
|
||||||
|
var mappings = this.observedSpaceMappings;
|
||||||
|
return this.mutex.use(function () {
|
||||||
|
this.observedSpaceMappings[id] = space;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
PersistenceTable.prototype.getSpace = function (id) {
|
||||||
|
var self = this;
|
||||||
|
return this.mutex.use(function () {
|
||||||
|
return self.staticSpaceMappings[id] ||
|
||||||
|
self.observedSpaceMappings[id];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
PersistenceTable.prototype.getSpaces = function () {
|
||||||
|
return this.spaces;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
@ -0,0 +1,77 @@
|
|||||||
|
/*global define*/
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function PersistenceTableInitializer($q, persistenceService) {
|
||||||
|
this.$q = $q;
|
||||||
|
this.persistenceService = persistenceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistenceTableInitializer.prototype.initialTable = function (spaces) {
|
||||||
|
var persistenceService = this.persistenceService,
|
||||||
|
$q = this.$q,
|
||||||
|
unreconciledSpaceMappings = {},
|
||||||
|
reconciledSpaceMappings = {};
|
||||||
|
|
||||||
|
function initializeSpace(space) {
|
||||||
|
return persistenceService.listObjects().then(function (ids) {
|
||||||
|
ids.forEach(function (id) {
|
||||||
|
unreconciledSpaceMappings[id] =
|
||||||
|
unreconciledSpaceMappings[id] || [];
|
||||||
|
unreconciledSpaceMappings[id].push(space);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function choose(models) {
|
||||||
|
var index = 0,
|
||||||
|
greatest = Number.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
|
models.forEach(function (model, i) {
|
||||||
|
if (model.persisted !== undefined &&
|
||||||
|
model.persisted > greatest) {
|
||||||
|
greatest = model.persisted;
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reconcileConflict(id) {
|
||||||
|
var candidateSpaces = unreconciledSpaceMappings[id];
|
||||||
|
return $q.all(candidateSpaces.map(function (space) {
|
||||||
|
return persistenceService.readObject(space, id);
|
||||||
|
})).then(choose).then(function (index) {
|
||||||
|
reconciledSpaceMappings[id] = candidateSpaces[index];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function reconcileConflicts() {
|
||||||
|
var toReconcile = [];
|
||||||
|
Object.keys(unreconciledSpaceMappings).forEach(function (id) {
|
||||||
|
if (unreconciledSpaceMappings[id].length > 1) {
|
||||||
|
toReconcile.push(id);
|
||||||
|
} else {
|
||||||
|
reconciledSpaceMappings[id] =
|
||||||
|
unreconciledSpaceMappings[id][0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return $q.all(toReconcile.map(reconcileConflict));
|
||||||
|
}
|
||||||
|
|
||||||
|
function giveResult() {
|
||||||
|
return reconciledSpaceMappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $q.all(spaces.map(initializeSpace))
|
||||||
|
.then(reconcileConflicts)
|
||||||
|
.then(giveResult);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
Reference in New Issue
Block a user