improved awaitOps

This commit is contained in:
Kevin Jahns 2016-05-07 13:16:48 +01:00
parent 483d2c78aa
commit 14d59de2bd
3 changed files with 90 additions and 33 deletions

View File

@ -479,16 +479,11 @@ module.exports = function (Y /* :any */) {
this.waitingTransactions.push(makeGen) this.waitingTransactions.push(makeGen)
if (!this.transactionInProgress) { if (!this.transactionInProgress) {
this.transactionInProgress = true this.transactionInProgress = true
if (false || callImmediately) { // TODO: decide whether this is ok or not.. setTimeout(() => {
this.transact(this.getNextRequest()) this.transact(this.getNextRequest())
} else {
var self = this
setTimeout(function () {
self.transact(self.getNextRequest())
}, 0) }, 0)
} }
} }
} }
}
Y.AbstractDatabase = AbstractDatabase Y.AbstractDatabase = AbstractDatabase
} }

View File

@ -88,8 +88,21 @@ g.getRandomString = getRandomString
function * applyTransactions (relAmount, numberOfTransactions, objects, users, transactions, noReconnect) { function * applyTransactions (relAmount, numberOfTransactions, objects, users, transactions, noReconnect) {
for (var i = 0; i < numberOfTransactions * relAmount + 1; i++) { for (var i = 0; i < numberOfTransactions * relAmount + 1; i++) {
var r = Math.random() var r = Math.random()
if (r >= 0.5) { if (r > 0.9) {
// 50% chance to flush // 10% chance of toggling concurrent user interactions.
// There will be an artificial delay until ops can be executed by the type,
// therefore, operations of the database will be (pre)transformed until user operations arrive
yield (function simulateConcurrentUserInteractions (type) {
if (type.eventHandler.awaiting === 0 && type.eventHandler._debuggingAwaiting !== true) {
type.eventHandler.awaiting = 1
type.eventHandler._debuggingAwaiting = true
} else {
// fixAwaitingInType will handle _debuggingAwaiting
return fixAwaitingInType(type)
}
})(getRandom(objects))
} else if (r >= 0.5) {
// 40% chance to flush
yield Y.utils.globalRoom.flushOne() // flushes for some user.. (not necessarily 0) yield Y.utils.globalRoom.flushOne() // flushes for some user.. (not necessarily 0)
} else if (noReconnect || r >= 0.05) { } else if (noReconnect || r >= 0.05) {
// 45% chance to create operation // 45% chance to create operation
@ -121,7 +134,7 @@ function fixAwaitingInType (type) {
type.os.requestTransaction(function * () { type.os.requestTransaction(function * () {
if (type.eventHandler.awaiting > 0 && type.eventHandler._debuggingAwaiting === true) { if (type.eventHandler.awaiting > 0 && type.eventHandler._debuggingAwaiting === true) {
type.eventHandler._debuggingAwaiting = false type.eventHandler._debuggingAwaiting = false
yield* type.eventHandler.awaitedOps(this, 0) yield* type.eventHandler.awaitOps(this, function * () { /* mock function */ })
} }
wait(50).then(type.os.whenTransactionsFinished()).then(wait(50)).then(resolve) wait(50).then(type.os.whenTransactionsFinished()).then(wait(50)).then(resolve)
}) })

View File

@ -105,9 +105,36 @@ module.exports = function (Y /* : any*/) {
this.awaiting++ this.awaiting++
ops.map(Y.utils.copyOperation).forEach(this.onevent) ops.map(Y.utils.copyOperation).forEach(this.onevent)
} }
* awaitedOps (transaction, n) { * awaitOps (transaction, f, args) {
// remove awaited ops function notSoSmartSort (array) {
this.waiting.splice(this.waiting.length - n) // this function sorts insertions in a executable order
var result = []
while (array.length > 0) {
for (var i = 0; i < array.length; i++) {
var independent = true
for (var j = 0; j < array.length; j++) {
if (Y.utils.matchesId(array[j], array[i].left)) {
// array[i] depends on array[j]
independent = false
break
}
}
if (independent) {
result.push(array.splice(i, 1)[0])
i--
}
}
}
return result
}
var before = this.waiting.length
// somehow create new operations
yield* f.apply(transaction, args)
// remove all appended ops / awaited ops
this.waiting.splice(before)
if (this.awaiting > 0) this.awaiting--
// if there are no awaited ops anymore, we can update all waiting ops, and send execute them (if there are still no awaited ops)
if (this.awaiting === 0 && this.waiting.length > 0) {
// update all waiting ops // update all waiting ops
for (let i = 0; i < this.waiting.length; i++) { for (let i = 0; i < this.waiting.length; i++) {
var o = this.waiting[i] var o = this.waiting[i]
@ -133,7 +160,29 @@ module.exports = function (Y /* : any*/) {
} }
} }
} }
this._tryCallEvents() // the previous stuff was async, so we have to check again!
// We also pull changes from the bindings, if there exists such a method, this could increase awaiting too
if (this._pullChanges != null) {
this._pullChanges()
}
if (this.awaiting === 0) {
// sort by type, execute inserts first
var ins = []
var dels = []
this.waiting.forEach(function (o) {
if (o.struct === 'Delete') {
dels.push(o)
} else {
ins.push(o)
}
})
// put in executable order
ins = notSoSmartSort(ins)
ins.forEach(this.onevent)
dels.forEach(this.onevent)
this.waiting = []
}
}
} }
// TODO: Remove awaitedInserts and awaitedDeletes in favor of awaitedOps, as they are deprecated and do not always work // TODO: Remove awaitedInserts and awaitedDeletes in favor of awaitedOps, as they are deprecated and do not always work
// Do this in one of the coming releases that are breaking anyway // Do this in one of the coming releases that are breaking anyway