add mergeUpdates tests to comparison framework
This commit is contained in:
parent
d8868c47e1
commit
fbbf085278
@ -640,10 +640,7 @@ export class Item extends AbstractStruct {
|
|||||||
}
|
}
|
||||||
if (origin === null && rightOrigin === null) {
|
if (origin === null && rightOrigin === null) {
|
||||||
const parent = /** @type {AbstractType<any>} */ (this.parent)
|
const parent = /** @type {AbstractType<any>} */ (this.parent)
|
||||||
if (parent.constructor === String) { // this edge case was added by differential updates
|
if (parent._item !== undefined) {
|
||||||
encoder.writeParentInfo(true) // write parentYKey
|
|
||||||
encoder.writeString(parent)
|
|
||||||
} else {
|
|
||||||
const parentItem = parent._item
|
const parentItem = parent._item
|
||||||
if (parentItem === null) {
|
if (parentItem === null) {
|
||||||
// parent type on y._map
|
// parent type on y._map
|
||||||
@ -655,6 +652,14 @@ export class Item extends AbstractStruct {
|
|||||||
encoder.writeParentInfo(false) // write parent id
|
encoder.writeParentInfo(false) // write parent id
|
||||||
encoder.writeLeftID(parentItem.id)
|
encoder.writeLeftID(parentItem.id)
|
||||||
}
|
}
|
||||||
|
} else if (parent.constructor === String) { // this edge case was added by differential updates
|
||||||
|
encoder.writeParentInfo(true) // write parentYKey
|
||||||
|
encoder.writeString(parent)
|
||||||
|
} else if (parent.constructor === ID) {
|
||||||
|
encoder.writeParentInfo(false) // write parent id
|
||||||
|
encoder.writeLeftID(parent)
|
||||||
|
} else {
|
||||||
|
error.unexpectedCase()
|
||||||
}
|
}
|
||||||
if (parentSub !== null) {
|
if (parentSub !== null) {
|
||||||
encoder.writeString(parentSub)
|
encoder.writeString(parentSub)
|
||||||
|
@ -14,7 +14,6 @@ import {
|
|||||||
getState,
|
getState,
|
||||||
findIndexSS,
|
findIndexSS,
|
||||||
UpdateEncoderV2,
|
UpdateEncoderV2,
|
||||||
DefaultDSEncoder,
|
|
||||||
applyUpdateV2,
|
applyUpdateV2,
|
||||||
AbstractDSDecoder, AbstractDSEncoder, DSEncoderV2, DSDecoderV1, DSDecoderV2, Transaction, Doc, DeleteSet, Item // eslint-disable-line
|
AbstractDSDecoder, AbstractDSEncoder, DSEncoderV2, DSDecoderV1, DSDecoderV2, Transaction, Doc, DeleteSet, Item // eslint-disable-line
|
||||||
} from '../internals.js'
|
} from '../internals.js'
|
||||||
@ -23,6 +22,7 @@ import * as map from 'lib0/map.js'
|
|||||||
import * as set from 'lib0/set.js'
|
import * as set from 'lib0/set.js'
|
||||||
import * as decoding from 'lib0/decoding.js'
|
import * as decoding from 'lib0/decoding.js'
|
||||||
import * as encoding from 'lib0/encoding.js'
|
import * as encoding from 'lib0/encoding.js'
|
||||||
|
import { DSEncoderV1 } from './UpdateEncoder.js'
|
||||||
|
|
||||||
export class Snapshot {
|
export class Snapshot {
|
||||||
/**
|
/**
|
||||||
@ -91,7 +91,7 @@ export const encodeSnapshotV2 = (snapshot, encoder = new DSEncoderV2()) => {
|
|||||||
* @param {Snapshot} snapshot
|
* @param {Snapshot} snapshot
|
||||||
* @return {Uint8Array}
|
* @return {Uint8Array}
|
||||||
*/
|
*/
|
||||||
export const encodeSnapshot = snapshot => encodeSnapshotV2(snapshot, new DefaultDSEncoder())
|
export const encodeSnapshot = snapshot => encodeSnapshotV2(snapshot, new DSEncoderV1())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Uint8Array} buf
|
* @param {Uint8Array} buf
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
Item,
|
Item,
|
||||||
generateNewClientId,
|
generateNewClientId,
|
||||||
createID,
|
createID,
|
||||||
AbstractUpdateEncoder, GC, StructStore, UpdateEncoderV2, DefaultUpdateEncoder, AbstractType, AbstractStruct, YEvent, Doc // eslint-disable-line
|
AbstractUpdateEncoder, GC, StructStore, UpdateEncoderV2, AbstractType, AbstractStruct, YEvent, Doc // eslint-disable-line
|
||||||
} from '../internals.js'
|
} from '../internals.js'
|
||||||
|
|
||||||
import * as map from 'lib0/map.js'
|
import * as map from 'lib0/map.js'
|
||||||
@ -19,6 +19,7 @@ import * as math from 'lib0/math.js'
|
|||||||
import * as set from 'lib0/set.js'
|
import * as set from 'lib0/set.js'
|
||||||
import * as logging from 'lib0/logging.js'
|
import * as logging from 'lib0/logging.js'
|
||||||
import { callAll } from 'lib0/function.js'
|
import { callAll } from 'lib0/function.js'
|
||||||
|
import { UpdateEncoderV1 } from './UpdateEncoder.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A transaction is created for every change on the Yjs model. It is possible
|
* A transaction is created for every change on the Yjs model. It is possible
|
||||||
@ -337,7 +338,7 @@ const cleanupTransactions = (transactionCleanups, i) => {
|
|||||||
// @todo Merge all the transactions into one and provide send the data as a single update message
|
// @todo Merge all the transactions into one and provide send the data as a single update message
|
||||||
doc.emit('afterTransactionCleanup', [transaction, doc])
|
doc.emit('afterTransactionCleanup', [transaction, doc])
|
||||||
if (doc._observers.has('update')) {
|
if (doc._observers.has('update')) {
|
||||||
const encoder = new DefaultUpdateEncoder()
|
const encoder = new UpdateEncoderV1()
|
||||||
const hasContent = writeUpdateMessageFromTransaction(encoder, transaction)
|
const hasContent = writeUpdateMessageFromTransaction(encoder, transaction)
|
||||||
if (hasContent) {
|
if (hasContent) {
|
||||||
doc.emit('update', [encoder.toUint8Array(), transaction.origin, doc])
|
doc.emit('update', [encoder.toUint8Array(), transaction.origin, doc])
|
||||||
|
@ -41,25 +41,6 @@ import * as decoding from 'lib0/decoding.js'
|
|||||||
import * as binary from 'lib0/binary.js'
|
import * as binary from 'lib0/binary.js'
|
||||||
import * as map from 'lib0/map.js'
|
import * as map from 'lib0/map.js'
|
||||||
|
|
||||||
export let DefaultDSEncoder = DSEncoderV1
|
|
||||||
export let DefaultDSDecoder = DSDecoderV1
|
|
||||||
export let DefaultUpdateEncoder = UpdateEncoderV1
|
|
||||||
export let DefaultUpdateDecoder = UpdateDecoderV1
|
|
||||||
|
|
||||||
export const useV1Encoding = () => {
|
|
||||||
DefaultDSEncoder = DSEncoderV1
|
|
||||||
DefaultDSDecoder = DSDecoderV1
|
|
||||||
DefaultUpdateEncoder = UpdateEncoderV1
|
|
||||||
DefaultUpdateDecoder = UpdateDecoderV1
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useV2Encoding = () => {
|
|
||||||
DefaultDSEncoder = DSEncoderV2
|
|
||||||
DefaultDSDecoder = DSDecoderV2
|
|
||||||
DefaultUpdateEncoder = UpdateEncoderV2
|
|
||||||
DefaultUpdateDecoder = UpdateDecoderV2
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {AbstractUpdateEncoder} encoder
|
* @param {AbstractUpdateEncoder} encoder
|
||||||
* @param {Array<GC|Item>} structs All structs by `client`
|
* @param {Array<GC|Item>} structs All structs by `client`
|
||||||
@ -445,7 +426,7 @@ export const readUpdateV2 = (decoder, ydoc, transactionOrigin, structDecoder = n
|
|||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
export const readUpdate = (decoder, ydoc, transactionOrigin) => readUpdateV2(decoder, ydoc, transactionOrigin, new DefaultUpdateDecoder(decoder))
|
export const readUpdate = (decoder, ydoc, transactionOrigin) => readUpdateV2(decoder, ydoc, transactionOrigin, new UpdateDecoderV1(decoder))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a document update created by, for example, `y.on('update', update => ..)` or `update = encodeStateAsUpdate()`.
|
* Apply a document update created by, for example, `y.on('update', update => ..)` or `update = encodeStateAsUpdate()`.
|
||||||
@ -475,7 +456,7 @@ export const applyUpdateV2 = (ydoc, update, transactionOrigin, YDecoder = Update
|
|||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
export const applyUpdate = (ydoc, update, transactionOrigin) => applyUpdateV2(ydoc, update, transactionOrigin, DefaultUpdateDecoder)
|
export const applyUpdate = (ydoc, update, transactionOrigin) => applyUpdateV2(ydoc, update, transactionOrigin, UpdateDecoderV1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write all the document as a single update message. If you specify the state of the remote client (`targetStateVector`) it will
|
* Write all the document as a single update message. If you specify the state of the remote client (`targetStateVector`) it will
|
||||||
@ -523,7 +504,7 @@ export const encodeStateAsUpdateV2 = (doc, encodedTargetStateVector, encoder = n
|
|||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
export const encodeStateAsUpdate = (doc, encodedTargetStateVector) => encodeStateAsUpdateV2(doc, encodedTargetStateVector, new DefaultUpdateEncoder())
|
export const encodeStateAsUpdate = (doc, encodedTargetStateVector) => encodeStateAsUpdateV2(doc, encodedTargetStateVector, new UpdateEncoderV1())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read state vector from Decoder and return as Map
|
* Read state vector from Decoder and return as Map
|
||||||
@ -562,7 +543,7 @@ export const decodeStateVectorV2 = decodedState => readStateVector(new DSDecoder
|
|||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
export const decodeStateVector = decodedState => readStateVector(new DefaultDSDecoder(decoding.createDecoder(decodedState)))
|
export const decodeStateVector = decodedState => readStateVector(new DSDecoderV1(decoding.createDecoder(decodedState)))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {AbstractDSEncoder} encoder
|
* @param {AbstractDSEncoder} encoder
|
||||||
@ -608,4 +589,4 @@ export const encodeStateVectorV2 = (doc, encoder = new DSEncoderV2()) => {
|
|||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
export const encodeStateVector = doc => encodeStateVectorV2(doc, new DefaultDSEncoder())
|
export const encodeStateVector = doc => encodeStateVectorV2(doc, new DSEncoderV1())
|
||||||
|
@ -27,6 +27,33 @@ const broadcastMessage = (y, m) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let useV2 = false
|
||||||
|
|
||||||
|
export let encodeStateAsUpdate = Y.encodeStateAsUpdate
|
||||||
|
export let mergeUpdates = Y.mergeUpdates
|
||||||
|
export let applyUpdate = Y.applyUpdate
|
||||||
|
export let logUpdate = Y.logUpdate
|
||||||
|
export let updateEventName = 'update'
|
||||||
|
|
||||||
|
const setEncoders = () => {
|
||||||
|
encodeStateAsUpdate = useV2 ? Y.encodeStateAsUpdateV2 : Y.encodeStateAsUpdate
|
||||||
|
mergeUpdates = useV2 ? Y.mergeUpdatesV2 : Y.mergeUpdates
|
||||||
|
applyUpdate = useV2 ? Y.applyUpdateV2 : Y.applyUpdate
|
||||||
|
logUpdate = useV2 ? Y.logUpdateV2 : Y.logUpdate
|
||||||
|
updateEventName = useV2 ? 'updateV2' : 'update'
|
||||||
|
}
|
||||||
|
|
||||||
|
const useV1Encoding = () => {
|
||||||
|
useV2 = false
|
||||||
|
setEncoders()
|
||||||
|
}
|
||||||
|
|
||||||
|
const useV2Encoding = () => {
|
||||||
|
useV2 = false
|
||||||
|
console.error('sync protocol doesnt support v2 protocol yet, fallback to v1 encoding') // @Todo
|
||||||
|
setEncoders()
|
||||||
|
}
|
||||||
|
|
||||||
export class TestYInstance extends Y.Doc {
|
export class TestYInstance extends Y.Doc {
|
||||||
/**
|
/**
|
||||||
* @param {TestConnector} testConnector
|
* @param {TestConnector} testConnector
|
||||||
@ -44,12 +71,19 @@ export class TestYInstance extends Y.Doc {
|
|||||||
*/
|
*/
|
||||||
this.receiving = new Map()
|
this.receiving = new Map()
|
||||||
testConnector.allConns.add(this)
|
testConnector.allConns.add(this)
|
||||||
|
/**
|
||||||
|
* The list of received updates.
|
||||||
|
* We are going to merge them later using Y.mergeUpdates and check if the resulting document is correct.
|
||||||
|
* @type {Array<Uint8Array>}
|
||||||
|
*/
|
||||||
|
this.updates = []
|
||||||
// set up observe on local model
|
// set up observe on local model
|
||||||
this.on('update', /** @param {Uint8Array} update @param {any} origin */ (update, origin) => {
|
this.on(updateEventName, /** @param {Uint8Array} update @param {any} origin */ (update, origin) => {
|
||||||
if (origin !== testConnector) {
|
if (origin !== testConnector) {
|
||||||
const encoder = encoding.createEncoder()
|
const encoder = encoding.createEncoder()
|
||||||
syncProtocol.writeUpdate(encoder, update)
|
syncProtocol.writeUpdate(encoder, update)
|
||||||
broadcastMessage(this, encoding.toUint8Array(encoder))
|
broadcastMessage(this, encoding.toUint8Array(encoder))
|
||||||
|
this.updates.push(update)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.connect()
|
this.connect()
|
||||||
@ -162,6 +196,17 @@ export class TestConnector {
|
|||||||
// send reply message
|
// send reply message
|
||||||
sender._receive(encoding.toUint8Array(encoder), receiver)
|
sender._receive(encoding.toUint8Array(encoder), receiver)
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
// If update message, add the received message to the list of received messages
|
||||||
|
const decoder = decoding.createDecoder(m)
|
||||||
|
const messageType = decoding.readVarUint(decoder)
|
||||||
|
switch (messageType) {
|
||||||
|
case syncProtocol.messageYjsUpdate:
|
||||||
|
case syncProtocol.messageYjsSyncStep2:
|
||||||
|
receiver.updates.push(decoding.readVarUint8Array(decoder))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -240,9 +285,9 @@ export const init = (tc, { users = 5 } = {}, initTestObject) => {
|
|||||||
const gen = tc.prng
|
const gen = tc.prng
|
||||||
// choose an encoding approach at random
|
// choose an encoding approach at random
|
||||||
if (prng.bool(gen)) {
|
if (prng.bool(gen)) {
|
||||||
Y.useV2Encoding()
|
useV2Encoding()
|
||||||
} else {
|
} else {
|
||||||
Y.useV1Encoding()
|
useV1Encoding()
|
||||||
}
|
}
|
||||||
|
|
||||||
const testConnector = new TestConnector(gen)
|
const testConnector = new TestConnector(gen)
|
||||||
@ -258,7 +303,7 @@ export const init = (tc, { users = 5 } = {}, initTestObject) => {
|
|||||||
}
|
}
|
||||||
testConnector.syncAll()
|
testConnector.syncAll()
|
||||||
result.testObjects = result.users.map(initTestObject || (() => null))
|
result.testObjects = result.users.map(initTestObject || (() => null))
|
||||||
Y.useV1Encoding()
|
useV1Encoding()
|
||||||
return /** @type {any} */ (result)
|
return /** @type {any} */ (result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,6 +319,14 @@ export const init = (tc, { users = 5 } = {}, initTestObject) => {
|
|||||||
export const compare = users => {
|
export const compare = users => {
|
||||||
users.forEach(u => u.connect())
|
users.forEach(u => u.connect())
|
||||||
while (users[0].tc.flushAllMessages()) {}
|
while (users[0].tc.flushAllMessages()) {}
|
||||||
|
// For each document, merge all received document updates with Y.mergeUpdates and create a new document which will be added to the list of "users"
|
||||||
|
// This ensures that mergeUpdates works correctly
|
||||||
|
const mergedDocs = users.map(user => {
|
||||||
|
const ydoc = new Y.Doc()
|
||||||
|
applyUpdate(ydoc, mergeUpdates(user.updates))
|
||||||
|
return ydoc
|
||||||
|
})
|
||||||
|
users.push(.../** @type {any} */(mergedDocs))
|
||||||
const userArrayValues = users.map(u => u.getArray('array').toJSON())
|
const userArrayValues = users.map(u => u.getArray('array').toJSON())
|
||||||
const userMapValues = users.map(u => u.getMap('map').toJSON())
|
const userMapValues = users.map(u => u.getMap('map').toJSON())
|
||||||
const userXmlValues = users.map(u => u.get('xml', Y.YXmlElement).toString())
|
const userXmlValues = users.map(u => u.get('xml', Y.YXmlElement).toString())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user