mirror of
https://github.com/yjs/yjs.git
synced 2025-12-16 11:47:46 +01:00
fix gc splice issues happening in y-quill
This commit is contained in:
@@ -76,9 +76,9 @@ export class ContentAny {
|
||||
*/
|
||||
delete (transaction) {}
|
||||
/**
|
||||
* @param {StructStore} store
|
||||
* @param {Transaction} _tr
|
||||
*/
|
||||
gc (store) {}
|
||||
gc (_tr) {}
|
||||
/**
|
||||
* @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
|
||||
* @param {number} offset
|
||||
|
||||
@@ -66,9 +66,9 @@ export class ContentBinary {
|
||||
*/
|
||||
delete (transaction) {}
|
||||
/**
|
||||
* @param {StructStore} store
|
||||
* @param {Transaction} _tr
|
||||
*/
|
||||
gc (store) {}
|
||||
gc (_tr) {}
|
||||
/**
|
||||
* @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
|
||||
* @param {number} offset
|
||||
|
||||
@@ -68,13 +68,13 @@ export class ContentDeleted {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Transaction} transaction
|
||||
* @param {Transaction} _transaction
|
||||
*/
|
||||
delete (transaction) {}
|
||||
delete (_transaction) {}
|
||||
/**
|
||||
* @param {StructStore} store
|
||||
* @param {Transaction} _tr
|
||||
*/
|
||||
gc (store) {}
|
||||
gc (_tr) {}
|
||||
/**
|
||||
* @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
|
||||
* @param {number} offset
|
||||
|
||||
@@ -110,9 +110,9 @@ export class ContentDoc {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {StructStore} store
|
||||
* @param {Transaction} _tr
|
||||
*/
|
||||
gc (store) { }
|
||||
gc (_tr) {}
|
||||
|
||||
/**
|
||||
* @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
|
||||
|
||||
@@ -69,9 +69,9 @@ export class ContentEmbed {
|
||||
*/
|
||||
delete (transaction) {}
|
||||
/**
|
||||
* @param {StructStore} store
|
||||
* @param {Transaction} _tr
|
||||
*/
|
||||
gc (store) {}
|
||||
gc (_tr) {}
|
||||
/**
|
||||
* @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
|
||||
* @param {number} offset
|
||||
|
||||
@@ -77,9 +77,9 @@ export class ContentFormat {
|
||||
*/
|
||||
delete (_transaction) {}
|
||||
/**
|
||||
* @param {StructStore} _store
|
||||
* @param {Transaction} _tr
|
||||
*/
|
||||
gc (_store) {}
|
||||
gc (_tr) {}
|
||||
/**
|
||||
* @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
|
||||
* @param {number} _offset
|
||||
|
||||
@@ -73,9 +73,9 @@ export class ContentJSON {
|
||||
*/
|
||||
delete (transaction) {}
|
||||
/**
|
||||
* @param {StructStore} store
|
||||
* @param {Transaction} _tr
|
||||
*/
|
||||
gc (store) {}
|
||||
gc (_tr) {}
|
||||
/**
|
||||
* @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
|
||||
* @param {number} offset
|
||||
|
||||
@@ -84,9 +84,9 @@ export class ContentString {
|
||||
*/
|
||||
delete (transaction) {}
|
||||
/**
|
||||
* @param {StructStore} store
|
||||
* @param {Transaction} _tr
|
||||
*/
|
||||
gc (store) {}
|
||||
gc (_tr) {}
|
||||
/**
|
||||
* @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
|
||||
* @param {number} offset
|
||||
|
||||
@@ -128,18 +128,18 @@ export class ContentType {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {StructStore} store
|
||||
* @param {Transaction} tr
|
||||
*/
|
||||
gc (store) {
|
||||
gc (tr) {
|
||||
let item = this.type._start
|
||||
while (item !== null) {
|
||||
item.gc(store, true)
|
||||
item.gc(tr, true)
|
||||
item = item.right
|
||||
}
|
||||
this.type._start = null
|
||||
this.type._map.forEach(/** @param {Item | null} item */ (item) => {
|
||||
while (item !== null) {
|
||||
item.gc(store, true)
|
||||
item.gc(tr, true)
|
||||
item = item.left
|
||||
}
|
||||
})
|
||||
@@ -148,9 +148,9 @@ export class ContentType {
|
||||
|
||||
/**
|
||||
* @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
|
||||
* @param {number} offset
|
||||
* @param {number} _offset
|
||||
*/
|
||||
write (encoder, offset) {
|
||||
write (encoder, _offset) {
|
||||
this.type._write(encoder)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ import {
|
||||
addStruct,
|
||||
addStructToIdSet,
|
||||
addToIdSet,
|
||||
UpdateEncoderV1, UpdateEncoderV2, StructStore, Transaction, // eslint-disable-line
|
||||
createID
|
||||
UpdateEncoderV1, UpdateEncoderV2, StructStore, Transaction // eslint-disable-line
|
||||
} from '../internals.js'
|
||||
|
||||
export const structGCRefNumber = 0
|
||||
@@ -55,20 +54,23 @@ export class GC extends AbstractStruct {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Transaction} transaction
|
||||
* @param {StructStore} store
|
||||
* @param {Transaction} _transaction
|
||||
* @param {StructStore} _store
|
||||
* @return {null | number}
|
||||
*/
|
||||
getMissing (transaction, store) {
|
||||
getMissing (_transaction, _store) {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} diff
|
||||
* gc structs can't be spliced.
|
||||
*
|
||||
* If this feature is required in the future, then need to try to merge this struct after
|
||||
* transaction.
|
||||
*
|
||||
* @param {number} _diff
|
||||
*/
|
||||
splice (diff) {
|
||||
const other = new GC(createID(this.id.client, this.id.clock + diff), this.length - diff)
|
||||
this.length = diff
|
||||
return other
|
||||
splice (_diff) {
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,16 +634,16 @@ export class Item extends AbstractStruct {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {StructStore} store
|
||||
* @param {Transaction} tr
|
||||
* @param {boolean} parentGCd
|
||||
*/
|
||||
gc (store, parentGCd) {
|
||||
gc (tr, parentGCd) {
|
||||
if (!this.deleted) {
|
||||
throw error.unexpectedCase()
|
||||
}
|
||||
this.content.gc(store)
|
||||
this.content.gc(tr)
|
||||
if (parentGCd) {
|
||||
replaceStruct(store, this, new GC(this.id, this.length))
|
||||
replaceStruct(tr, this, new GC(this.id, this.length))
|
||||
} else {
|
||||
this.content = new ContentDeleted(this.length)
|
||||
}
|
||||
@@ -799,9 +799,9 @@ export class AbstractContent {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {StructStore} _store
|
||||
* @param {Transaction} _transaction
|
||||
*/
|
||||
gc (_store) {
|
||||
gc (_transaction) {
|
||||
throw error.methodUnimplemented()
|
||||
}
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ export const getItem = /** @type {function(StructStore,ID):Item} */ (find)
|
||||
export const findIndexCleanStart = (transaction, structs, clock) => {
|
||||
const index = findIndexSS(structs, clock)
|
||||
const struct = structs[index]
|
||||
if (struct.id.clock < clock) {
|
||||
if (struct.id.clock < clock && struct.constructor !== GC) {
|
||||
structs.splice(index + 1, 0, struct instanceof Item ? splitItem(transaction, struct, clock - struct.id.clock) : struct.splice(clock - struct.id.clock))
|
||||
return index + 1
|
||||
}
|
||||
@@ -247,16 +247,17 @@ export const getItemCleanEnd = (transaction, store, id) => {
|
||||
|
||||
/**
|
||||
* Replace `item` with `newitem` in store
|
||||
* @param {StructStore} store
|
||||
* @param {Transaction} tr
|
||||
* @param {GC|Item} struct
|
||||
* @param {GC|Item} newStruct
|
||||
*
|
||||
* @private
|
||||
* @function
|
||||
*/
|
||||
export const replaceStruct = (store, struct, newStruct) => {
|
||||
const structs = /** @type {Array<GC|Item>} */ (store.clients.get(struct.id.client))
|
||||
export const replaceStruct = (tr, struct, newStruct) => {
|
||||
const structs = /** @type {Array<GC|Item>} */ (tr.doc.store.clients.get(struct.id.client))
|
||||
structs[findIndexSS(structs, struct.id.clock)] = newStruct
|
||||
tr._mergeStructs.push(newStruct)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,8 +10,7 @@ import {
|
||||
generateNewClientId,
|
||||
createID,
|
||||
cleanupYTextAfterTransaction,
|
||||
IdSet, UpdateEncoderV1, UpdateEncoderV2, GC, StructStore, AbstractType, AbstractStruct, YEvent, Doc,
|
||||
diffIdSet, // eslint-disable-line
|
||||
IdSet, UpdateEncoderV1, UpdateEncoderV2, GC, StructStore, AbstractType, AbstractStruct, YEvent, Doc
|
||||
// insertIntoIdSet
|
||||
} from '../internals.js'
|
||||
|
||||
@@ -239,14 +238,14 @@ const tryToMergeWithLefts = (structs, pos) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Transaction} tr
|
||||
* @param {IdSet} ds
|
||||
* @param {StructStore} store
|
||||
* @param {function(Item):boolean} gcFilter
|
||||
*/
|
||||
const tryGcDeleteSet = (ds, store, gcFilter) => {
|
||||
const tryGcDeleteSet = (tr, ds, gcFilter) => {
|
||||
for (const [client, _deleteItems] of ds.clients.entries()) {
|
||||
const deleteItems = _deleteItems.getIds()
|
||||
const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
|
||||
const structs = /** @type {Array<GC|Item>} */ (tr.doc.store.clients.get(client))
|
||||
for (let di = deleteItems.length - 1; di >= 0; di--) {
|
||||
const deleteItem = deleteItems[di]
|
||||
const endDeleteItemClock = deleteItem.clock + deleteItem.len
|
||||
@@ -260,7 +259,7 @@ const tryGcDeleteSet = (ds, store, gcFilter) => {
|
||||
break
|
||||
}
|
||||
if (struct instanceof Item && struct.deleted && !struct.keep && gcFilter(struct)) {
|
||||
struct.gc(store, false)
|
||||
struct.gc(tr, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,7 +270,7 @@ const tryGcDeleteSet = (ds, store, gcFilter) => {
|
||||
* @param {IdSet} ds
|
||||
* @param {StructStore} store
|
||||
*/
|
||||
const tryMergeDeleteSet = (ds, store) => {
|
||||
const tryMerge = (ds, store) => {
|
||||
// try to merge deleted / gc'd items
|
||||
// merge from right to left for better efficiency and so we don't miss any merge targets
|
||||
ds.clients.forEach((_deleteItems, client) => {
|
||||
@@ -293,13 +292,13 @@ const tryMergeDeleteSet = (ds, store) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {IdSet} ds
|
||||
* @param {StructStore} store
|
||||
* @param {Transaction} tr
|
||||
* @param {IdSet} idset
|
||||
* @param {function(Item):boolean} gcFilter
|
||||
*/
|
||||
export const tryGc = (ds, store, gcFilter) => {
|
||||
tryGcDeleteSet(ds, store, gcFilter)
|
||||
tryMergeDeleteSet(ds, store)
|
||||
export const tryGc = (tr, idset, gcFilter) => {
|
||||
tryGcDeleteSet(tr, idset, gcFilter)
|
||||
tryMerge(idset, tr.doc.store)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -367,9 +366,9 @@ const cleanupTransactions = (transactionCleanups, i) => {
|
||||
// Replace deleted items with ItemDeleted / GC.
|
||||
// This is where content is actually remove from the Yjs Doc.
|
||||
if (doc.gc) {
|
||||
tryGcDeleteSet(ds, store, doc.gcFilter)
|
||||
tryGcDeleteSet(transaction, ds, doc.gcFilter)
|
||||
}
|
||||
tryMergeDeleteSet(ds, store)
|
||||
tryMerge(ds, store)
|
||||
|
||||
// on all affected store.clients props, try to merge
|
||||
transaction.insertSet.clients.forEach((ids, client) => {
|
||||
|
||||
Reference in New Issue
Block a user