Skip to content

Commit

Permalink
Reduce number of children filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
skhugh committed May 10, 2024
1 parent f6b04c0 commit efe3bf9
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 9 deletions.
16 changes: 11 additions & 5 deletions yorkie/src/main/kotlin/dev/yorkie/document/crdt/CrdtTree.kt
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,13 @@ internal data class CrdtTreeNode private constructor(
get() = id.createdAt

var removedAt: TimeTicket? = null
private set
private set(value) {
field = value
if (field != null) {
parent?.childRemoved()
return
}
}

override val isRemoved: Boolean
get() = removedAt != null
Expand Down Expand Up @@ -835,16 +841,16 @@ internal data class CrdtTreeNode private constructor(
fun deepCopy(): CrdtTreeNode {
return copy(
_value = _value,
childNodes = childrenInternal.map { child ->
childNodes = allChildren.map { child ->
child.deepCopy()
}.toMutableList(),
_attributes = _attributes.deepCopy(),
).also {
it.size = size
it.removedAt = removedAt
it.childrenInternal.forEach { child ->
it.allChildren.forEach { child ->
child.parent = it
}
it.size = size
it.removedAt = removedAt
it.insPrevID = insPrevID
it.insNextID = insNextID
}
Expand Down
31 changes: 27 additions & 4 deletions yorkie/src/main/kotlin/dev/yorkie/util/IndexTree.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package dev.yorkie.util

import androidx.annotation.VisibleForTesting
import dev.yorkie.document.time.TimeTicket

/**
Expand Down Expand Up @@ -215,12 +214,14 @@ internal class IndexTree<T : IndexTreeNode<T>>(val root: T) {
node = parent
mutableListOf(sizeOfLeftSiblings + treePos.offset)
}

node.hasTextChild -> {
// TODO(hackerwins): The function does not consider the situation
// where Element and Text nodes are mixed in the Element's Children.
val sizeOfLeftSiblings = addSizeOfLeftSiblings(node, treePos.offset)
mutableListOf(sizeOfLeftSiblings)
}

else -> {
mutableListOf(treePos.offset)
}
Expand Down Expand Up @@ -372,7 +373,7 @@ internal data class TreePos<T : IndexTreeNode<T>>(
internal abstract class IndexTreeNode<T : IndexTreeNode<T>>(children: MutableList<T>) {
abstract val type: String

protected val childrenInternal: MutableList<T> = children
private val childrenInternal: MutableList<T> = children

val isText
get() = type == DEFAULT_TEXT_TYPE
Expand All @@ -397,19 +398,31 @@ internal abstract class IndexTreeNode<T : IndexTreeNode<T>>(children: MutableLis
return parent?.children?.getOrNull(offset + 1)
}

private var canUseCachedChildren = false
private var cachedChildren: List<T> = emptyList()

/**
* Returns the children of the node.
* Tombstone nodes remain awhile in the tree during editing.
* They will be removed after the editing is done.
* So, we need to filter out the tombstone nodes to get the real children.
*/
val children: List<T>
get() = childrenInternal.filterNot { it.isRemoved }
get() {
return if (canUseCachedChildren) {
cachedChildren
} else {
cachedChildren = childrenInternal.filterNotTo(ArrayList(childrenInternal.size)) {
it.isRemoved
}
canUseCachedChildren = true
cachedChildren
}
}

/**
* Returns the children of the node including tombstones.
*/
@VisibleForTesting
val allChildren: List<T>
get() = childrenInternal.toList()

Expand Down Expand Up @@ -461,6 +474,7 @@ internal abstract class IndexTreeNode<T : IndexTreeNode<T>>(children: MutableLis
}

childrenInternal.addAll(newNode)
canUseCachedChildren = false
newNode.forEach { node ->
node.parent = this as T

Expand All @@ -479,6 +493,7 @@ internal abstract class IndexTreeNode<T : IndexTreeNode<T>>(children: MutableLis
}

childrenInternal.addAll(0, newNode.toList())
canUseCachedChildren = false
newNode.forEach { node ->
node.parent = this as T

Expand Down Expand Up @@ -536,6 +551,7 @@ internal abstract class IndexTreeNode<T : IndexTreeNode<T>>(children: MutableLis
}

childrenInternal.add(offset, newNode)
canUseCachedChildren = false
newNode.parent = this as T
}

Expand All @@ -551,6 +567,7 @@ internal abstract class IndexTreeNode<T : IndexTreeNode<T>>(children: MutableLis
?: throw NoSuchElementException("child not found")

childrenInternal.removeAt(offset)
canUseCachedChildren = false
child.parent = null
}

Expand Down Expand Up @@ -579,8 +596,10 @@ internal abstract class IndexTreeNode<T : IndexTreeNode<T>>(children: MutableLis
val rightChildren = childrenInternal.drop(offset)
childrenInternal.clear()
childrenInternal.addAll(leftChildren)
canUseCachedChildren = false
clone.childrenInternal.clear()
clone.childrenInternal.addAll(rightChildren)
clone.canUseCachedChildren = false
size = childrenInternal.fold(0) { acc, child ->
acc + child.paddedSize
}
Expand Down Expand Up @@ -615,6 +634,10 @@ internal abstract class IndexTreeNode<T : IndexTreeNode<T>>(children: MutableLis
*/
abstract fun cloneElement(issueTimeTicket: () -> TimeTicket): T

fun childRemoved() {
canUseCachedChildren = false
}

companion object {
/**
* [ELEMENT_PADDING_SIZE] is the size of an element node as a child of another element node.
Expand Down

0 comments on commit efe3bf9

Please sign in to comment.