mirror of
https://github.com/yjs/yjs.git
synced 2025-12-16 11:47:46 +01:00
doc maintains ds
This commit is contained in:
@@ -99,6 +99,7 @@ export {
|
||||
UpdateDecoderV2,
|
||||
snapshotContainsUpdate,
|
||||
// idset
|
||||
IdSet,
|
||||
equalIdSets,
|
||||
createDeleteSetFromStructStore
|
||||
} from './internals.js'
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
AbstractStruct,
|
||||
addStruct,
|
||||
addStructToIdSet,
|
||||
addToIdSet,
|
||||
UpdateEncoderV1, UpdateEncoderV2, StructStore, Transaction // eslint-disable-line
|
||||
} from '../internals.js'
|
||||
|
||||
@@ -38,6 +39,7 @@ export class GC extends AbstractStruct {
|
||||
this.id.clock += offset
|
||||
this.length -= offset
|
||||
}
|
||||
addToIdSet(transaction.deleteSet, this.id.client, this.id.clock, this.length)
|
||||
addStructToIdSet(transaction.insertSet, this)
|
||||
addStruct(transaction.doc.store, this)
|
||||
}
|
||||
|
||||
@@ -191,6 +191,25 @@ export const mergeIdSets = idSets => {
|
||||
return merged
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {IdSet} dest
|
||||
* @param {IdSet} src
|
||||
*/
|
||||
export const insertIntoIdSet = (dest, src) => {
|
||||
src.clients.forEach((srcRanges, client) => {
|
||||
const targetRanges = dest.clients.get(client)
|
||||
if (targetRanges) {
|
||||
array.appendTo(targetRanges.getIds(), srcRanges.getIds())
|
||||
targetRanges.sorted = false
|
||||
} else {
|
||||
const res = new IdRanges(srcRanges.getIds().slice())
|
||||
res.sorted = true
|
||||
dest.clients.set(client, res)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove all ranges from `exclude` from `ds`. The result is a fresh IdSet containing all ranges from `idSet` that are not
|
||||
* in `exclude`.
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import {
|
||||
GC,
|
||||
splitItem,
|
||||
Transaction, ID, Item, DSDecoderV2 // eslint-disable-line
|
||||
IdSet,
|
||||
Transaction, ID, Item // eslint-disable-line
|
||||
} from '../internals.js'
|
||||
|
||||
import * as math from 'lib0/math'
|
||||
@@ -13,6 +14,7 @@ export class StructStore {
|
||||
* @type {Map<number,Array<GC|Item>>}
|
||||
*/
|
||||
this.clients = new Map()
|
||||
this.ds = new IdSet()
|
||||
/**
|
||||
* @type {null | { missing: Map<number, number>, update: Uint8Array }}
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,8 @@ import {
|
||||
generateNewClientId,
|
||||
createID,
|
||||
cleanupYTextAfterTransaction,
|
||||
IdSet, UpdateEncoderV1, UpdateEncoderV2, GC, StructStore, AbstractType, AbstractStruct, YEvent, Doc // eslint-disable-line
|
||||
IdSet, UpdateEncoderV1, UpdateEncoderV2, GC, StructStore, AbstractType, AbstractStruct, YEvent, Doc, // eslint-disable-line
|
||||
insertIntoIdSet
|
||||
} from '../internals.js'
|
||||
|
||||
import * as error from 'lib0/error'
|
||||
@@ -307,6 +308,7 @@ const cleanupTransactions = (transactionCleanups, i) => {
|
||||
const store = doc.store
|
||||
const ds = transaction.deleteSet
|
||||
const mergeStructs = transaction._mergeStructs
|
||||
insertIntoIdSet(store.ds, ds)
|
||||
try {
|
||||
doc.emit('beforeObserverCalls', [transaction, doc])
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as t from 'lib0/testing'
|
||||
import * as d from '../src/utils/IdSet.js'
|
||||
import * as prng from 'lib0/prng'
|
||||
import * as math from 'lib0/math'
|
||||
import { compareIdSets } from './testHelper.js'
|
||||
|
||||
/**
|
||||
* @param {Array<[number, number, number]>} ops
|
||||
@@ -14,25 +15,6 @@ const simpleConstructIdSet = ops => {
|
||||
return ds
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {d.IdSet} idSet1
|
||||
* @param {d.IdSet} idSet2
|
||||
*/
|
||||
const compareIdSets = (idSet1, idSet2) => {
|
||||
if (idSet1.clients.size !== idSet2.clients.size) return false
|
||||
for (const [client, _items1] of idSet1.clients.entries()) {
|
||||
const items1 = _items1.getIds()
|
||||
const items2 = idSet2.clients.get(client)?.getIds()
|
||||
t.assert(items2 !== undefined && items1.length === items2.length)
|
||||
for (let i = 0; i < items1.length; i++) {
|
||||
const di1 = items1[i]
|
||||
const di2 = /** @type {Array<d.IdRange>} */ (items2)[i]
|
||||
t.assert(di1.clock === di2.clock && di1.len === di2.len)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {t.TestCase} _tc
|
||||
*/
|
||||
|
||||
@@ -304,6 +304,26 @@ export const init = (tc, { users = 5 } = {}, initTestObject) => {
|
||||
return /** @type {any} */ (result)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Y.IdSet} idSet1
|
||||
* @param {Y.IdSet} idSet2
|
||||
*/
|
||||
export const compareIdSets = (idSet1, idSet2) => {
|
||||
if (idSet1.clients.size !== idSet2.clients.size) return false
|
||||
for (const [client, _items1] of idSet1.clients.entries()) {
|
||||
const items1 = _items1.getIds()
|
||||
const items2 = idSet2.clients.get(client)?.getIds()
|
||||
t.assert(items2 !== undefined && items1.length === items2.length)
|
||||
for (let i = 0; i < items1.length; i++) {
|
||||
const di1 = items1[i]
|
||||
const di2 = /** @type {Array<import('../src/utils/IdSet.js').IdRange>} */ (items2)[i]
|
||||
t.assert(di1.clock === di2.clock && di1.len === di2.len)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 1. reconnect and flush all
|
||||
* 2. user 0 gc
|
||||
@@ -366,6 +386,9 @@ export const compare = users => {
|
||||
compareStructStores(users[i].store, users[i + 1].store)
|
||||
t.compare(Y.encodeSnapshot(Y.snapshot(users[i])), Y.encodeSnapshot(Y.snapshot(users[i + 1])))
|
||||
}
|
||||
users.forEach(user => {
|
||||
compareIdSets(user.store.ds, Y.createDeleteSetFromStructStore(user.store))
|
||||
})
|
||||
users.map(u => u.destroy())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user