update
This commit is contained in:
parent
1c32067908
commit
ecc2aef0f8
@ -216,11 +216,15 @@ module.exports = function (Y /* :any */) {
|
|||||||
whenUserIdSet (f) {
|
whenUserIdSet (f) {
|
||||||
this.userIdPromise.then(f)
|
this.userIdPromise.then(f)
|
||||||
}
|
}
|
||||||
getNextOpId () {
|
getNextOpId (numberOfIds) {
|
||||||
if (this.userId == null) {
|
if (numberOfIds == null) {
|
||||||
|
throw new Error('getNextOpId expects the number of created ids to create!')
|
||||||
|
} else if (this.userId == null) {
|
||||||
throw new Error('OperationStore not yet initialized!')
|
throw new Error('OperationStore not yet initialized!')
|
||||||
} else {
|
} else {
|
||||||
return [this.userId, this.opClock++]
|
var id = [this.userId, this.opClock]
|
||||||
|
this.opClock += numberOfIds
|
||||||
|
return id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -294,7 +298,7 @@ module.exports = function (Y /* :any */) {
|
|||||||
for (var sid in ls) {
|
for (var sid in ls) {
|
||||||
var l = ls[sid]
|
var l = ls[sid]
|
||||||
var id = JSON.parse(sid)
|
var id = JSON.parse(sid)
|
||||||
var op = yield* this.getOperation(id)
|
var op = yield* this.getInsertion(id)
|
||||||
if (op == null) {
|
if (op == null) {
|
||||||
store.listenersById[sid] = l
|
store.listenersById[sid] = l
|
||||||
} else {
|
} else {
|
||||||
|
@ -25,7 +25,7 @@ g.g = g
|
|||||||
|
|
||||||
g.YConcurrency_TestingMode = true
|
g.YConcurrency_TestingMode = true
|
||||||
|
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000
|
||||||
|
|
||||||
g.describeManyTimes = function describeManyTimes (times, name, f) {
|
g.describeManyTimes = function describeManyTimes (times, name, f) {
|
||||||
for (var i = 0; i < times; i++) {
|
for (var i = 0; i < times; i++) {
|
||||||
|
@ -93,12 +93,9 @@ module.exports = function (Y/* :any */) {
|
|||||||
return ids
|
return ids
|
||||||
},
|
},
|
||||||
getDistanceToOrigin: function * (op) {
|
getDistanceToOrigin: function * (op) {
|
||||||
if (op.left == null) {
|
|
||||||
return 0
|
|
||||||
} else {
|
|
||||||
var d = 0
|
var d = 0
|
||||||
var o = yield* this.getInsertion(op.left)
|
var o = op
|
||||||
while (!Y.utils.compareIds(op.origin, (o ? o.id : null))) {
|
while (!Y.utils.matchesId(o, op.origin)) {
|
||||||
d++
|
d++
|
||||||
if (o.left == null) {
|
if (o.left == null) {
|
||||||
break
|
break
|
||||||
@ -107,7 +104,6 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return d
|
return d
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/*
|
/*
|
||||||
# $this has to find a unique position between origin and the next known character
|
# $this has to find a unique position between origin and the next known character
|
||||||
@ -162,14 +158,14 @@ module.exports = function (Y/* :any */) {
|
|||||||
if (oOriginDistance === i) {
|
if (oOriginDistance === i) {
|
||||||
// case 1
|
// case 1
|
||||||
if (o.id[0] < op.id[0]) {
|
if (o.id[0] < op.id[0]) {
|
||||||
op.left = o.id
|
op.left = Y.utils.getLastId(o)
|
||||||
distanceToOrigin = i + 1
|
distanceToOrigin = i + 1 // just ignore o.content.length, doesn't make a difference
|
||||||
}
|
}
|
||||||
} else if (oOriginDistance < i) {
|
} else if (oOriginDistance < i) {
|
||||||
// case 2
|
// case 2
|
||||||
if (i - distanceToOrigin <= oOriginDistance) {
|
if (i - distanceToOrigin <= oOriginDistance) {
|
||||||
op.left = o.id
|
op.left = Y.utils.getLastId(o)
|
||||||
distanceToOrigin = i + 1
|
distanceToOrigin = i + 1 // just ignore o.content.length, doesn't make a difference
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
@ -194,7 +190,8 @@ module.exports = function (Y/* :any */) {
|
|||||||
|
|
||||||
// reconnect left and set right of op
|
// reconnect left and set right of op
|
||||||
if (op.left != null) {
|
if (op.left != null) {
|
||||||
left = yield* this.getOperation(op.left)
|
left = yield* this.getInsertion(op.left)
|
||||||
|
// TODO: remove false
|
||||||
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) {
|
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
|
// extend left
|
||||||
left.content = left.content.concat(op.content)
|
left.content = left.content.concat(op.content)
|
||||||
@ -214,7 +211,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
if (op.right != null) {
|
if (op.right != null) {
|
||||||
// TODO: wanna connect right too?
|
// TODO: wanna connect right too?
|
||||||
right = yield* this.getOperation(op.right)
|
right = yield* this.getOperation(op.right)
|
||||||
right.left = op.id
|
right.left = Y.utils.getLastId(op)
|
||||||
|
|
||||||
// if right exists, and it is supposed to be gc'd. Remove it from the gc
|
// if right exists, and it is supposed to be gc'd. Remove it from the gc
|
||||||
if (right.gc != null) {
|
if (right.gc != null) {
|
||||||
@ -257,7 +254,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
end: null,
|
end: null,
|
||||||
struct: "List",
|
struct: "List",
|
||||||
type: "",
|
type: "",
|
||||||
id: this.os.getNextOpId()
|
id: this.os.getNextOpId(1)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
create: function (id) {
|
create: function (id) {
|
||||||
@ -338,7 +335,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
map: {},
|
map: {},
|
||||||
struct: "Map",
|
struct: "Map",
|
||||||
type: "",
|
type: "",
|
||||||
id: this.os.getNextOpId()
|
id: this.os.getNextOpId(1)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
create: function (id) {
|
create: function (id) {
|
||||||
|
@ -101,7 +101,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
* createType (typedefinition, id) {
|
* createType (typedefinition, id) {
|
||||||
var structname = typedefinition[0].struct
|
var structname = typedefinition[0].struct
|
||||||
id = id || this.store.getNextOpId()
|
id = id || this.store.getNextOpId(1)
|
||||||
var op
|
var op
|
||||||
if (id[0] === '_') {
|
if (id[0] === '_') {
|
||||||
op = yield* this.getOperation(id)
|
op = yield* this.getOperation(id)
|
||||||
@ -121,7 +121,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
/* createType (typedefinition, id) {
|
/* createType (typedefinition, id) {
|
||||||
var structname = typedefinition[0].struct
|
var structname = typedefinition[0].struct
|
||||||
id = id || this.store.getNextOpId()
|
id = id || this.store.getNextOpId(1)
|
||||||
var op = Y.Struct[structname].create(id)
|
var op = Y.Struct[structname].create(id)
|
||||||
op.type = typedefinition[0].name
|
op.type = typedefinition[0].name
|
||||||
if (typedefinition[0].appendAdditionalInfo != null) {
|
if (typedefinition[0].appendAdditionalInfo != null) {
|
||||||
@ -224,7 +224,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
var left
|
var left
|
||||||
if (target.left != null) {
|
if (target.left != null) {
|
||||||
left = yield* this.getOperation(target.left)
|
left = yield* this.getInsertion(target.left)
|
||||||
} else {
|
} else {
|
||||||
left = null
|
left = null
|
||||||
}
|
}
|
||||||
@ -417,7 +417,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (op.deleted && op.left != null) {
|
if (op.deleted && op.left != null) {
|
||||||
var left = yield* this.getOperation(op.left)
|
var left = yield* this.getInsertion(op.left)
|
||||||
this.store.addToGarbageCollector(op, left)
|
this.store.addToGarbageCollector(op, left)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -434,7 +434,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
*/
|
*/
|
||||||
* garbageCollectOperation (id) {
|
* garbageCollectOperation (id) {
|
||||||
this.store.addToDebug('yield* this.garbageCollectOperation(', id, ')')
|
this.store.addToDebug('yield* this.garbageCollectOperation(', id, ')')
|
||||||
var o = yield* this.getOperation(id)
|
var o = yield* this.getInsertionCleanStartEnd(id)
|
||||||
yield* this.markGarbageCollected(id, 1) // always mark gc'd
|
yield* this.markGarbageCollected(id, 1) // always mark gc'd
|
||||||
// if op exists, then clean that mess up..
|
// if op exists, then clean that mess up..
|
||||||
if (o != null) {
|
if (o != null) {
|
||||||
@ -470,7 +470,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
|
|
||||||
// remove gc'd op from the left op, if it exists
|
// remove gc'd op from the left op, if it exists
|
||||||
if (o.left != null) {
|
if (o.left != null) {
|
||||||
var left = yield* this.getOperation(o.left)
|
var left = yield* this.getInsertion(o.left)
|
||||||
left.right = o.right
|
left.right = o.right
|
||||||
yield* this.setOperation(left)
|
yield* this.setOperation(left)
|
||||||
}
|
}
|
||||||
@ -486,7 +486,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
var neworigin = o.left
|
var neworigin = o.left
|
||||||
var neworigin_ = null
|
var neworigin_ = null
|
||||||
while (neworigin != null) {
|
while (neworigin != null) {
|
||||||
neworigin_ = yield* this.getOperation(neworigin)
|
neworigin_ = yield* this.getInsertion(neworigin)
|
||||||
if (neworigin_.deleted) {
|
if (neworigin_.deleted) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -554,7 +554,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
// o may originate in another operation.
|
// o may originate in another operation.
|
||||||
// Since o is deleted, we have to reset o.origin's `originOf` property
|
// Since o is deleted, we have to reset o.origin's `originOf` property
|
||||||
if (o.origin != null) {
|
if (o.origin != null) {
|
||||||
var origin = yield* this.getOperation(o.origin)
|
var origin = yield* this.getInsertion(o.origin)
|
||||||
origin.originOf = origin.originOf.filter(function (_id) {
|
origin.originOf = origin.originOf.filter(function (_id) {
|
||||||
return !Y.utils.compareIds(id, _id)
|
return !Y.utils.compareIds(id, _id)
|
||||||
})
|
})
|
||||||
@ -604,7 +604,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
var o = yield* this.getOperation([user, state.clock])
|
var o = yield* this.getOperation([user, state.clock])
|
||||||
while (o != null && o.id[1] === state.clock && user === o.id[0]) {
|
while (o != null && o.id[1] === state.clock && user === o.id[0]) {
|
||||||
// either its a new operation (1. case), or it is an operation that was deleted, but is not yet in the OS
|
// either its a new operation (1. case), or it is an operation that was deleted, but is not yet in the OS
|
||||||
state.clock++
|
state.clock += o.content == null ? 1 : o.content.length
|
||||||
yield* this.checkDeleteStoreForState(state)
|
yield* this.checkDeleteStoreForState(state)
|
||||||
o = yield* this.os.findNext(o.id)
|
o = yield* this.os.findNext(o.id)
|
||||||
}
|
}
|
||||||
@ -762,7 +762,7 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
* getInsertionCleanStartEnd (id) {
|
* getInsertionCleanStartEnd (id) {
|
||||||
yield* this.getInsertionCleanStart(id)
|
yield* this.getInsertionCleanStart(id)
|
||||||
yield* this.getInsertionCleanEnd(id)
|
return yield* this.getInsertionCleanEnd(id)
|
||||||
}
|
}
|
||||||
// Return an insertion such that id is the first element of content
|
// Return an insertion such that id is the first element of content
|
||||||
// This function manipulates an operation, if necessary
|
// This function manipulates an operation, if necessary
|
||||||
@ -775,11 +775,12 @@ module.exports = function (Y/* :any */) {
|
|||||||
var left = Y.utils.copyObject(ins)
|
var left = Y.utils.copyObject(ins)
|
||||||
ins.content = left.content.splice(ins.id[1] - id[1])
|
ins.content = left.content.splice(ins.id[1] - id[1])
|
||||||
ins.id = id
|
ins.id = id
|
||||||
ins.origin = left.id
|
var leftLid = Y.utils.getLastId(left)
|
||||||
|
ins.origin = leftLid
|
||||||
left.originOf = [ins.id]
|
left.originOf = [ins.id]
|
||||||
left.right = ins.id
|
left.right = ins.id
|
||||||
ins.left = left.id
|
ins.left = leftLid
|
||||||
debugger // check
|
// debugger // check
|
||||||
yield* this.setOperation(left)
|
yield* this.setOperation(left)
|
||||||
yield* this.setOperation(ins)
|
yield* this.setOperation(ins)
|
||||||
return ins
|
return ins
|
||||||
@ -799,11 +800,12 @@ module.exports = function (Y/* :any */) {
|
|||||||
var right = Y.utils.copyObject(ins)
|
var right = Y.utils.copyObject(ins)
|
||||||
right.content = ins.content.splice(-(ins.id[1] + ins.content.length - 1 - id[1])) // cut off remainder
|
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.id = [id[0], id[1] + 1]
|
||||||
right.origin = ins.id
|
var insLid = Y.utils.getLastId(ins)
|
||||||
|
right.origin = insLid
|
||||||
ins.originOf = [right.id]
|
ins.originOf = [right.id]
|
||||||
ins.right = right.id
|
ins.right = right.id
|
||||||
right.left = ins.id
|
right.left = insLid
|
||||||
debugger // check
|
// debugger // check
|
||||||
yield* this.setOperation(right)
|
yield* this.setOperation(right)
|
||||||
yield* this.setOperation(ins)
|
yield* this.setOperation(ins)
|
||||||
return ins
|
return ins
|
||||||
@ -961,17 +963,17 @@ module.exports = function (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
o = yield* this.getOperation(o.left)
|
o = yield* this.getInsertion(o.left)
|
||||||
// we set another o, check if we can reduce $missing_origins
|
// we set another o, check if we can reduce $missing_origins
|
||||||
while (missing_origins.length > 0 && Y.utils.compareIds(missing_origins[missing_origins.length - 1].origin, o.id)) {
|
while (missing_origins.length > 0 && Y.utils.compareIds(missing_origins[missing_origins.length - 1].origin, o.id)) {
|
||||||
missing_origins.pop()
|
missing_origins.pop()
|
||||||
}
|
}
|
||||||
if (o.id[1] < (startSS[o.id[0]] || 0)) {
|
if (o.id[1] < (startSS[o.id[0]] || 0)) {
|
||||||
// case 2. o is known
|
// case 2. o is known
|
||||||
op.left = o.id
|
op.left = Y.utils.getLastId(o)
|
||||||
send.push(op)
|
send.push(op)
|
||||||
break
|
break
|
||||||
} else if (Y.utils.compareIds(o.id, op.origin)) {
|
} else if (Y.utils.matchesId(o, op.origin)) {
|
||||||
// case 3. o is op.origin
|
// case 3. o is op.origin
|
||||||
op.left = op.origin
|
op.left = op.origin
|
||||||
send.push(op)
|
send.push(op)
|
||||||
|
47
src/Utils.js
47
src/Utils.js
@ -244,22 +244,37 @@ module.exports = function (Y /* : any*/) {
|
|||||||
|
|
||||||
function compareIds (id1, id2) {
|
function compareIds (id1, id2) {
|
||||||
if (id1 == null || id2 == null) {
|
if (id1 == null || id2 == null) {
|
||||||
if (id1 == null && id2 == null) {
|
return id1 === id2
|
||||||
return true
|
} else {
|
||||||
|
return id1[0] === id2[0] && id1[1] === id2[1]
|
||||||
}
|
}
|
||||||
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
|
Y.utils.compareIds = compareIds
|
||||||
|
|
||||||
|
function matchesId (op, id) {
|
||||||
|
if (id == null || op == null) {
|
||||||
|
return id === op
|
||||||
|
} else {
|
||||||
|
if (id[0] === op.id[0]) {
|
||||||
|
if (op.content == null) {
|
||||||
|
return id[1] === op.id[1]
|
||||||
|
} else {
|
||||||
|
return id[1] >= op.id[1] && id[1] < op.id[1] + op.content.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Y.utils.matchesId = matchesId
|
||||||
|
|
||||||
|
function getLastId (op) {
|
||||||
|
if (op.content == null || op.content.length === 1) {
|
||||||
|
return op.id
|
||||||
|
} else {
|
||||||
|
return [op.id[0], op.id[1] + op.content.length - 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Y.utils.getLastId = getLastId
|
||||||
|
|
||||||
function createEmptyOpsArray (n) {
|
function createEmptyOpsArray (n) {
|
||||||
var a = new Array(n)
|
var a = new Array(n)
|
||||||
for (var i = 0; i < a.length; i++) {
|
for (var i = 0; i < a.length; i++) {
|
||||||
@ -288,7 +303,7 @@ module.exports = function (Y /* : any*/) {
|
|||||||
this.writeBuffer = createEmptyOpsArray(5)
|
this.writeBuffer = createEmptyOpsArray(5)
|
||||||
this.readBuffer = createEmptyOpsArray(10)
|
this.readBuffer = createEmptyOpsArray(10)
|
||||||
}
|
}
|
||||||
* find (id) {
|
* find (id, noSuperCall) {
|
||||||
var i, r
|
var i, r
|
||||||
for (i = this.readBuffer.length - 1; i >= 0; i--) {
|
for (i = this.readBuffer.length - 1; i >= 0; i--) {
|
||||||
r = this.readBuffer[i]
|
r = this.readBuffer[i]
|
||||||
@ -311,7 +326,7 @@ module.exports = function (Y /* : any*/) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i < 0) {
|
if (i < 0 && noSuperCall === undefined) {
|
||||||
// did not reach break in last loop
|
// did not reach break in last loop
|
||||||
// read id and put it to the end of readBuffer
|
// read id and put it to the end of readBuffer
|
||||||
o = yield* super.find(id)
|
o = yield* super.find(id)
|
||||||
@ -378,7 +393,7 @@ module.exports = function (Y /* : any*/) {
|
|||||||
yield* super.delete(id)
|
yield* super.delete(id)
|
||||||
}
|
}
|
||||||
* findWithLowerBound (id) {
|
* findWithLowerBound (id) {
|
||||||
var o = yield* this.find(id)
|
var o = yield* this.find(id, true)
|
||||||
if (o != null) {
|
if (o != null) {
|
||||||
return o
|
return o
|
||||||
} else {
|
} else {
|
||||||
@ -387,7 +402,7 @@ module.exports = function (Y /* : any*/) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
* findWithUpperBound (id) {
|
* findWithUpperBound (id) {
|
||||||
var o = yield* this.find(id)
|
var o = yield* this.find(id, true)
|
||||||
if (o != null) {
|
if (o != null) {
|
||||||
return o
|
return o
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user