fix several sync issues. improve performance a bit by removing ds from first sync step
This commit is contained in:
		
							parent
							
								
									409a9414f1
								
							
						
					
					
						commit
						a64730e651
					
				@ -59,7 +59,6 @@ export default function extendConnector (Y/* :any */) {
 | 
				
			|||||||
      this.syncingClients = []
 | 
					      this.syncingClients = []
 | 
				
			||||||
      this.forwardToSyncingClients = opts.forwardToSyncingClients !== false
 | 
					      this.forwardToSyncingClients = opts.forwardToSyncingClients !== false
 | 
				
			||||||
      this.debug = opts.debug === true
 | 
					      this.debug = opts.debug === true
 | 
				
			||||||
      this.syncStep2 = Promise.resolve()
 | 
					 | 
				
			||||||
      this.broadcastOpBuffer = []
 | 
					      this.broadcastOpBuffer = []
 | 
				
			||||||
      this.protocolVersion = 11
 | 
					      this.protocolVersion = 11
 | 
				
			||||||
      this.authInfo = opts.auth || null
 | 
					      this.authInfo = opts.auth || null
 | 
				
			||||||
@ -146,6 +145,9 @@ export default function extendConnector (Y/* :any */) {
 | 
				
			|||||||
        isSynced: false,
 | 
					        isSynced: false,
 | 
				
			||||||
        role: role
 | 
					        role: role
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      let defer = {}
 | 
				
			||||||
 | 
					      defer.promise = new Promise(function (resolve) { defer.resolve = resolve })
 | 
				
			||||||
 | 
					      this.connections[user].syncStep2 = defer
 | 
				
			||||||
      for (var f of this.userEventListeners) {
 | 
					      for (var f of this.userEventListeners) {
 | 
				
			||||||
        f({
 | 
					        f({
 | 
				
			||||||
          action: 'userJoined',
 | 
					          action: 'userJoined',
 | 
				
			||||||
@ -187,7 +189,7 @@ export default function extendConnector (Y/* :any */) {
 | 
				
			|||||||
          var answer = {
 | 
					          var answer = {
 | 
				
			||||||
            type: 'sync step 1',
 | 
					            type: 'sync step 1',
 | 
				
			||||||
            stateSet: stateSet,
 | 
					            stateSet: stateSet,
 | 
				
			||||||
            deleteSet: deleteSet,
 | 
					            // deleteSet: deleteSet,
 | 
				
			||||||
            protocolVersion: conn.protocolVersion,
 | 
					            protocolVersion: conn.protocolVersion,
 | 
				
			||||||
            auth: conn.authInfo
 | 
					            auth: conn.authInfo
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
@ -289,51 +291,59 @@ export default function extendConnector (Y/* :any */) {
 | 
				
			|||||||
          if (message.type === 'sync step 1' && canRead(auth)) {
 | 
					          if (message.type === 'sync step 1' && canRead(auth)) {
 | 
				
			||||||
            let conn = this
 | 
					            let conn = this
 | 
				
			||||||
            let m = message
 | 
					            let m = message
 | 
				
			||||||
 | 
					            let wait // wait for sync step 2 to complete
 | 
				
			||||||
 | 
					            if (this.role === 'slave') {
 | 
				
			||||||
 | 
					              wait = Promise.all(Object.keys(this.connections)
 | 
				
			||||||
 | 
					                .map(uid => this.connections[uid])
 | 
				
			||||||
 | 
					                .filter(conn => conn.role === 'master')
 | 
				
			||||||
 | 
					                .map(conn => conn.syncStep2.promise)
 | 
				
			||||||
 | 
					              )
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              wait = Promise.resolve()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            wait.then(() => {
 | 
				
			||||||
 | 
					              this.y.db.requestTransaction(function * () {
 | 
				
			||||||
 | 
					                var currentStateSet = yield * this.getStateSet()
 | 
				
			||||||
 | 
					                // TODO: remove
 | 
				
			||||||
 | 
					                // if (canWrite(auth)) {
 | 
				
			||||||
 | 
					                //  yield * this.applyDeleteSet(m.deleteSet)
 | 
				
			||||||
 | 
					                // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.y.db.requestTransaction(function * () {
 | 
					                var ds = yield * this.getDeleteSet()
 | 
				
			||||||
              var currentStateSet = yield * this.getStateSet()
 | 
					                var answer = {
 | 
				
			||||||
              if (canWrite(auth)) {
 | 
					                  type: 'sync step 2',
 | 
				
			||||||
                yield * this.applyDeleteSet(m.deleteSet)
 | 
					                  stateSet: currentStateSet,
 | 
				
			||||||
              }
 | 
					                  deleteSet: ds,
 | 
				
			||||||
 | 
					                  protocolVersion: this.protocolVersion,
 | 
				
			||||||
              var ds = yield * this.getDeleteSet()
 | 
					                  auth: this.authInfo
 | 
				
			||||||
              var answer = {
 | 
					                }
 | 
				
			||||||
                type: 'sync step 2',
 | 
					                if (message.preferUntransformed === true && Object.keys(m.stateSet).length === 0) {
 | 
				
			||||||
                stateSet: currentStateSet,
 | 
					                  answer.osUntransformed = yield * this.getOperationsUntransformed()
 | 
				
			||||||
                deleteSet: ds,
 | 
					                } else {
 | 
				
			||||||
                protocolVersion: this.protocolVersion,
 | 
					                  answer.os = yield * this.getOperations(m.stateSet)
 | 
				
			||||||
                auth: this.authInfo
 | 
					                }
 | 
				
			||||||
              }
 | 
					                conn.send(sender, answer)
 | 
				
			||||||
              if (message.preferUntransformed === true && Object.keys(m.stateSet).length === 0) {
 | 
					                if (this.forwardToSyncingClients) {
 | 
				
			||||||
                answer.osUntransformed = yield * this.getOperationsUntransformed()
 | 
					                  conn.syncingClients.push(sender)
 | 
				
			||||||
              } else {
 | 
					                  setTimeout(function () {
 | 
				
			||||||
                answer.os = yield * this.getOperations(m.stateSet)
 | 
					                    conn.syncingClients = conn.syncingClients.filter(function (cli) {
 | 
				
			||||||
              }
 | 
					                      return cli !== sender
 | 
				
			||||||
              conn.send(sender, answer)
 | 
					                    })
 | 
				
			||||||
              if (this.forwardToSyncingClients) {
 | 
					                    conn.send(sender, {
 | 
				
			||||||
                conn.syncingClients.push(sender)
 | 
					                      type: 'sync done'
 | 
				
			||||||
                setTimeout(function () {
 | 
					                    })
 | 
				
			||||||
                  conn.syncingClients = conn.syncingClients.filter(function (cli) {
 | 
					                  }, 5000) // TODO: conn.syncingClientDuration)
 | 
				
			||||||
                    return cli !== sender
 | 
					                } else {
 | 
				
			||||||
                  })
 | 
					 | 
				
			||||||
                  conn.send(sender, {
 | 
					                  conn.send(sender, {
 | 
				
			||||||
                    type: 'sync done'
 | 
					                    type: 'sync done'
 | 
				
			||||||
                  })
 | 
					                  })
 | 
				
			||||||
                }, 5000) // TODO: conn.syncingClientDuration)
 | 
					                }
 | 
				
			||||||
              } else {
 | 
					              })
 | 
				
			||||||
                conn.send(sender, {
 | 
					 | 
				
			||||||
                  type: 'sync done'
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
          } else if (message.type === 'sync step 2' && canWrite(auth)) {
 | 
					          } else if (message.type === 'sync step 2' && canWrite(auth)) {
 | 
				
			||||||
            var db = this.y.db
 | 
					            var db = this.y.db
 | 
				
			||||||
            var defer = {}
 | 
					            let defer = this.connections[sender].syncStep2
 | 
				
			||||||
            defer.promise = new Promise(function (resolve) {
 | 
					            let m = message
 | 
				
			||||||
              defer.resolve = resolve
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            this.syncStep2 = defer.promise
 | 
					 | 
				
			||||||
            let m /* :MessageSyncStep2 */ = message
 | 
					 | 
				
			||||||
            // apply operations first
 | 
					            // apply operations first
 | 
				
			||||||
            db.requestTransaction(function * () {
 | 
					            db.requestTransaction(function * () {
 | 
				
			||||||
              yield * this.applyDeleteSet(m.deleteSet)
 | 
					              yield * this.applyDeleteSet(m.deleteSet)
 | 
				
			||||||
@ -344,18 +354,17 @@ export default function extendConnector (Y/* :any */) {
 | 
				
			|||||||
              }
 | 
					              }
 | 
				
			||||||
              defer.resolve()
 | 
					              defer.resolve()
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            /*
 | 
					            /*/ then apply ds
 | 
				
			||||||
            then apply ds
 | 
					 | 
				
			||||||
            db.whenTransactionsFinished().then(() => {
 | 
					            db.whenTransactionsFinished().then(() => {
 | 
				
			||||||
              db.requestTransaction(function * () {
 | 
					              db.requestTransaction(function * () {
 | 
				
			||||||
                yield * this.applyDeleteSet(m.deleteSet)
 | 
					                yield * this.applyDeleteSet(m.deleteSet)
 | 
				
			||||||
              })
 | 
					              })
 | 
				
			||||||
              defer.resolve()
 | 
					              defer.resolve()
 | 
				
			||||||
            })*/
 | 
					            })*/
 | 
				
			||||||
            return this.syncStep2
 | 
					            return defer.promise
 | 
				
			||||||
          } else if (message.type === 'sync done') {
 | 
					          } else if (message.type === 'sync done') {
 | 
				
			||||||
            var self = this
 | 
					            var self = this
 | 
				
			||||||
            this.syncStep2.then(function () {
 | 
					            this.connections[sender].syncStep2.promise.then(function () {
 | 
				
			||||||
              self._setSyncedWith(sender)
 | 
					              self._setSyncedWith(sender)
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
          } else if (message.type === 'update' && canWrite(auth)) {
 | 
					          } else if (message.type === 'update' && canWrite(auth)) {
 | 
				
			||||||
 | 
				
			|||||||
@ -93,9 +93,19 @@ export async function initArrays (t, opts) {
 | 
				
			|||||||
  var chance = opts.chance || new Chance(t.getSeed() * 1000000000)
 | 
					  var chance = opts.chance || new Chance(t.getSeed() * 1000000000)
 | 
				
			||||||
  var connector = Object.assign({ room: 'debugging_' + t.name, testContext: t, chance }, opts.connector)
 | 
					  var connector = Object.assign({ room: 'debugging_' + t.name, testContext: t, chance }, opts.connector)
 | 
				
			||||||
  for (let i = 0; i < opts.users; i++) {
 | 
					  for (let i = 0; i < opts.users; i++) {
 | 
				
			||||||
 | 
					    let dbOpts
 | 
				
			||||||
 | 
					    let connOpts
 | 
				
			||||||
 | 
					    if (i === 0) {
 | 
				
			||||||
 | 
					      // Only one instance can gc!
 | 
				
			||||||
 | 
					      dbOpts = Object.assign({ gc: true }, opts.db)
 | 
				
			||||||
 | 
					      connOpts = Object.assign({ role: 'master' }, connector)
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      dbOpts = Object.assign({ gc: false }, opts.db)
 | 
				
			||||||
 | 
					      connOpts = Object.assign({ role: 'slave' }, connector)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    let y = await Y({
 | 
					    let y = await Y({
 | 
				
			||||||
      connector: connector,
 | 
					      connector: connOpts,
 | 
				
			||||||
      db: Object.assign({ gc: i === 0 }, opts.db), // Only one instance can gc!
 | 
					      db: dbOpts,
 | 
				
			||||||
      share: share
 | 
					      share: share
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    result.users.push(y)
 | 
					    result.users.push(y)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
/* global Y */
 | 
					/* global Y */
 | 
				
			||||||
 | 
					import { wait } from './helper.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var rooms = {}
 | 
					var rooms = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -13,8 +14,8 @@ export class TestRoom {
 | 
				
			|||||||
      connector.setUserId('' + (this.nextUserId++))
 | 
					      connector.setUserId('' + (this.nextUserId++))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    Object.keys(this.users).forEach(uid => {
 | 
					    Object.keys(this.users).forEach(uid => {
 | 
				
			||||||
      this.users[uid].userJoined(connector.userId, 'master')
 | 
					      this.users[uid].userJoined(connector.userId, connector.role)
 | 
				
			||||||
      connector.userJoined(uid, 'master')
 | 
					      connector.userJoined(uid, this.users[uid].role)
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    this.users[connector.userId] = connector
 | 
					    this.users[connector.userId] = connector
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -43,6 +44,7 @@ export class TestRoom {
 | 
				
			|||||||
      users = allUserIds.map(id => this.users[id].y)
 | 
					      users = allUserIds.map(id => this.users[id].y)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    while (flushing) {
 | 
					    while (flushing) {
 | 
				
			||||||
 | 
					      await wait(10)
 | 
				
			||||||
      let res = await Promise.all(allUserIds.map(id => this.users[id]._flushAll(users)))
 | 
					      let res = await Promise.all(allUserIds.map(id => this.users[id]._flushAll(users)))
 | 
				
			||||||
      flushing = res.some(status => status === 'flushing')
 | 
					      flushing = res.some(status => status === 'flushing')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -65,7 +67,6 @@ export default function extendTestConnector (Y) {
 | 
				
			|||||||
      if (options.room == null) {
 | 
					      if (options.room == null) {
 | 
				
			||||||
        throw new Error('You must define a room name!')
 | 
					        throw new Error('You must define a room name!')
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      options.role = 'slave'
 | 
					 | 
				
			||||||
      super(y, options)
 | 
					      super(y, options)
 | 
				
			||||||
      this.options = options
 | 
					      this.options = options
 | 
				
			||||||
      this.room = options.room
 | 
					      this.room = options.room
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user