Compare commits

..

5 Commits

Author SHA1 Message Date
Kevin Jahns
658c520b93 13.5.47 2023-02-21 14:37:24 +01:00
Kevin Jahns
2576d4efca increasing sort of ds encoding 2023-02-21 14:35:28 +01:00
Kevin Jahns
58b754950e Merge pull request #439 from Synthesia-Technologies/feat/deterministic-update-encoding
Make encodeStateAsUpdate deterministic
2023-02-21 10:59:31 +01:00
Adam Chelminski
6b7b3136e0 delete set encoding should be in descending order 2022-06-23 16:01:29 +02:00
Adam Chelminski
da052bdb0a Make encodeStateAsUpdate deterministic 2022-06-23 15:50:35 +02:00
6 changed files with 25 additions and 19 deletions

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "yjs",
"version": "13.5.46",
"version": "13.5.47",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "yjs",
"version": "13.5.46",
"version": "13.5.47",
"license": "MIT",
"dependencies": {
"lib0": "^0.2.49"

View File

@@ -1,6 +1,6 @@
{
"name": "yjs",
"version": "13.5.46",
"version": "13.5.47",
"description": "Shared Editing Library",
"main": "./dist/yjs.cjs",
"module": "./dist/yjs.mjs",

View File

@@ -21,6 +21,7 @@ import {
} from '../internals.js'
import * as error from 'lib0/error'
import * as array from 'lib0/array'
/**
* Define the elements to which a set of CSS queries apply.
@@ -237,7 +238,7 @@ export class YXmlFragment extends AbstractType {
querySelectorAll (query) {
query = query.toUpperCase()
// @ts-ignore
return Array.from(new YXmlTreeWalker(this, element => element.nodeName && element.nodeName.toUpperCase() === query))
return array.from(new YXmlTreeWalker(this, element => element.nodeName && element.nodeName.toUpperCase() === query))
}
/**

View File

@@ -219,17 +219,21 @@ export const createDeleteSetFromStructStore = ss => {
*/
export const writeDeleteSet = (encoder, ds) => {
encoding.writeVarUint(encoder.restEncoder, ds.clients.size)
ds.clients.forEach((dsitems, client) => {
encoder.resetDsCurVal()
encoding.writeVarUint(encoder.restEncoder, client)
const len = dsitems.length
encoding.writeVarUint(encoder.restEncoder, len)
for (let i = 0; i < len; i++) {
const item = dsitems[i]
encoder.writeDsClock(item.clock)
encoder.writeDsLen(item.len)
}
})
// Ensure that the delete set is written in a deterministic order
array.from(ds.clients.entries())
.sort((a, b) => b[0] - a[0])
.forEach(([client, dsitems]) => {
encoder.resetDsCurVal()
encoding.writeVarUint(encoder.restEncoder, client)
const len = dsitems.length
encoding.writeVarUint(encoder.restEncoder, len)
for (let i = 0; i < len; i++) {
const item = dsitems[i]
encoder.writeDsClock(item.clock)
encoder.writeDsLen(item.len)
}
})
}
/**

View File

@@ -147,7 +147,7 @@ export class Doc extends Observable {
}
getSubdocGuids () {
return new Set(Array.from(this.subdocs).map(doc => doc.guid))
return new Set(array.from(this.subdocs).map(doc => doc.guid))
}
/**

View File

@@ -45,6 +45,7 @@ import * as decoding from 'lib0/decoding'
import * as binary from 'lib0/binary'
import * as map from 'lib0/map'
import * as math from 'lib0/math'
import * as array from 'lib0/array'
/**
* @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
@@ -96,7 +97,7 @@ export const writeClientsStructs = (encoder, store, _sm) => {
encoding.writeVarUint(encoder.restEncoder, sm.size)
// Write items with higher client ids first
// This heavily improves the conflict algorithm.
Array.from(sm.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
array.from(sm.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
// @ts-ignore
writeStructs(encoder, store.clients.get(client), client, clock)
})
@@ -231,7 +232,7 @@ const integrateStructs = (transaction, store, clientsStructRefs) => {
*/
const stack = []
// sort them so that we take the higher id first, in case of conflicts the lower id will probably not conflict with the id from the higher user.
let clientsStructRefsIds = Array.from(clientsStructRefs.keys()).sort((a, b) => a - b)
let clientsStructRefsIds = array.from(clientsStructRefs.keys()).sort((a, b) => a - b)
if (clientsStructRefsIds.length === 0) {
return null
}
@@ -601,7 +602,7 @@ export const decodeStateVector = decodedState => readStateVector(new DSDecoderV1
*/
export const writeStateVector = (encoder, sv) => {
encoding.writeVarUint(encoder.restEncoder, sv.size)
Array.from(sv.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
array.from(sv.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
encoding.writeVarUint(encoder.restEncoder, client) // @todo use a special client decoder that is based on mapping
encoding.writeVarUint(encoder.restEncoder, clock)
})