implement new method awaitedOps in favor of awaitedDeletes/awaitedInserts. This will fix some bugs when the type gets out of sync with the state of yjs
This commit is contained in:
		
							parent
							
								
									996566419c
								
							
						
					
					
						commit
						5b835563c8
					
				
							
								
								
									
										2
									
								
								dist
									
									
									
									
									
								
							
							
								
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist
									
									
									
									
									
								
							@ -1 +1 @@
 | 
				
			|||||||
Subproject commit 3f60690880908e7f9a92642e37253f1ac84db3f6
 | 
					Subproject commit e2f93af86e9dd207cb57d313c6ac305cd69e34d1
 | 
				
			||||||
@ -413,7 +413,7 @@ module.exports = function (Y /* :any */) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      // notify parent, if it was instanciated as a custom type
 | 
					      // notify parent, if it was instanciated as a custom type
 | 
				
			||||||
      if (t != null) {
 | 
					      if (t != null) {
 | 
				
			||||||
        let o = Y.utils.copyObject(op)
 | 
					        let o = Y.utils.copyOperation(op)
 | 
				
			||||||
        yield* t._changed(transaction, o)
 | 
					        yield* t._changed(transaction, o)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (!op.deleted) {
 | 
					      if (!op.deleted) {
 | 
				
			||||||
 | 
				
			|||||||
@ -86,10 +86,6 @@ function getRandomString () {
 | 
				
			|||||||
g.getRandomString = getRandomString
 | 
					g.getRandomString = getRandomString
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function * applyTransactions (relAmount, numberOfTransactions, objects, users, transactions, noReconnect) {
 | 
					function * applyTransactions (relAmount, numberOfTransactions, objects, users, transactions, noReconnect) {
 | 
				
			||||||
  function randomTransaction (root) {
 | 
					 | 
				
			||||||
    var f = getRandom(transactions)
 | 
					 | 
				
			||||||
    f(root)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  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.5) {
 | 
				
			||||||
@ -97,44 +93,76 @@ function * applyTransactions (relAmount, numberOfTransactions, objects, users, t
 | 
				
			|||||||
      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
 | 
				
			||||||
      randomTransaction(getRandom(objects))
 | 
					      var done = getRandom(transactions)(getRandom(objects))
 | 
				
			||||||
 | 
					      if (done != null) {
 | 
				
			||||||
 | 
					        yield done
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        yield wait()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      yield Y.utils.globalRoom.whenTransactionsFinished()
 | 
					      yield Y.utils.globalRoom.whenTransactionsFinished()
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // 5% chance to disconnect/reconnect
 | 
					      // 5% chance to disconnect/reconnect
 | 
				
			||||||
      var u = getRandom(users)
 | 
					      var u = getRandom(users)
 | 
				
			||||||
 | 
					      yield Promise.all(objects.map(fixAwaitingInType))
 | 
				
			||||||
      if (u.connector.isDisconnected()) {
 | 
					      if (u.connector.isDisconnected()) {
 | 
				
			||||||
        yield u.reconnect()
 | 
					        yield u.reconnect()
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        yield u.disconnect()
 | 
					        yield u.disconnect()
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      yield Promise.all(objects.map(fixAwaitingInType))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function fixAwaitingInType (type) {
 | 
				
			||||||
 | 
					  return new Promise(function (resolve) {
 | 
				
			||||||
 | 
					    type.os.whenTransactionsFinished().then(function () {
 | 
				
			||||||
 | 
					      // _debuggingAwaiting artificially increases the awaiting property. We need to make sure that we only do that once / reverse the effect once
 | 
				
			||||||
 | 
					      type.os.requestTransaction(function * () {
 | 
				
			||||||
 | 
					        if (type.eventHandler.awaiting > 0 && type.eventHandler._debuggingAwaiting === true) {
 | 
				
			||||||
 | 
					          type.eventHandler._debuggingAwaiting = false
 | 
				
			||||||
 | 
					          yield* type.eventHandler.awaitedOps(this, 0)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        wait(50).then(type.os.whenTransactionsFinished()).then(wait(50)).then(resolve)
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					g.fixAwaitingInType = fixAwaitingInType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
g.applyRandomTransactionsNoGCNoDisconnect = async(function * applyRandomTransactions (users, objects, transactions, numberOfTransactions) {
 | 
					g.applyRandomTransactionsNoGCNoDisconnect = async(function * applyRandomTransactions (users, objects, transactions, numberOfTransactions) {
 | 
				
			||||||
  yield* applyTransactions(1, numberOfTransactions, objects, users, transactions, true)
 | 
					  yield* applyTransactions(1, numberOfTransactions, objects, users, transactions, true)
 | 
				
			||||||
  yield Y.utils.globalRoom.flushAll()
 | 
					  yield Y.utils.globalRoom.flushAll()
 | 
				
			||||||
 | 
					  yield Promise.all(objects.map(fixAwaitingInType))
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
g.applyRandomTransactionsAllRejoinNoGC = async(function * applyRandomTransactions (users, objects, transactions, numberOfTransactions) {
 | 
					g.applyRandomTransactionsAllRejoinNoGC = async(function * applyRandomTransactions (users, objects, transactions, numberOfTransactions) {
 | 
				
			||||||
  yield* applyTransactions(1, numberOfTransactions, objects, users, transactions)
 | 
					  yield* applyTransactions(1, numberOfTransactions, objects, users, transactions)
 | 
				
			||||||
 | 
					  yield Promise.all(objects.map(fixAwaitingInType))
 | 
				
			||||||
  yield Y.utils.globalRoom.flushAll()
 | 
					  yield Y.utils.globalRoom.flushAll()
 | 
				
			||||||
 | 
					  yield Promise.all(objects.map(fixAwaitingInType))
 | 
				
			||||||
  for (var u in users) {
 | 
					  for (var u in users) {
 | 
				
			||||||
 | 
					    yield Promise.all(objects.map(fixAwaitingInType))
 | 
				
			||||||
    yield users[u].reconnect()
 | 
					    yield users[u].reconnect()
 | 
				
			||||||
 | 
					    yield Promise.all(objects.map(fixAwaitingInType))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  yield Promise.all(objects.map(fixAwaitingInType))
 | 
				
			||||||
  yield Y.utils.globalRoom.flushAll()
 | 
					  yield Y.utils.globalRoom.flushAll()
 | 
				
			||||||
 | 
					  yield Promise.all(objects.map(fixAwaitingInType))
 | 
				
			||||||
  yield g.garbageCollectAllUsers(users)
 | 
					  yield g.garbageCollectAllUsers(users)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
g.applyRandomTransactionsWithGC = async(function * applyRandomTransactions (users, objects, transactions, numberOfTransactions) {
 | 
					g.applyRandomTransactionsWithGC = async(function * applyRandomTransactions (users, objects, transactions, numberOfTransactions) {
 | 
				
			||||||
  yield* applyTransactions(1, numberOfTransactions, objects, users.slice(1), transactions)
 | 
					  yield* applyTransactions(1, numberOfTransactions, objects, users.slice(1), transactions)
 | 
				
			||||||
  yield Y.utils.globalRoom.flushAll()
 | 
					  yield Y.utils.globalRoom.flushAll()
 | 
				
			||||||
 | 
					  yield Promise.all(objects.map(fixAwaitingInType))
 | 
				
			||||||
  for (var u in users) {
 | 
					  for (var u in users) {
 | 
				
			||||||
    // TODO: here, we enforce that two users never sync at the same time with u[0]
 | 
					    // TODO: here, we enforce that two users never sync at the same time with u[0]
 | 
				
			||||||
    //       enforce that in the connector itself!
 | 
					    //       enforce that in the connector itself!
 | 
				
			||||||
    yield users[u].reconnect()
 | 
					    yield users[u].reconnect()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  yield Y.utils.globalRoom.flushAll()
 | 
					  yield Y.utils.globalRoom.flushAll()
 | 
				
			||||||
 | 
					  yield Promise.all(objects.map(fixAwaitingInType))
 | 
				
			||||||
  yield g.garbageCollectAllUsers(users)
 | 
					  yield g.garbageCollectAllUsers(users)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -222,7 +250,6 @@ g.compareAllUsers = async(function * compareAllUsers (users) {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // TODO: make requestTransaction return a promise..
 | 
					 | 
				
			||||||
      u.db.requestTransaction(function * () {
 | 
					      u.db.requestTransaction(function * () {
 | 
				
			||||||
        yield* t2.call(this)
 | 
					        yield* t2.call(this)
 | 
				
			||||||
        var db2 = []
 | 
					        var db2 = []
 | 
				
			||||||
 | 
				
			|||||||
@ -1068,7 +1068,7 @@ module.exports = function (Y/* :any */) {
 | 
				
			|||||||
    /* this is what we used before.. use this as a reference..
 | 
					    /* this is what we used before.. use this as a reference..
 | 
				
			||||||
    * makeOperationReady (startSS, op) {
 | 
					    * makeOperationReady (startSS, op) {
 | 
				
			||||||
      op = Y.Struct[op.struct].encode(op)
 | 
					      op = Y.Struct[op.struct].encode(op)
 | 
				
			||||||
      op = Y.utils.copyObject(op)
 | 
					      op = Y.utils.copyObject(op) -- use copyoperation instead now!
 | 
				
			||||||
      var o = op
 | 
					      var o = op
 | 
				
			||||||
      var ids = [op.id]
 | 
					      var ids = [op.id]
 | 
				
			||||||
      // search for the new op.right
 | 
					      // search for the new op.right
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										93
									
								
								src/Utils.js
									
									
									
									
									
								
							
							
						
						
									
										93
									
								
								src/Utils.js
									
									
									
									
									
								
							@ -102,9 +102,41 @@ module.exports = function (Y /* : any*/) {
 | 
				
			|||||||
      prematurely called operations are executed
 | 
					      prematurely called operations are executed
 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
    awaitAndPrematurelyCall (ops) {
 | 
					    awaitAndPrematurelyCall (ops) {
 | 
				
			||||||
      this.awaiting += ops.length
 | 
					      this.awaiting++
 | 
				
			||||||
      ops.forEach(this.onevent)
 | 
					      ops.map(Y.utils.copyOperation).forEach(this.onevent)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    * awaitedOps (transaction, n) {
 | 
				
			||||||
 | 
					      // remove awaited ops
 | 
				
			||||||
 | 
					      this.waiting.splice(this.waiting.length - n)
 | 
				
			||||||
 | 
					      // update all waiting ops
 | 
				
			||||||
 | 
					      for (let i = 0; i < this.waiting.length; i++) {
 | 
				
			||||||
 | 
					        var o = this.waiting[i]
 | 
				
			||||||
 | 
					        if (o.struct === 'Insert') {
 | 
				
			||||||
 | 
					          var _o = yield* transaction.getInsertion(o.id)
 | 
				
			||||||
 | 
					          if (!Y.utils.compareIds(_o.id, o.id)) {
 | 
				
			||||||
 | 
					            // o got extended
 | 
				
			||||||
 | 
					            o.left = [o.id[0], o.id[1] - 1]
 | 
				
			||||||
 | 
					          } else if (_o.left == null) {
 | 
				
			||||||
 | 
					            o.left = null
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            // find next undeleted op
 | 
				
			||||||
 | 
					            var left = yield* transaction.getInsertion(_o.left)
 | 
				
			||||||
 | 
					            while (left.deleted != null) {
 | 
				
			||||||
 | 
					              if (left.left != null) {
 | 
				
			||||||
 | 
					                left = yield* transaction.getInsertion(left.left)
 | 
				
			||||||
 | 
					              } else {
 | 
				
			||||||
 | 
					                left = null
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            o.left = left != null ? Y.utils.getLastId(left) : null
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this._tryCallEvents()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 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
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
      Call this when you successfully awaited the execution of n Insert operations
 | 
					      Call this when you successfully awaited the execution of n Insert operations
 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
@ -162,12 +194,42 @@ module.exports = function (Y /* : any*/) {
 | 
				
			|||||||
    /* (private)
 | 
					    /* (private)
 | 
				
			||||||
      Try to execute the events for the waiting operations
 | 
					      Try to execute the events for the waiting operations
 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
    _tryCallEvents (n) {
 | 
					    _tryCallEvents () {
 | 
				
			||||||
      this.awaiting -= n
 | 
					      function notSoSmartSort (array) {
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (this.awaiting > 0) this.awaiting--
 | 
				
			||||||
      if (this.awaiting === 0 && this.waiting.length > 0) {
 | 
					      if (this.awaiting === 0 && this.waiting.length > 0) {
 | 
				
			||||||
        var ops = this.waiting
 | 
					        var ins = []
 | 
				
			||||||
 | 
					        var dels = []
 | 
				
			||||||
 | 
					        this.waiting.forEach(function (o) {
 | 
				
			||||||
 | 
					          if (o.struct === 'Delete') {
 | 
				
			||||||
 | 
					            dels.push(o)
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            ins.push(o)
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        ins = notSoSmartSort(ins)
 | 
				
			||||||
 | 
					        ins.forEach(this.onevent)
 | 
				
			||||||
 | 
					        dels.forEach(this.onevent)
 | 
				
			||||||
        this.waiting = []
 | 
					        this.waiting = []
 | 
				
			||||||
        ops.forEach(this.onevent)
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -236,6 +298,20 @@ module.exports = function (Y /* : any*/) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  Y.utils.copyObject = copyObject
 | 
					  Y.utils.copyObject = copyObject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					    Copy an operation, so that it can be manipulated.
 | 
				
			||||||
 | 
					    Note: You must not change subproperties (except o.content)!
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					  function copyOperation (o) {
 | 
				
			||||||
 | 
					    o = copyObject(o)
 | 
				
			||||||
 | 
					    if (o.content != null) {
 | 
				
			||||||
 | 
					      o.content = o.content.map(function (c) { return c })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return o
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Y.utils.copyOperation = copyOperation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*
 | 
					  /*
 | 
				
			||||||
    Defines a smaller relation on Id's
 | 
					    Defines a smaller relation on Id's
 | 
				
			||||||
  */
 | 
					  */
 | 
				
			||||||
@ -244,6 +320,11 @@ module.exports = function (Y /* : any*/) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  Y.utils.smaller = smaller
 | 
					  Y.utils.smaller = smaller
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function inDeletionRange (del, ins) {
 | 
				
			||||||
 | 
					    return del.target[0] === ins[0] && del.target[1] <= ins[1] && ins[1] < del.target[1] + (del.length || 1)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  Y.utils.inDeletionRange = inDeletionRange
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function compareIds (id1, id2) {
 | 
					  function compareIds (id1, id2) {
 | 
				
			||||||
    if (id1 == null || id2 == null) {
 | 
					    if (id1 == null || id2 == null) {
 | 
				
			||||||
      return id1 === id2
 | 
					      return id1 === id2
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user