126 lines
3.6 KiB
JavaScript
126 lines
3.6 KiB
JavaScript
import Tree from '../Util/Tree.js'
|
|
import ID from '../Util/ID/ID.js'
|
|
|
|
class DSNode {
|
|
constructor (id, len, gc) {
|
|
this._id = id
|
|
this.len = len
|
|
this.gc = gc
|
|
}
|
|
clone () {
|
|
return new DSNode(this._id, this.len, this.gc)
|
|
}
|
|
}
|
|
|
|
export default class DeleteStore extends Tree {
|
|
logTable () {
|
|
const deletes = []
|
|
this.iterate(null, null, function (n) {
|
|
deletes.push({
|
|
user: n._id.user,
|
|
clock: n._id.clock,
|
|
len: n.len,
|
|
gc: n.gc
|
|
})
|
|
})
|
|
console.table(deletes)
|
|
}
|
|
isDeleted (id) {
|
|
var n = this.findWithUpperBound(id)
|
|
return n !== null && n._id.user === id.user && id.clock < n._id.clock + n.len
|
|
}
|
|
/*
|
|
* Mark an operation as deleted. returns the deleted node
|
|
*/
|
|
markDeleted (id, length) {
|
|
if (length == null) {
|
|
throw new Error('length must be defined')
|
|
}
|
|
var n = this.findWithUpperBound(id)
|
|
if (n != null && n._id.user === id.user) {
|
|
if (n._id.clock <= id.clock && id.clock <= n._id.clock + n.len) {
|
|
// id is in n's range
|
|
var diff = id.clock + length - (n._id.clock + n.len) // overlapping right
|
|
if (diff > 0) {
|
|
// id+length overlaps n
|
|
if (!n.gc) {
|
|
n.len += diff
|
|
} else {
|
|
diff = n._id.clock + n.len - id.clock // overlapping left (id till n.end)
|
|
if (diff < length) {
|
|
// a partial deletion
|
|
let nId = id.clone()
|
|
nId.clock += diff
|
|
n = new DSNode(nId, length - diff, false)
|
|
this.put(n)
|
|
} else {
|
|
// already gc'd
|
|
throw new Error(
|
|
'DS reached an inconsistent state. Please report this issue!'
|
|
)
|
|
}
|
|
}
|
|
} else {
|
|
// no overlapping, already deleted
|
|
return n
|
|
}
|
|
} else {
|
|
// cannot extend left (there is no left!)
|
|
n = new DSNode(id, length, false)
|
|
this.put(n) // TODO: you double-put !!
|
|
}
|
|
} else {
|
|
// cannot extend left
|
|
n = new DSNode(id, length, false)
|
|
this.put(n)
|
|
}
|
|
// can extend right?
|
|
var next = this.findNext(n._id)
|
|
if (
|
|
next != null &&
|
|
n._id.user === next._id.user &&
|
|
n._id.clock + n.len >= next._id.clock
|
|
) {
|
|
diff = n._id.clock + n.len - next._id.clock // from next.start to n.end
|
|
while (diff >= 0) {
|
|
// n overlaps with next
|
|
if (next.gc) {
|
|
// gc is stronger, so reduce length of n
|
|
n.len -= diff
|
|
if (diff >= next.len) {
|
|
// delete the missing range after next
|
|
diff = diff - next.len // missing range after next
|
|
if (diff > 0) {
|
|
this.put(n) // unneccessary? TODO!
|
|
this.markDeleted(new ID(next._id.user, next._id.clock + next.len), diff)
|
|
}
|
|
}
|
|
break
|
|
} else {
|
|
// we can extend n with next
|
|
if (diff > next.len) {
|
|
// n is even longer than next
|
|
// get next.next, and try to extend it
|
|
var _next = this.findNext(next._id)
|
|
this.delete(next._id)
|
|
if (_next == null || n._id.user !== _next._id.user) {
|
|
break
|
|
} else {
|
|
next = _next
|
|
diff = n._id.clock + n.len - next._id.clock // from next.start to n.end
|
|
// continue!
|
|
}
|
|
} else {
|
|
// n just partially overlaps with next. extend n, delete next, and break this loop
|
|
n.len += next.len - diff
|
|
this.delete(next._id)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this.put(n)
|
|
return n
|
|
}
|
|
}
|