gc implementation

This commit is contained in:
Kevin Jahns 2015-07-26 16:03:13 +00:00
parent c8ded24842
commit 06e7caab2d
6 changed files with 58 additions and 22 deletions

View File

@ -61,6 +61,13 @@ async function applyRandomTransactions (users, objects, transactions, numberOfTr
await users[0].connector.flushAll()
}
async function garbageCollectAllUsers (users) {
for (var i in users) {
await users[i].db.garbageCollect()
await users[i].db.garbageCollect()
}
}
async function compareAllUsers(users){//eslint-disable-line
var s1, s2, ds1, ds2, allDels1, allDels2
var db1 = []
@ -81,6 +88,8 @@ async function compareAllUsers(users){//eslint-disable-line
})
}
await users[0].connector.flushAll()
await garbageCollectAllUsers(users)
await wait(200)
for (var uid = 0; uid < users.length; uid++) {
var u = users[uid]
// compare deleted ops against deleteStore
@ -99,9 +108,8 @@ async function compareAllUsers(users){//eslint-disable-line
var d = ds[j]
for (var i = 0; i < d.len; i++) {
var o = yield* this.getOperation([d.id[0], d.id[1] + i])
if (o != null) {
expect(o.deleted).toBeTruthy()
}
// gc'd or deleted
expect(o == null || o.deleted).toBeTruthy()
}
}
})

View File

@ -68,6 +68,7 @@ class AbstractOperationStore { // eslint-disable-line no-unused-vars
this.gcTimeout = opts.gcTimeout || 5000
var os = this
function garbageCollect () {
var def = Promise.defer()
os.requestTransaction(function * () {
for (var i in os.gc2) {
var oid = os.gc2[i]
@ -87,7 +88,9 @@ class AbstractOperationStore { // eslint-disable-line no-unused-vars
if (os.gcTimeout > 0) {
os.gcInterval = setTimeout(garbageCollect, os.gcTimeout)
}
def.resolve()
})
return def.promise
}
this.garbageCollect = garbageCollect
if (this.gcTimeout > 0) {
@ -125,8 +128,12 @@ class AbstractOperationStore { // eslint-disable-line no-unused-vars
apply (ops) {
for (var key in ops) {
var o = ops[key]
var required = Struct[o.struct].requiredOps(o)
this.whenOperationsExist(required, o)
if (!o.gc) {
var required = Struct[o.struct].requiredOps(o)
this.whenOperationsExist(required, o)
} else {
throw new Error("Must not receive gc'd ops!")
}
}
}
// op is executed as soon as every operation requested is available.
@ -200,6 +207,7 @@ class AbstractOperationStore { // eslint-disable-line no-unused-vars
var state = yield* this.getState(op.id[0])
if (op.id[1] === state.clock) {
state.clock++
yield* this.checkDeleteStoreForState(state)
yield* this.setState(state)
yield* Struct[op.struct].execute.call(this, op)
yield* this.addOperation(op)

View File

@ -125,6 +125,12 @@ Y.Memory = (function () { // eslint-disable-line no-unused-vars
this.os = store.os
this.ds = store.ds
}
* checkDeleteStoreForState (state) {
var n = this.ds.findNodeWithUpperBound([state.user, state.clock])
if (n !== null && n.val.id[0] === state.user) {
state.clock = Math.max(state.clock, n.val.id[1] + n.val.len)
}
}
* getDeleteSet (id) {
return this.ds.toDeleteSet(id)
}
@ -196,14 +202,16 @@ Y.Memory = (function () { // eslint-disable-line no-unused-vars
var endPos = endState.clock
this.os.iterate([user, startPos], [user, endPos], function (op) {// eslint-disable-line
ops.push(Struct[op.struct].encode(op))
if (!op.gc) {
ops.push(Struct[op.struct].encode(op))
}
})
}
var res = []
for (var op of ops) {
res.push(yield* this.makeOperationReady(startSS, op))
var state = startSS[op.id[0]] || 0
if (state === op.id[1]) {
if (state === op.id[1] || true) {
startSS[op.id[0]] = state + 1
} else {
throw new Error('Unexpected operation!')
@ -218,8 +226,8 @@ Y.Memory = (function () { // eslint-disable-line no-unused-vars
var clock
while (o.right != null) {
// while unknown, go to the right
clock = ss[o.right[0]]
if (clock != null && o.right[1] < clock) {
clock = ss[o.right[0]] || 0
if (o.right[1] < clock && !o.gc) {
break
}
o = yield* this.getOperation(o.right)
@ -227,8 +235,8 @@ Y.Memory = (function () { // eslint-disable-line no-unused-vars
op.right = o.right
while (o.left != null) {
// while unknown, go to the right
clock = ss[o.left[0]]
if (clock != null && o.left[1] < clock) {
clock = ss[o.left[0]] || 0
if (o.left[1] < clock && !o.gc) {
break
}
o = yield* this.getOperation(o.left)

View File

@ -25,11 +25,12 @@ var Struct = {
return op
},
requiredOps: function (op) {
return [op.target]
return [] // [op.target]
},
execute: function * (op) {
console.log('Delete', op, console.trace())
var target = yield* this.getOperation(op.target)
if (!target.deleted) {
if (target != null && !target.deleted) {
target.deleted = true
if (target.left !== null && (yield* this.getOperation(target.left)).deleted) {
this.store.addToGarbageCollector(target.id)
@ -44,13 +45,19 @@ var Struct = {
}
}
yield* this.setOperation(target)
this.ds.delete(target.id)
var t = this.store.initializedTypes[JSON.stringify(target.parent)]
if (t != null) {
yield* t._changed(this, copyObject(op))
}
}
if (target == null || !target.deleted) {
this.ds.delete(op.target)
var state = yield* this.getState(op.target[0])
if (state === op.target[1]) {
yield* this.checkDeleteStoreForState(state)
yield* this.setState(state)
}
}
}
},
Insert: {
@ -65,7 +72,7 @@ var Struct = {
}
*/
encode: function (op) {
/*
/* bad idea, right?
var e = {
id: op.id,
left: op.left,

View File

@ -1,17 +1,17 @@
/* global createUsers, wait, Y, compareAllUsers, getRandomNumber, applyRandomTransactions */
/* eslint-env browser,jasmine */
var numberOfYArrayTests = 100
var numberOfYArrayTests = 5
describe('Array Type', function () {
var y1, y2, y3, yconfig1, yconfig2, yconfig3, flushAll
jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000
beforeEach(async function (done) {
await createUsers(this, 5)
await createUsers(this, 2)
y1 = (yconfig1 = this.users[0]).root
y2 = (yconfig2 = this.users[1]).root
y3 = (yconfig3 = this.users[2]).root
// y3 = (yconfig3 = this.users[2]).root
flushAll = this.users[0].connector.flushAll
done()
})
@ -192,12 +192,12 @@ describe('Array Type', function () {
await wait()
l3 = await y3.get('Array')
await flushAll()
yconfig1.db.garbageCollect()
yconfig1.db.garbageCollect()
await garbageCollectAllUsers(this.users)
yconfig1.db.logTable()
expect(l1.toArray()).toEqual(l2.toArray())
expect(l2.toArray()).toEqual(l3.toArray())
expect(l2.toArray()).toEqual([])
await compareAllUsers(this.users)
done()
})
})
@ -240,6 +240,9 @@ describe('Array Type', function () {
done()
})
it(`succeed after ${numberOfYArrayTests} actions`, async function (done) {
for (var u of this.users) {
u.connector.debug = true
}
await applyRandomTransactions(this.users, this.arrays, randomArrayTransactions, numberOfYArrayTests)
await flushAll()
await compareArrayValues(this.arrays)

View File

@ -35,7 +35,9 @@ class YConfig { // eslint-disable-line no-unused-vars
disconnect () {
this.connector.disconnect()
}
reconnect () {
async reconnect () {
await this.db.garbageCollect()
await this.db.garbageCollect()
this.connector.reconnect()
}
destroy () {