Delete all children of ItemType when it is deleted

This commit is contained in:
Kevin Jahns 2019-04-26 12:29:28 +02:00
parent 1d0f9faa91
commit 21d86cd2be
6 changed files with 44 additions and 25 deletions

View File

@ -425,6 +425,7 @@ export class AbstractItem extends AbstractStruct {
* @private * @private
*/ */
gc (transaction, store) { gc (transaction, store) {
this.delete(transaction)
let r let r
if (this.parent._item !== null && this.parent._item.deleted) { if (this.parent._item !== null && this.parent._item.deleted) {
r = new GC(this.id, this.length) r = new GC(this.id, this.length)

View File

@ -100,9 +100,21 @@ export class ItemType extends AbstractItem {
* @private * @private
*/ */
delete (transaction) { delete (transaction) {
super.delete(transaction) if (!this.deleted) {
transaction.changed.delete(this.type) super.delete(transaction)
transaction.changedParentTypes.delete(this.type) let item = this.type._start
while (item !== null) {
if (!item.deleted) {
item.delete(transaction)
}
item = item.right
}
this.type._map.forEach(item => {
item.delete(transaction)
})
transaction.changed.delete(this.type)
transaction.changedParentTypes.delete(this.type)
}
} }
/** /**

View File

@ -454,13 +454,10 @@ export const typeArrayDelete = (transaction, parent, index, length) => {
if (length === 0) { return } if (length === 0) { return }
let n = parent._start let n = parent._start
// compute the first item to be deleted // compute the first item to be deleted
for (; n !== null; n = n.right) { for (; n !== null && index > 0; n = n.right) {
if (!n.deleted && n.countable) { if (!n.deleted && n.countable) {
if (index <= n.length) { if (index < n.length) {
if (index < n.length && index > 0) { getItemCleanStart(transaction, transaction.y.store, createID(n.id.client, n.id.clock + index))
n = getItemCleanStart(transaction, transaction.y.store, createID(n.id.client, n.id.clock + index))
}
break
} }
index -= n.length index -= n.length
} }

View File

@ -165,9 +165,9 @@ export const transact = (y, f) => {
// transaction cleanup // transaction cleanup
const store = transaction.y.store const store = transaction.y.store
const ds = transaction.deleteSet const ds = transaction.deleteSet
// replace deleted items with ItemDeleted / GC
sortAndMergeDeleteSet(ds) sortAndMergeDeleteSet(ds)
y.emit('afterTransaction', [transaction, y]) y.emit('afterTransaction', [transaction, y])
// replace deleted items with ItemDeleted / GC
for (const [client, deleteItems] of ds.clients) { for (const [client, deleteItems] of ds.clients) {
/** /**
* @type {Array<AbstractStruct>} * @type {Array<AbstractStruct>}

View File

@ -270,8 +270,5 @@ export const createAbsolutePositionFromCursor = (cursor, y) => {
* @function * @function
*/ */
export const compareCursors = (a, b) => a === b || ( export const compareCursors = (a, b) => a === b || (
a !== null && b !== null && a.tname === b.tname && ( a !== null && b !== null && a.tname === b.tname && compareIDs(a.item, b.item) && compareIDs(a.type, b.type)
(a.item !== null && b.item !== null && compareIDs(a.item, b.item)) ||
(a.type !== null && b.type !== null && compareIDs(a.type, b.type))
)
) )

View File

@ -230,11 +230,13 @@ export class TestConnector {
} }
/** /**
* @template T
* @param {t.TestCase} tc * @param {t.TestCase} tc
* @param {{users?:number}} conf * @param {{users?:number}} conf
* @return {{testConnector:TestConnector,users:Array<TestYInstance>,array0:Y.Array<any>,array1:Y.Array<any>,array2:Y.Array<any>,map0:Y.Map<any>,map1:Y.Map<any>,map2:Y.Map<any>,map3:Y.Map<any>,text0:Y.Text,text1:Y.Text,text2:Y.Text,xml0:Y.XmlElement,xml1:Y.XmlElement,xml2:Y.XmlElement}} * @param {InitTestObjectCallback<T>} initTestObject
* @return {{testObjects:Array<any>,testConnector:TestConnector,users:Array<TestYInstance>,array0:Y.Array<any>,array1:Y.Array<any>,array2:Y.Array<any>,map0:Y.Map<any>,map1:Y.Map<any>,map2:Y.Map<any>,map3:Y.Map<any>,text0:Y.Text,text1:Y.Text,text2:Y.Text,xml0:Y.XmlElement,xml1:Y.XmlElement,xml2:Y.XmlElement}}
*/ */
export const init = (tc, { users = 5 } = {}) => { export const init = (tc, { users = 5 } = {}, initTestObject) => {
/** /**
* @type {Object<string,any>} * @type {Object<string,any>}
*/ */
@ -254,6 +256,7 @@ export const init = (tc, { users = 5 } = {}) => {
result['text' + i] = y.get('text', Y.Text) result['text' + i] = y.get('text', Y.Text)
} }
testConnector.syncAll() testConnector.syncAll()
result.testObjects = result.users.map(initTestObject)
// @ts-ignore // @ts-ignore
return result return result
} }
@ -365,15 +368,24 @@ export const compareDS = (ds1, ds2) => {
} }
/** /**
* @param {t.TestCase} tc * @template T
* @param {Array<function(TestYInstance,prng.PRNG):void>} mods * @callback InitTestObjectCallback
* @param {number} iterations * @param {TestYInstance} y
* @return {T}
*/ */
export const applyRandomTests = (tc, mods, iterations) => {
/**
* @template T
* @param {t.TestCase} tc
* @param {Array<function(TestYInstance,prng.PRNG,T):void>} mods
* @param {number} iterations
* @param {InitTestObjectCallback<T>} [initTestObject]
*/
export const applyRandomTests = (tc, mods, iterations, initTestObject) => {
const gen = tc.prng const gen = tc.prng
const result = init(tc, { users: 5 }) const result = init(tc, { users: 5 }, initTestObject || (() => null))
const { testConnector, users } = result const { testConnector, users } = result
for (var i = 0; i < iterations; i++) { for (let i = 0; i < iterations; i++) {
if (prng.int31(gen, 0, 100) <= 2) { if (prng.int31(gen, 0, 100) <= 2) {
// 2% chance to disconnect/reconnect a random user // 2% chance to disconnect/reconnect a random user
if (prng.bool(gen)) { if (prng.bool(gen)) {
@ -388,9 +400,9 @@ export const applyRandomTests = (tc, mods, iterations) => {
// 50% chance to flush a random message // 50% chance to flush a random message
testConnector.flushRandomMessage() testConnector.flushRandomMessage()
} }
let user = prng.oneOf(gen, users) const user = prng.int31(gen, 0, users.length - 1)
var test = prng.oneOf(gen, mods) const test = prng.oneOf(gen, mods)
test(user, gen) test(users[user], gen, result.testObjects[user])
} }
compare(users) compare(users)
return result return result