From bffd130b92b60e7b6f744fa6e0635d74f660d08d Mon Sep 17 00:00:00 2001 From: Kevin Jahns <kevin.jahns@rwth-aachen.de> Date: Thu, 21 Apr 2016 18:04:46 +0200 Subject: [PATCH] fixed first two random cases, (gc seems still to be an issue ..) --- src/Database.js | 25 +------------ src/Struct.js | 35 +++++++++++++++---- src/Transaction.js | 87 +++++++++++++++++++++++++++++++--------------- 3 files changed, 89 insertions(+), 58 deletions(-) diff --git a/src/Database.js b/src/Database.js index d8a37ea8..964b7efa 100644 --- a/src/Database.js +++ b/src/Database.js @@ -367,30 +367,7 @@ module.exports = function (Y /* :any */) { yield* this.store.operationAdded(this, op) // if insertion, try to combine with left - if (op.left != null && - op.content != null && - op.left[0] === op.id[0] && - Y.utils.compareIds(op.left, op.origin) - ) { - var left = yield* this.getInsertion(op.left) - if (left.content != null && - left.id[1] + left.content.length === op.id[1] && - left.originOf.length === 1 && - !left.gc && !left.deleted && - !op.gc && !op.deleted - ) { - // combine! - if (op.originOf != null){ - left.originOf = op.originOf - } else { - delete left.originOf - } - left.content = left.content.concat(op.content) - left.right = op.right - yield* this.os.delete(op.id) - yield* this.setOperation(left) - } - } + yield* this.tryCombineWithLeft(op) } } } diff --git a/src/Struct.js b/src/Struct.js index 21a53c88..82bed80a 100644 --- a/src/Struct.js +++ b/src/Struct.js @@ -124,10 +124,13 @@ module.exports = function (Y/* :any */) { # case 3: $origin > $o.origin # $this insert_position is to the left of $o (forever!) */ - execute: function *(op) { + execute: function * (op) { var i // loop counter - var distanceToOrigin = i = yield* Struct.Insert.getDistanceToOrigin.call(this, op) // most cases: 0 (starts from 0) - + + // during this function some ops may get split into two pieces (e.g. with getInsertionCleanEnd) + // We try to merge them later, if possible + var tryToRemergeLater = [] + if (op.origin != null) { // TODO: !== instead of != // we save in origin that op originates in it // we need that later when we eventually garbage collect origin (see transaction) @@ -137,7 +140,11 @@ module.exports = function (Y/* :any */) { } origin.originOf.push(op.id) yield* this.setOperation(origin) + if (origin.right != null) { + tryToRemergeLater.push(origin.right) + } } + var distanceToOrigin = i = yield* Struct.Insert.getDistanceToOrigin.call(this, op) // most cases: 0 (starts from 0) // now we begin to insert op in the list of insertions.. var o @@ -147,14 +154,24 @@ module.exports = function (Y/* :any */) { // find o. o is the first conflicting operation if (op.left != null) { o = yield* this.getInsertionCleanEnd(op.left) - o = (o.right == null) ? null : yield* this.getInsertionCleanStart(o.right) + if (!Y.utils.compareIds(op.left, op.origin) && o.right != null) { + // only if not added previously + tryToRemergeLater.push(o.right) + } + o = (o.right == null) ? null : yield* this.getOperation(o.right) } else { // left == null parent = yield* this.getOperation(op.parent) let startId = op.parentSub ? parent.map[op.parentSub] : parent.start start = startId == null ? null : yield* this.getOperation(startId) o = start } - + + // make sure to split op.right if necessary (also add to tryCombineWithLeft) + if (op.right != null) { + tryToRemergeLater.push(op.right) + yield* this.getInsertionCleanStart(op.right) + } + // handle conflicts while (true) { if (o != null && !Y.utils.compareIds(o.id, op.right)) { @@ -176,7 +193,7 @@ module.exports = function (Y/* :any */) { } i++ if (o.right != null) { - o = yield* this.getInsertionCleanStart(o.right) + o = yield* this.getInsertion(o.right) } else { o = null } @@ -249,6 +266,12 @@ module.exports = function (Y/* :any */) { yield* this.setOperation(parent) } } + + // try to merge original op.left and op.origin + for (var i = 0; i < tryToRemergeLater.length; i++) { + var m = yield* this.getOperation(tryToRemergeLater[i]) + yield* this.tryCombineWithLeft(m) + } } }, List: { diff --git a/src/Transaction.js b/src/Transaction.js index e178c710..37ce364e 100644 --- a/src/Transaction.js +++ b/src/Transaction.js @@ -421,38 +421,37 @@ module.exports = function (Y/* :any */) { */ * garbageCollectAfterSync () { yield* this.os.iterate(this, null, null, function * (op) { - var opLength = op.content != null ? op.content.length : 1 if (op.gc) { - this.store.gc1.push(op.id) - } else { - if (op.parent != null) { - var parentDeleted = yield* this.isDeleted(op.parent) - if (parentDeleted) { - op.gc = true - if (!op.deleted) { - yield* this.markDeleted(op.id, opLength) - op.deleted = true - if (op.opContent != null) { - yield* this.deleteOperation(op.opContent) - } - if (op.requires != null) { - for (var i = 0; i < op.requires.length; i++) { - yield* this.deleteOperation(op.requires[i]) - } + delete op.gc + yield* this.setOperation(op) + } + if (op.parent != null) { + var parentDeleted = yield* this.isDeleted(op.parent) + if (parentDeleted) { + op.gc = true + if (!op.deleted) { + yield* this.markDeleted(op.id, op.content != null ? op.content.length : 1) + op.deleted = true + if (op.opContent != null) { + yield* this.deleteOperation(op.opContent) + } + if (op.requires != null) { + for (var i = 0; i < op.requires.length; i++) { + yield* this.deleteOperation(op.requires[i]) } } - yield* this.setOperation(op) - this.store.gc1.push(op.id) - return } + yield* this.setOperation(op) + this.store.gc1.push(op.id) + return } - if (op.deleted) { - var left = null - if (op.left != null) { - left = yield* this.getInsertion(op.left) - } - yield* this.store.addToGarbageCollector.call(this, op, left) + } + if (op.deleted) { + var left = null + if (op.left != null) { + left = yield* this.getInsertion(op.left) } + yield* this.store.addToGarbageCollector.call(this, op, left) } }) } @@ -715,8 +714,11 @@ module.exports = function (Y/* :any */) { var counter = del[1] + del[2] while (counter >= del[1]) { var o = yield* this.os.findWithUpperBound([del[0], counter - 1]) + if (o == null) { + break + } var oLen = o.content != null ? o.content.length : 1 - if (o.id[0] !== del[0] || del[1] < o.id[1] + oLen) { + if (o.id[0] !== del[0] || o.id[1] + oLen <= del[1]) { // not in range break } @@ -728,8 +730,8 @@ module.exports = function (Y/* :any */) { // overlaps left o = yield* this.getInsertionCleanStart([del[0], del[1]]) } - yield* this.garbageCollectOperation(o.id) counter = o.id[1] + yield* this.garbageCollectOperation(o.id) } } } else { @@ -796,6 +798,35 @@ module.exports = function (Y/* :any */) { this.store.y.connector.broadcastOps([op]) } } + // if insertion, try to combine with left insertion (if both have content property) + * tryCombineWithLeft (op) { + if ( + op != null && + op.left != null && + op.content != null && + op.left[0] === op.id[0] && + Y.utils.compareIds(op.left, op.origin) + ) { + var left = yield* this.getInsertion(op.left) + if (left.content != null && + left.id[1] + left.content.length === op.id[1] && + left.originOf.length === 1 && + !left.gc && !left.deleted && + !op.gc && !op.deleted + ) { + // combine! + if (op.originOf != null){ + left.originOf = op.originOf + } else { + delete left.originOf + } + left.content = left.content.concat(op.content) + left.right = op.right + yield* this.os.delete(op.id) + yield* this.setOperation(left) + } + } + } * getInsertion (id) { var ins = yield* this.os.findWithUpperBound(id) if (ins == null) { -- GitLab