UNPKG

mute-structs

Version:

NodeJS module providing an implementation of the LogootSplit CRDT algorithm

222 lines (218 loc) 10.5 kB
/* This file is part of MUTE-structs. Copyright (C) 2017 Matthieu Nicolas, Victorien Elvinger This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; import { isObject } from "./data-validation"; import { Epoch } from "./epoch/epoch"; import { EpochId } from "./epoch/epochid"; import { compareEpochFullIds, EpochStore } from "./epoch/epochstore"; import { IdentifierInterval } from "./identifierinterval"; import { createAtPosition } from "./idfactory"; import { LogootSRopes } from "./logootsropes"; import { LogootSDel } from "./operations/delete/logootsdel"; import { RenamableLogootSDel } from "./operations/delete/renamablelogootsdel"; import { LogootSAdd } from "./operations/insert/logootsadd"; import { RenamableLogootSAdd } from "./operations/insert/renamablelogootsadd"; import { LogootSRename } from "./operations/rename/logootsrename"; import { RenamingMap } from "./renamingmap/renamingmap"; import { RenamingMapStore } from "./renamingmap/renamingmapstore"; import { mkNodeAt } from "./ropesnodes"; function generateInsertOps(idIntervals, str) { var currentOffset = 0; return idIntervals .map(function (idInterval) { var nextOffset = currentOffset + idInterval.length; var content = str.slice(currentOffset, nextOffset); currentOffset = nextOffset; return new LogootSAdd(idInterval.idBegin, content); }); } var RenamableReplicableList = /** @class */ (function () { function RenamableReplicableList(list, currentEpoch, epochsStore, renamingMapStore) { this.list = list; this.currentEpoch = currentEpoch; this.epochsStore = epochsStore; this.renamingMapStore = renamingMapStore; } RenamableReplicableList.create = function (replicaNumber, clock) { if (replicaNumber === void 0) { replicaNumber = 0; } if (clock === void 0) { clock = 0; } var list = new LogootSRopes(replicaNumber, clock); var currentEpoch = new Epoch(new EpochId(0, 0)); var epochsStore = new EpochStore(currentEpoch); var renamingMapStore = new RenamingMapStore(); return new RenamableReplicableList(list, currentEpoch, epochsStore, renamingMapStore); }; RenamableReplicableList.fromPlain = function (o) { if (isObject(o)) { var list = LogootSRopes.fromPlain(o.list); var epochsStore = EpochStore.fromPlain(o.epochsStore); var renamingMapStore = RenamingMapStore.fromPlain(o.renamingMapStore); var currentEpoch = Epoch.fromPlain(o.currentEpoch); if (list !== null && epochsStore !== null && renamingMapStore !== null && currentEpoch !== null) { return new RenamableReplicableList(list, currentEpoch, epochsStore, renamingMapStore); } } return null; }; RenamableReplicableList.fromPlainLogootSRopes = function (o) { var list = LogootSRopes.fromPlain(o); if (list !== null) { var currentEpoch = new Epoch(new EpochId(0, 0)); var epochsStore = new EpochStore(currentEpoch); var renamingMapStore = new RenamingMapStore(); return new RenamableReplicableList(list, currentEpoch, epochsStore, renamingMapStore); } return null; }; Object.defineProperty(RenamableReplicableList.prototype, "replicaNumber", { get: function () { return this.list.replicaNumber; }, enumerable: true, configurable: true }); Object.defineProperty(RenamableReplicableList.prototype, "clock", { get: function () { return this.list.clock; }, enumerable: true, configurable: true }); Object.defineProperty(RenamableReplicableList.prototype, "currentRenamingMap", { get: function () { return this.renamingMapStore.getRenamingMap(this.currentEpoch.id); }, enumerable: true, configurable: true }); RenamableReplicableList.prototype.getList = function () { return this.list; }; RenamableReplicableList.prototype.getCurrentEpoch = function () { return this.currentEpoch; }; Object.defineProperty(RenamableReplicableList.prototype, "str", { get: function () { return this.list.str; }, enumerable: true, configurable: true }); RenamableReplicableList.prototype.insertLocal = function (pos, l) { return new RenamableLogootSAdd(this.list.insertLocal(pos, l), this.currentEpoch); }; RenamableReplicableList.prototype.insertRemote = function (epoch, op) { var _this = this; if (!epoch.equals(this.currentEpoch)) { var strat = function (rmap, ids) { return rmap.initRenameIds(ids); }; var newIds = this.renameFromEpochToCurrent(op.insertedIds, epoch, strat); var newIdIntervals = IdentifierInterval.mergeIdsIntoIntervals(newIds); var insertOps = generateInsertOps(newIdIntervals, op.content); return insertOps .flatMap(function (insertOp) { return insertOp.execute(_this.list); }); } return op.execute(this.list); }; RenamableReplicableList.prototype.delLocal = function (begin, end) { return new RenamableLogootSDel(this.list.delLocal(begin, end), this.currentEpoch); }; RenamableReplicableList.prototype.delRemote = function (epoch, op) { if (!epoch.equals(this.currentEpoch)) { var idsToRename = op.lid .flatMap(function (idInterval) { return idInterval.toIds(); }); var strat = function (rmap, ids) { return rmap.initRenameIds(ids); }; var newIds = this.renameFromEpochToCurrent(idsToRename, epoch, strat); var newIdIntervals = IdentifierInterval.mergeIdsIntoIntervals(newIds); var newOp = new LogootSDel(newIdIntervals, op.author); return newOp.execute(this.list); } return op.execute(this.list); }; RenamableReplicableList.prototype.renameLocal = function () { var renamedIdIntervals = this.list.toList(); var clock = this.clock; var newEpochNumber = this.currentEpoch.id.epochNumber + 1; var newEpochId = new EpochId(this.replicaNumber, newEpochNumber); this.currentEpoch = new Epoch(newEpochId, this.currentEpoch.id); this.epochsStore.addEpoch(this.currentEpoch); var newRandom = renamedIdIntervals[0].idBegin.tuples[0].random; var renamingMap = new RenamingMap(this.replicaNumber, clock, renamedIdIntervals); this.renamingMapStore.add(this.currentEpoch, renamingMap); var baseId = createAtPosition(this.replicaNumber, clock, newRandom, 0); var newRoot = mkNodeAt(baseId, this.str.length); this.list = new LogootSRopes(this.replicaNumber, clock + 1, newRoot, this.str); return new LogootSRename(this.replicaNumber, clock, this.currentEpoch, renamedIdIntervals); }; RenamableReplicableList.prototype.renameRemote = function (replicaNumber, clock, newEpoch, renamedIdIntervals) { var renamingMap = new RenamingMap(replicaNumber, clock, renamedIdIntervals); this.epochsStore.addEpoch(newEpoch); this.renamingMapStore.add(newEpoch, renamingMap); var newEpochFullId = this.epochsStore.getEpochFullId(newEpoch); var currentEpochFullId = this.epochsStore.getEpochFullId(this.currentEpoch); if (compareEpochFullIds(currentEpochFullId, newEpochFullId) === -1 /* Less */) { var previousEpoch = this.currentEpoch; this.currentEpoch = newEpoch; var idsToRename = this.list.toList().flatMap(function (idInterval) { return idInterval.toIds(); }); var strat = function (rmap, ids) { return rmap.initRenameSeq(ids); }; var newIds = this.renameFromEpochToCurrent(idsToRename, previousEpoch, strat); var newIdIntervals = IdentifierInterval.mergeIdsIntoIntervals(newIds); var newList_1 = new LogootSRopes(this.replicaNumber, this.clock); var insertOps = generateInsertOps(newIdIntervals, this.str); insertOps.forEach(function (insertOp) { insertOp.execute(newList_1); }); this.list = newList_1; } }; RenamableReplicableList.prototype.renameFromEpochToCurrent = function (idsToRename, fromEpoch, strat) { var _this = this; var _a = __read(this.epochsStore.getPathBetweenEpochs(fromEpoch, this.currentEpoch), 2), epochsToRevert = _a[0], epochsToApply = _a[1]; var ids = idsToRename; epochsToRevert.forEach(function (epoch) { var rmap = _this.renamingMapStore.getRenamingMap(epoch.id); ids = ids.map(function (id) { return rmap.reverseRenameId(id); }); }); epochsToApply.forEach(function (epoch) { var rmap = _this.renamingMapStore.getRenamingMap(epoch.id); ids = strat(rmap, ids); }); return ids; }; RenamableReplicableList.prototype.getNbBlocks = function () { return this.list.toList().length; }; RenamableReplicableList.prototype.digest = function () { return this.list.digest(); }; return RenamableReplicableList; }()); export { RenamableReplicableList }; //# sourceMappingURL=renamablereplicablelist.js.map