Skip to content
Snippets Groups Projects
Commit 06e7caab authored by Kevin Jahns's avatar Kevin Jahns
Browse files

gc implementation

parent c8ded248
No related branches found
No related tags found
No related merge requests found
......@@ -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()
}
}
})
......
......@@ -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)
......
......@@ -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)
......
......@@ -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,
......
/* 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)
......
......@@ -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 () {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment