Implemented more efficient garbage collectior

from worst case of O(n) -> O(1) - where n is the number of insertions in
a list

So this is a huge improvement, I guess :)
This commit is contained in:
Kevin Jahns 2016-01-23 20:09:30 +01:00
parent 38bf398709
commit 39dc2317b7
3 changed files with 63 additions and 8 deletions

View File

@ -208,6 +208,7 @@ g.compareAllUsers = async(function * compareAllUsers (users) {
yield* this.os.iterate(this, null, null, function * (o) {
o = Y.utils.copyObject(o)
delete o.origin
delete o.originOf
db1.push(o)
})
})
@ -222,6 +223,7 @@ g.compareAllUsers = async(function * compareAllUsers (users) {
yield* this.os.iterate(this, null, null, function * (o) {
o = Y.utils.copyObject(o)
delete o.origin
delete o.originOf
expect(db1[count++]).toEqual(o)
})
})

View File

@ -126,6 +126,19 @@ module.exports = function (Y/* :any */) {
execute: function *(op) {
var i // loop counter
var distanceToOrigin = i = yield* Struct.Insert.getDistanceToOrigin.call(this, op) // most cases: 0 (starts from 0)
if (op.origin != null) {
// 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)
if (origin.originOf == null) {
origin.originOf = []
}
origin.originOf.push(op.id)
yield* this.setOperation(origin)
}
// now we begin to insert op in the list of insertions..
var o
var parent
var start

View File

@ -362,23 +362,31 @@ module.exports = function (Y/* :any */) {
if (o.right != null) {
var right = yield* this.getOperation(o.right)
right.left = o.left
if (Y.utils.compareIds(right.origin, o.id)) { // rights origin is o
if (Y.utils.compareIds(right.origin, id)) { // rights origin is o
// find new origin of right ops
// origin is the first left deleted operation
var neworigin = o.left
var neworigin_ = null
while (neworigin != null) {
var neworigin_ = yield* this.getOperation(neworigin)
neworigin_ = yield* this.getOperation(neworigin)
if (neworigin_.deleted) {
break
}
neworigin = neworigin_.left
}
// reset origin of all right ops (except first right - duh!),
/* ** The following code does not rely on the the originOf property **
I recently added originOf to all Insert Operations (see Struct.Insert.execute),
which saves which operations originate in a Insert operation.
Garbage collecting without originOf is more memory efficient, but is nearly impossible for large texts, or lists!
But I keep this code for now
```
// reset origin of right
right.origin = neworigin
// reset origin of all right ops (except first right - duh!),
// until you find origin pointer to the left of o
// search until you find origin pointer to the left of o
if (right.right != null) {
var i = yield* this.getOperation(right.right)
var ids = [o.id, o.right]
@ -399,9 +407,41 @@ module.exports = function (Y/* :any */) {
}
}
}
} /* otherwise, rights origin is to the left of o,
then there is no right op (from o), that origins in o */
yield* this.setOperation(right)
```
*/
// ** Now the new implementation starts **
// reset neworigin of all originOf[*]
for (var _i in o.originOf) {
var originsIn = yield* this.getOperation(o.originOf[_i])
if (originsIn != null) {
originsIn.origin = neworigin
yield* this.setOperation(originsIn)
}
}
if (neworigin != null) {
if (neworigin_.originOf == null) {
neworigin_.originOf = o.originOf
} else {
neworigin_.originOf = o.originOf.concat(neworigin_.originOf)
}
yield* this.setOperation(neworigin_)
}
// we don't need to set right here, because
// right should be in o.originOf => it is set it the previous for loop
} else {
// we didn't need to reset the origin of right
// so we have to set right here
yield* this.setOperation(right)
}
// o may originate in another operation.
// Since o is deleted, we have to reset o.origin's `originOf` property
if (o.origin != null) {
var origin = yield* this.getOperation(o.origin)
origin.originOf = origin.originOf.filter(function (_id) {
return !Y.utils.compareIds(id, _id)
})
yield* this.setOperation(origin)
}
}
if (o.parent != null) {