mirror of
https://github.com/nasa/openmct.git
synced 2025-06-25 10:44:21 +00:00
Compare commits
5 Commits
git-error-
...
open245
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