From 1c32067908383c0cda048374787958e581f7aff7 Mon Sep 17 00:00:00 2001 From: Kevin Jahns Date: Tue, 5 Apr 2016 10:43:57 +0100 Subject: [PATCH] implementing new insertion struct (unfinished) --- src/SpecHelper.js | 2 +- src/Struct.js | 32 +++++++++++++------- src/Transaction.js | 75 ++++++++++++++++++++++++++++++++++++++++++---- src/Utils.js | 33 +++++++++++++------- 4 files changed, 114 insertions(+), 28 deletions(-) diff --git a/src/SpecHelper.js b/src/SpecHelper.js index 079c7627..e2afb847 100644 --- a/src/SpecHelper.js +++ b/src/SpecHelper.js @@ -25,7 +25,7 @@ g.g = g g.YConcurrency_TestingMode = true -jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000 +jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000 g.describeManyTimes = function describeManyTimes (times, name, f) { for (var i = 0; i < times; i++) { diff --git a/src/Struct.js b/src/Struct.js index db880cf6..32a1d30c 100644 --- a/src/Struct.js +++ b/src/Struct.js @@ -41,7 +41,8 @@ module.exports = function (Y/* :any */) { }, Insert: { /* { - content: any, + content: [any], + opContent: Id, id: Id, left: Id, origin: Id, @@ -96,13 +97,13 @@ module.exports = function (Y/* :any */) { return 0 } else { var d = 0 - var o = yield* this.getOperation(op.left) + var o = yield* this.getInsertion(op.left) while (!Y.utils.compareIds(op.origin, (o ? o.id : null))) { d++ if (o.left == null) { break } else { - o = yield* this.getOperation(o.left) + o = yield* this.getInsertion(o.left) } } return d @@ -130,7 +131,7 @@ module.exports = function (Y/* :any */) { 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) - var origin = yield* this.getOperation(op.origin) + var origin = yield* this.getInsertionCleanEnd(op.origin) if (origin.originOf == null) { origin.originOf = [] } @@ -145,8 +146,8 @@ module.exports = function (Y/* :any */) { // find o. o is the first conflicting operation if (op.left != null) { - o = yield* this.getOperation(op.left) - o = (o.right == null) ? null : yield* this.getOperation(o.right) + o = yield* this.getInsertionCleanEnd(op.left) + o = (o.right == null) ? null : yield* this.getInsertionCleanStart(o.right) } else { // left == null parent = yield* this.getOperation(op.parent) let startId = op.parentSub ? parent.map[op.parentSub] : parent.start @@ -175,7 +176,7 @@ module.exports = function (Y/* :any */) { } i++ if (o.right != null) { - o = yield* this.getOperation(o.right) + o = yield* this.getInsertionCleanStart(o.right) } else { o = null } @@ -194,15 +195,24 @@ module.exports = function (Y/* :any */) { // reconnect left and set right of op if (op.left != null) { left = yield* this.getOperation(op.left) - op.right = left.right - left.right = op.id + if (false && op.content != null && left.content != null && left.id[0] === op.id[0] && left.id[1] + left.content.length === op.id[1] && left.originOf == null && left.deleted !== true && left.gc !== true) { + // extend left + left.content = left.content.concat(op.content) + op = left + } else { + // link left + op.right = left.right + left.right = op.id - yield* this.setOperation(left) + yield* this.setOperation(left) + } } else { + // set op.right from parent, if necessary op.right = op.parentSub ? parent.map[op.parentSub] || null : parent.start } // reconnect right if (op.right != null) { + // TODO: wanna connect right too? right = yield* this.getOperation(op.right) right.left = op.id @@ -367,7 +377,7 @@ module.exports = function (Y/* :any */) { if (res == null || res.deleted) { return void 0 } else if (res.opContent == null) { - return res.content + return res.content[0] } else { return yield* this.getType(res.opContent) } diff --git a/src/Transaction.js b/src/Transaction.js index 3ac10c24..b0a54eb8 100644 --- a/src/Transaction.js +++ b/src/Transaction.js @@ -176,7 +176,7 @@ module.exports = function (Y/* :any */) { Mark an operation as deleted, and add it to the GC, if possible. */ * deleteOperation (targetId, preventCallType) /* :Generator */ { - var target = yield* this.getOperation(targetId) + var target = yield* this.getInsertionCleanStartEnd(targetId) var callType = false if (target == null || !target.deleted) { @@ -751,11 +751,75 @@ module.exports = function (Y/* :any */) { this.store.y.connector.broadcastOps([op]) } } - * getOperation (id/* :any */)/* :Transaction */ { - var o = yield* this.os.find(id) - if (o != null || id[0] !== '_') { - return o + * getInsertion (id) { + var ins = yield* this.os.findWithUpperBound(id) + var len = ins.content != null ? ins.content.length : 1 // in case of opContent + if (ins != null && id[0] === ins.id[0] && id[1] < ins.id[1] + len) { + return ins } else { + return null + } + } + * getInsertionCleanStartEnd (id) { + yield* this.getInsertionCleanStart(id) + yield* this.getInsertionCleanEnd(id) + } + // Return an insertion such that id is the first element of content + // This function manipulates an operation, if necessary + * getInsertionCleanStart (id) { + var ins = yield* this.getInsertion(id) + if (ins != null) { + if (ins.id[1] === id[1]) { + return ins + } else { + var left = Y.utils.copyObject(ins) + ins.content = left.content.splice(ins.id[1] - id[1]) + ins.id = id + ins.origin = left.id + left.originOf = [ins.id] + left.right = ins.id + ins.left = left.id + debugger // check + yield* this.setOperation(left) + yield* this.setOperation(ins) + return ins + } + } else { + return null + } + } + // Return an insertion such that id is the last element of content + // This function manipulates an operation, if necessary + * getInsertionCleanEnd (id) { + var ins = yield* this.getInsertion(id) + if (ins != null) { + if (ins.content == null || (ins.id[1] + ins.content.length - 1 === id[1])) { + return ins + } else { + var right = Y.utils.copyObject(ins) + right.content = ins.content.splice(-(ins.id[1] + ins.content.length - 1 - id[1])) // cut off remainder + right.id = [id[0], id[1] + 1] + right.origin = ins.id + ins.originOf = [right.id] + ins.right = right.id + right.left = ins.id + debugger // check + yield* this.setOperation(right) + yield* this.setOperation(ins) + return ins + } + } else { + return null + } + } + * getOperation (id/* :any */)/* :Transaction */ { + if (id.length > 2) { + id = [id[0], id[1]] + } + var o = yield* this.os.find(id) + if (id[0] !== '_' || o != null) { + return o + } else { // type is string // generate this operation? var comp = id[1].split('_') if (comp.length > 1) { @@ -770,7 +834,6 @@ module.exports = function (Y/* :any */) { debugger // eslint-disable-line return null } - return null } } * removeOperation (id) { diff --git a/src/Utils.js b/src/Utils.js index a45469dd..2f87c4de 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -249,11 +249,14 @@ module.exports = function (Y /* : any*/) { } return false } - if (id1[0] === id2[0] && id1[1] === id2[1]) { - return true - } else { - return false + if (id1[0] === id2[0]) { + var add1 = id1.length > 2 ? id1[2] : 0 + var add2 = id2.length > 2 ? id2[2] : 0 + if (id1[1] + add1 === id2[1] + add2) { + return true + } } + return false } Y.utils.compareIds = compareIds @@ -374,13 +377,23 @@ module.exports = function (Y /* : any*/) { yield* this.flush() yield* super.delete(id) } - * findWithLowerBound () { - yield* this.flush() - return yield* super.findWithLowerBound.apply(this, arguments) + * findWithLowerBound (id) { + var o = yield* this.find(id) + if (o != null) { + return o + } else { + yield* this.flush() + return yield* super.findWithLowerBound.apply(this, arguments) + } } - * findWithUpperBound () { - yield* this.flush() - return yield* super.findWithUpperBound.apply(this, arguments) + * findWithUpperBound (id) { + var o = yield* this.find(id) + if (o != null) { + return o + } else { + yield* this.flush() + return yield* super.findWithUpperBound.apply(this, arguments) + } } * findNext () { yield* this.flush()