parent
90f2a06b5e
commit
c77dedb68d
@ -108,7 +108,7 @@ export class ContentType {
|
|||||||
while (item !== null) {
|
while (item !== null) {
|
||||||
if (!item.deleted) {
|
if (!item.deleted) {
|
||||||
item.delete(transaction)
|
item.delete(transaction)
|
||||||
} else {
|
} else if (item.id.clock < (transaction.beforeState.get(item.id.client) || 0)) {
|
||||||
// This will be gc'd later and we want to merge it if possible
|
// This will be gc'd later and we want to merge it if possible
|
||||||
// We try to merge all deleted items after each transaction,
|
// We try to merge all deleted items after each transaction,
|
||||||
// but we have no knowledge about that this needs to be merged
|
// but we have no knowledge about that this needs to be merged
|
||||||
@ -120,7 +120,7 @@ export class ContentType {
|
|||||||
this.type._map.forEach(item => {
|
this.type._map.forEach(item => {
|
||||||
if (!item.deleted) {
|
if (!item.deleted) {
|
||||||
item.delete(transaction)
|
item.delete(transaction)
|
||||||
} else {
|
} else if (item.id.clock < (transaction.beforeState.get(item.id.client) || 0)) {
|
||||||
// same as above
|
// same as above
|
||||||
transaction._mergeStructs.push(item)
|
transaction._mergeStructs.push(item)
|
||||||
}
|
}
|
||||||
|
@ -166,18 +166,29 @@ export const addChangedTypeToTransaction = (transaction, type, parentSub) => {
|
|||||||
/**
|
/**
|
||||||
* @param {Array<AbstractStruct>} structs
|
* @param {Array<AbstractStruct>} structs
|
||||||
* @param {number} pos
|
* @param {number} pos
|
||||||
|
* @return {number} # of merged structs
|
||||||
*/
|
*/
|
||||||
const tryToMergeWithLeft = (structs, pos) => {
|
const tryToMergeWithLefts = (structs, pos) => {
|
||||||
const left = structs[pos - 1]
|
let right = structs[pos]
|
||||||
const right = structs[pos]
|
let left = structs[pos - 1]
|
||||||
if (left.deleted === right.deleted && left.constructor === right.constructor) {
|
let i = pos
|
||||||
if (left.mergeWith(right)) {
|
for (; i > 0; right = left, left = structs[--i - 1]) {
|
||||||
structs.splice(pos, 1)
|
if (left.deleted === right.deleted && left.constructor === right.constructor) {
|
||||||
if (right instanceof Item && right.parentSub !== null && /** @type {AbstractType<any>} */ (right.parent)._map.get(right.parentSub) === right) {
|
if (left.mergeWith(right)) {
|
||||||
/** @type {AbstractType<any>} */ (right.parent)._map.set(right.parentSub, /** @type {Item} */ (left))
|
if (right instanceof Item && right.parentSub !== null && /** @type {AbstractType<any>} */ (right.parent)._map.get(right.parentSub) === right) {
|
||||||
|
/** @type {AbstractType<any>} */ (right.parent)._map.set(right.parentSub, /** @type {Item} */ (left))
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
const merged = pos - i
|
||||||
|
if (merged) {
|
||||||
|
// remove all merged structs from the array
|
||||||
|
structs.splice(pos + 1 - merged, merged)
|
||||||
|
}
|
||||||
|
return merged
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,9 +235,9 @@ const tryMergeDeleteSet = (ds, store) => {
|
|||||||
for (
|
for (
|
||||||
let si = mostRightIndexToCheck, struct = structs[si];
|
let si = mostRightIndexToCheck, struct = structs[si];
|
||||||
si > 0 && struct.id.clock >= deleteItem.clock;
|
si > 0 && struct.id.clock >= deleteItem.clock;
|
||||||
struct = structs[--si]
|
struct = structs[si]
|
||||||
) {
|
) {
|
||||||
tryToMergeWithLeft(structs, si)
|
si -= 1 + tryToMergeWithLefts(structs, si)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -318,23 +329,25 @@ const cleanupTransactions = (transactionCleanups, i) => {
|
|||||||
const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
|
const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
|
||||||
// we iterate from right to left so we can safely remove entries
|
// we iterate from right to left so we can safely remove entries
|
||||||
const firstChangePos = math.max(findIndexSS(structs, beforeClock), 1)
|
const firstChangePos = math.max(findIndexSS(structs, beforeClock), 1)
|
||||||
for (let i = structs.length - 1; i >= firstChangePos; i--) {
|
for (let i = structs.length - 1; i >= firstChangePos;) {
|
||||||
tryToMergeWithLeft(structs, i)
|
i -= 1 + tryToMergeWithLefts(structs, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// try to merge mergeStructs
|
// try to merge mergeStructs
|
||||||
// @todo: it makes more sense to transform mergeStructs to a DS, sort it, and merge from right to left
|
// @todo: it makes more sense to transform mergeStructs to a DS, sort it, and merge from right to left
|
||||||
// but at the moment DS does not handle duplicates
|
// but at the moment DS does not handle duplicates
|
||||||
for (let i = 0; i < mergeStructs.length; i++) {
|
for (let i = mergeStructs.length - 1; i >= 0; i--) {
|
||||||
const { client, clock } = mergeStructs[i].id
|
const { client, clock } = mergeStructs[i].id
|
||||||
const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
|
const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
|
||||||
const replacedStructPos = findIndexSS(structs, clock)
|
const replacedStructPos = findIndexSS(structs, clock)
|
||||||
if (replacedStructPos + 1 < structs.length) {
|
if (replacedStructPos + 1 < structs.length) {
|
||||||
tryToMergeWithLeft(structs, replacedStructPos + 1)
|
if (tryToMergeWithLefts(structs, replacedStructPos + 1) > 1) {
|
||||||
|
continue // no need to perform next check, both are already merged
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (replacedStructPos > 0) {
|
if (replacedStructPos > 0) {
|
||||||
tryToMergeWithLeft(structs, replacedStructPos)
|
tryToMergeWithLefts(structs, replacedStructPos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!transaction.local && transaction.afterState.get(doc.clientID) !== transaction.beforeState.get(doc.clientID)) {
|
if (!transaction.local && transaction.afterState.get(doc.clientID) !== transaction.beforeState.get(doc.clientID)) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user