prelim gc
This commit is contained in:
parent
32207cbca0
commit
d915c8dd13
@ -13,18 +13,18 @@ export function deleteItemRange (y, user, clock, range) {
|
|||||||
if (item !== null) {
|
if (item !== null) {
|
||||||
if (!item._deleted) {
|
if (!item._deleted) {
|
||||||
item._splitAt(y, range)
|
item._splitAt(y, range)
|
||||||
item._delete(y, createDelete)
|
item._delete(y, createDelete, true)
|
||||||
}
|
}
|
||||||
let itemLen = item._length
|
let itemLen = item._length
|
||||||
range -= itemLen
|
range -= itemLen
|
||||||
clock += itemLen
|
clock += itemLen
|
||||||
if (range > 0) {
|
if (range > 0) {
|
||||||
let node = y.os.findNode(new ID(user, clock))
|
let node = y.os.findNode(new ID(user, clock))
|
||||||
while (node !== null && range > 0 && node.val._id.equals(new ID(user, clock))) {
|
while (node !== null && node.val !== null && range > 0 && node.val._id.equals(new ID(user, clock))) {
|
||||||
const nodeVal = node.val
|
const nodeVal = node.val
|
||||||
if (!nodeVal._deleted) {
|
if (!nodeVal._deleted) {
|
||||||
nodeVal._splitAt(y, range)
|
nodeVal._splitAt(y, range)
|
||||||
nodeVal._delete(y, createDelete)
|
nodeVal._delete(y, createDelete, true)
|
||||||
}
|
}
|
||||||
const nodeLen = nodeVal._length
|
const nodeLen = nodeVal._length
|
||||||
range -= nodeLen
|
range -= nodeLen
|
||||||
|
44
src/Struct/GC.js
Normal file
44
src/Struct/GC.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
export default class GC {
|
||||||
|
constructor () {
|
||||||
|
this._id = null
|
||||||
|
this._length = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
get _deleted () {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
integrate () {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the properties of this type to binary and write it to an
|
||||||
|
* BinaryEncoder.
|
||||||
|
*
|
||||||
|
* This is called when this Item is sent to a remote peer.
|
||||||
|
*
|
||||||
|
* @param {BinaryEncoder} encoder The encoder to write data to.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_toBinary (encoder) {
|
||||||
|
encoder.writeUint8(getStructReference(this.constructor))
|
||||||
|
encoder.writeID(this._id)
|
||||||
|
encoder.writeVarUint(this._length)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the next Item in a Decoder and fill this Item with the read data.
|
||||||
|
*
|
||||||
|
* This is called when data is received from a remote peer.
|
||||||
|
*
|
||||||
|
* @param {Y} y The Yjs instance that this Item belongs to.
|
||||||
|
* @param {BinaryDecoder} decoder The decoder object to read data from.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_fromBinary (y, decoder) {
|
||||||
|
this._id = decoder.readID()
|
||||||
|
this._length = decoder.readVarUint()
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ import ID from '../Util/ID/ID.js'
|
|||||||
import { RootFakeUserID } from '../Util/ID/RootID.js'
|
import { RootFakeUserID } from '../Util/ID/RootID.js'
|
||||||
import Delete from './Delete.js'
|
import Delete from './Delete.js'
|
||||||
import { transactionTypeChanged } from '../Transaction.js'
|
import { transactionTypeChanged } from '../Transaction.js'
|
||||||
|
import GC from './GC.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@ -220,7 +221,7 @@ export default class Item {
|
|||||||
_delete (y, createDelete = true) {
|
_delete (y, createDelete = true) {
|
||||||
if (!this._deleted) {
|
if (!this._deleted) {
|
||||||
this._deleted = true
|
this._deleted = true
|
||||||
y.ds.markDeleted(this._id, this._length)
|
y.ds.mark(this._id, this._length, false)
|
||||||
let del = new Delete()
|
let del = new Delete()
|
||||||
del._targetID = this._id
|
del._targetID = this._id
|
||||||
del._length = this._length
|
del._length = this._length
|
||||||
@ -236,6 +237,32 @@ export default class Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_gcChildren (y) {}
|
||||||
|
|
||||||
|
_gc (y) {
|
||||||
|
y.ds.mark(this._id, this._length, true)
|
||||||
|
const gc = new GC()
|
||||||
|
gc._id = this._id
|
||||||
|
gc._length = this._length
|
||||||
|
y.os.delete(this._id)
|
||||||
|
let n = y.os.put(gc)
|
||||||
|
const prev = n.prev().val
|
||||||
|
if (prev !== null && prev.constructor === GC && prev._id.user === n.val._id.user && prev._id.clock + prev._length === n.val._id.clock) {
|
||||||
|
// TODO: do merging for all items!
|
||||||
|
prev._length += n.val._length
|
||||||
|
y.os.delete(n.val._id)
|
||||||
|
n = prev
|
||||||
|
}
|
||||||
|
if (n.val) {
|
||||||
|
n = n.val
|
||||||
|
}
|
||||||
|
const next = y.os.findNext(n._id)
|
||||||
|
if (next !== null && next.constructor === GC && next._id.user === n._id.user && next._id.clock === n._id.clock + n._length) {
|
||||||
|
n._length += next._length
|
||||||
|
y.os.delete(n._id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called right before this Item receives any children.
|
* This is called right before this Item receives any children.
|
||||||
* It can be overwritten to apply pending changes before applying remote changes
|
* It can be overwritten to apply pending changes before applying remote changes
|
||||||
|
@ -30,6 +30,14 @@ export function getListItemIDByPosition (type, i) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function gcChildren (y, item) {
|
||||||
|
while (item !== null) {
|
||||||
|
item._delete(y, false, true)
|
||||||
|
item._gc(y)
|
||||||
|
item = item._right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract Yjs Type class
|
* Abstract Yjs Type class
|
||||||
*/
|
*/
|
||||||
@ -184,6 +192,20 @@ export default class Type extends Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_gcChildren (y) {
|
||||||
|
gcChildren(y, this._start)
|
||||||
|
this._start = null
|
||||||
|
this._map.forEach(item => {
|
||||||
|
gcChildren(y, item)
|
||||||
|
})
|
||||||
|
this._map = new Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
_gc (y) {
|
||||||
|
this._gcChildren(y)
|
||||||
|
super._gc(y)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* Mark this Item as deleted.
|
* Mark this Item as deleted.
|
||||||
@ -192,22 +214,25 @@ export default class Type extends Item {
|
|||||||
* @param {boolean} createDelete Whether to propagate a message that this
|
* @param {boolean} createDelete Whether to propagate a message that this
|
||||||
* Type was deleted.
|
* Type was deleted.
|
||||||
*/
|
*/
|
||||||
_delete (y, createDelete) {
|
_delete (y, createDelete, gcChildren = true) {
|
||||||
super._delete(y, createDelete)
|
super._delete(y, createDelete, gcChildren)
|
||||||
y._transaction.changedTypes.delete(this)
|
y._transaction.changedTypes.delete(this)
|
||||||
// delete map types
|
// delete map types
|
||||||
for (let value of this._map.values()) {
|
for (let value of this._map.values()) {
|
||||||
if (value instanceof Item && !value._deleted) {
|
if (value instanceof Item && !value._deleted) {
|
||||||
value._delete(y, false)
|
value._delete(y, false, gcChildren)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// delete array types
|
// delete array types
|
||||||
let t = this._start
|
let t = this._start
|
||||||
while (t !== null) {
|
while (t !== null) {
|
||||||
if (!t._deleted) {
|
if (!t._deleted) {
|
||||||
t._delete(y, false)
|
t._delete(y, false, gcChildren)
|
||||||
}
|
}
|
||||||
t = t._right
|
t = t._right
|
||||||
}
|
}
|
||||||
|
if (gcChildren) {
|
||||||
|
this._gcChildren(y)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,8 +126,8 @@ export default class YXmlFragment extends YArray {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_delete (y, createDelete) {
|
_delete (y, createDelete, gcChildren) {
|
||||||
super._delete(y, createDelete)
|
super._delete(y, createDelete, gcChildren)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,7 +36,7 @@ export default class YXmlText extends YText {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_delete (y, createDelete) {
|
_delete (y, createDelete, gcChildren) {
|
||||||
super._delete(y, createDelete)
|
super._delete(y, createDelete, gcChildren)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import ItemJSON from '../Struct/ItemJSON.js'
|
|||||||
import ItemString from '../Struct/ItemString.js'
|
import ItemString from '../Struct/ItemString.js'
|
||||||
import ItemFormat from '../Struct/ItemFormat.js'
|
import ItemFormat from '../Struct/ItemFormat.js'
|
||||||
import ItemEmbed from '../Struct/ItemEmbed.js'
|
import ItemEmbed from '../Struct/ItemEmbed.js'
|
||||||
|
import GC from '../Struct/GC.js'
|
||||||
|
|
||||||
const structs = new Map()
|
const structs = new Map()
|
||||||
const references = new Map()
|
const references = new Map()
|
||||||
@ -54,3 +55,5 @@ registerStruct(6, YXmlFragment)
|
|||||||
registerStruct(7, YXmlElement)
|
registerStruct(7, YXmlElement)
|
||||||
registerStruct(8, YXmlText)
|
registerStruct(8, YXmlText)
|
||||||
registerStruct(9, YXmlHook)
|
registerStruct(9, YXmlHook)
|
||||||
|
|
||||||
|
registerStruct(12, GC)
|
Loading…
x
Reference in New Issue
Block a user