CPP-40400: WorkspaceBuilderChangeLog: use persistent collections instead of immutable

GitOrigin-RevId: 5d8c98a6b165f8336c0126970a4fdc259430bc59
This commit is contained in:
Edem Ibraimov
2024-08-29 11:18:34 +03:00
committed by intellij-monorepo-bot
parent c228ac9115
commit bb4ea4e545
3 changed files with 51 additions and 53 deletions

View File

@@ -8,6 +8,7 @@ import com.intellij.platform.workspace.storage.ConnectionId
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.WorkspaceEntityWithSymbolicId
import com.intellij.platform.workspace.storage.impl.exceptions.ApplyChangesFromException
import kotlinx.collections.immutable.PersistentSet
import java.util.*
internal class ApplyChangesFromOperation(val target: MutableEntityStorageImpl, val diff: MutableEntityStorageImpl) {
@@ -223,7 +224,7 @@ internal class ApplyChangesFromOperation(val target: MutableEntityStorageImpl, v
newEntityId: ParentEntityId,
addedChildrenMap: MutableMap<ConnectionId, MutableList<ChildEntityId>>,
removedChildrenMap: MutableMap<ConnectionId, MutableList<ChildEntityId>>,
childrenOrdering: Map<ConnectionId, LinkedHashSet<ChildEntityId>>?,
childrenOrdering: Map<ConnectionId, PersistentSet<ChildEntityId>>?,
) {
// Children from target store with connectionIds of affected references
val existingChildrenOfAffectedIds: MutableMap<ConnectionId, List<ChildEntityId>> = HashMap()

View File

@@ -8,8 +8,8 @@ import com.intellij.platform.diagnostic.telemetry.TelemetryManager
import com.intellij.platform.diagnostic.telemetry.helpers.MillisecondsMeasurer
import com.intellij.platform.workspace.storage.ConnectionId
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.util.containers.with
import io.opentelemetry.api.metrics.Meter
import kotlinx.collections.immutable.*
internal typealias ChangeLog = MutableMap<EntityId, ChangeEntry>
@@ -84,21 +84,21 @@ internal class WorkspaceBuilderChangeLog {
val existingChange = changeLog[entityId]
val updateReplaceEvent = { replaceEntity: ChangeEntry.ReplaceEntity ->
val newAddedParents: Map<ConnectionId, ParentEntityId> = if (replaceEntity.references != null) {
val newAddedParents = if (replaceEntity.references != null) {
if (!replaceEntity.references.newParents.contains(newConnectionId, newParentId)
&& !replaceEntity.references.removedParents.contains(newConnectionId, newParentId)) {
replaceEntity.references.newParents.toMutableMap().also { it[newConnectionId] = newParentId }
replaceEntity.references.newParents.put(newConnectionId, newParentId)
}
else {
replaceEntity.references.newParents
}
}
else mapOf(newConnectionId to newParentId)
else persistentHashMapOf(newConnectionId to newParentId)
val newRemovedParents = if (replaceEntity.references != null) {
replaceEntity.references.removedParents.toMutableMap().also { it.remove(newConnectionId, newParentId) }
replaceEntity.references.removedParents.remove(newConnectionId, newParentId)
}
else emptyMap()
else persistentHashMapOf()
if (replaceEntity.references != null) {
if (replaceEntity.references.newChildren.isEmpty() && replaceEntity.references.removedChildren.isEmpty() && replaceEntity.references.childrenOrdering.isEmpty() && newAddedParents.isEmpty() && newRemovedParents.isEmpty()) {
@@ -115,7 +115,7 @@ internal class WorkspaceBuilderChangeLog {
if (existingChange == null) {
changeLog[entityId] = ChangeEntry.ReplaceEntity(
null,
ChangeEntry.ReplaceEntity.References(newParents = mapOf(newConnectionId to newParentId))
ChangeEntry.ReplaceEntity.References(newParents = persistentHashMapOf(newConnectionId to newParentId))
)
}
else {
@@ -152,16 +152,16 @@ internal class WorkspaceBuilderChangeLog {
val newRemovedParents = if (replaceEntity.references != null) {
if (!replaceEntity.references.removedParents.contains(removedConnectionId, removedParentId)
&& !replaceEntity.references.newParents.contains(removedConnectionId, removedParentId)) {
replaceEntity.references.removedParents.toMutableMap().also { it[removedConnectionId] = removedParentId }
replaceEntity.references.removedParents.put(removedConnectionId, removedParentId)
}
else replaceEntity.references.removedParents
}
else mapOf(removedConnectionId to removedParentId)
else persistentHashMapOf(removedConnectionId to removedParentId)
val newAddedParents: Map<ConnectionId, ParentEntityId> = if (replaceEntity.references != null) {
replaceEntity.references.newParents.toMutableMap().also { it.remove(removedConnectionId, removedParentId) }
val newAddedParents = if (replaceEntity.references != null) {
replaceEntity.references.newParents.remove(removedConnectionId, removedParentId)
}
else emptyMap()
else persistentHashMapOf()
if (replaceEntity.references != null) {
if (replaceEntity.references.newChildren.isEmpty() && replaceEntity.references.removedChildren.isEmpty() && replaceEntity.references.childrenOrdering.isEmpty() && newAddedParents.isEmpty() && newRemovedParents.isEmpty()) {
@@ -178,7 +178,7 @@ internal class WorkspaceBuilderChangeLog {
if (existingChange == null) {
changeLog[entityId] = ChangeEntry.ReplaceEntity(
null,
ChangeEntry.ReplaceEntity.References(removedParents = mapOf(removedConnectionId to removedParentId))
ChangeEntry.ReplaceEntity.References(removedParents = persistentHashMapOf(removedConnectionId to removedParentId))
)
}
else {
@@ -215,27 +215,24 @@ internal class WorkspaceBuilderChangeLog {
val connectionToId = addedChildConnectionId to addedChildId
val newAddedChildren = if (replaceEntity.references != null) {
if (connectionToId !in replaceEntity.references.newChildren && connectionToId !in replaceEntity.references.removedChildren) {
replaceEntity.references.newChildren + connectionToId
replaceEntity.references.newChildren.add(connectionToId)
}
else {
replaceEntity.references.newChildren
}
}
else {
setOf(connectionToId)
persistentHashSetOf(connectionToId)
}
val newRemovedChildren = if (replaceEntity.references != null) {
replaceEntity.references.removedChildren - connectionToId
replaceEntity.references.removedChildren.remove(connectionToId)
}
else emptySet()
else persistentHashSetOf()
val newOrder = if (replaceEntity.references != null) {
val prevSet = replaceEntity.references.childrenOrdering.getOrElse(addedChildConnectionId) { LinkedHashSet() }
val set = LinkedHashSet(prevSet)
set.add(addedChildId)
set
replaceEntity.references.childrenOrdering.getOrElse(addedChildConnectionId) { persistentSetOf() }.add(addedChildId)
} else {
LinkedHashSet<ChildEntityId?>().also { it.add(addedChildId) }
persistentSetOf(addedChildId)
}
if (replaceEntity.references != null) {
@@ -243,23 +240,23 @@ internal class WorkspaceBuilderChangeLog {
if (replaceEntity.data == null) null else replaceEntity.copy(references = null)
}
else {
val ordering = replaceEntity.references.childrenOrdering.with(addedChildConnectionId, newOrder)
val ordering = replaceEntity.references.childrenOrdering.put(addedChildConnectionId, newOrder)
replaceEntity.copy(
references = replaceEntity.references.copy(newChildren = newAddedChildren, removedChildren = newRemovedChildren,
childrenOrdering = ordering))
}
}
else {
val ordering = mapOf(addedChildConnectionId to newOrder)
val ordering = persistentHashMapOf(addedChildConnectionId to newOrder)
replaceEntity.copy(references = ChangeEntry.ReplaceEntity.References(newAddedChildren, newRemovedChildren, ordering))
}
}
if (existingChange == null) {
val ordering = mapOf(addedChildConnectionId to LinkedHashSet<ChildEntityId>().also { it.add(addedChildId) })
val ordering = persistentHashMapOf(addedChildConnectionId to persistentSetOf(addedChildId))
changeLog[entityId] = ChangeEntry.ReplaceEntity(
null,
ChangeEntry.ReplaceEntity.References(setOf(addedChildConnectionId to addedChildId), emptySet(), ordering)
ChangeEntry.ReplaceEntity.References(persistentHashSetOf(addedChildConnectionId to addedChildId), persistentHashSetOf(), ordering)
)
}
else {
@@ -297,26 +294,23 @@ internal class WorkspaceBuilderChangeLog {
val newRemovedChildren = if (replaceEntity.references != null) {
if (connectionToId !in replaceEntity.references.removedChildren && connectionToId !in replaceEntity.references.newChildren) {
replaceEntity.references.removedChildren + connectionToId
replaceEntity.references.removedChildren.add(connectionToId)
}
else {
replaceEntity.references.removedChildren
}
}
else setOf(connectionToId)
else persistentHashSetOf(connectionToId)
val newAddedChildren = if (replaceEntity.references != null) {
replaceEntity.references.newChildren - connectionToId
replaceEntity.references.newChildren.remove(connectionToId)
}
else emptySet()
else persistentHashSetOf()
val newOrder = if (replaceEntity.references != null) {
val prevSet = replaceEntity.references.childrenOrdering.getOrElse(removedChildConnectionId) { LinkedHashSet() }
val set = LinkedHashSet(prevSet)
set.remove(removedChildId)
set
replaceEntity.references.childrenOrdering.getOrElse(removedChildConnectionId) { persistentSetOf() }.remove(removedChildId)
} else {
LinkedHashSet<ChildEntityId?>()
persistentSetOf()
}
if (replaceEntity.references != null) {
@@ -324,7 +318,7 @@ internal class WorkspaceBuilderChangeLog {
if (replaceEntity.data == null) null else replaceEntity.copy(references = null)
}
else {
val ordering = replaceEntity.references.childrenOrdering.with(removedChildConnectionId, newOrder)
val ordering = replaceEntity.references.childrenOrdering.put(removedChildConnectionId, newOrder)
replaceEntity.copy(references = replaceEntity.references.copy(
newChildren = newAddedChildren,
removedChildren = newRemovedChildren,
@@ -333,16 +327,16 @@ internal class WorkspaceBuilderChangeLog {
}
}
else {
val ordering = mapOf(removedChildConnectionId to newOrder)
val ordering = persistentHashMapOf(removedChildConnectionId to newOrder)
replaceEntity.copy(references = ChangeEntry.ReplaceEntity.References(newAddedChildren, newRemovedChildren, ordering))
}
}
if (existingChange == null) {
val ordering = mapOf(removedChildConnectionId to LinkedHashSet<ChildEntityId>())
val ordering = persistentHashMapOf(removedChildConnectionId to persistentSetOf<ChildEntityId>())
changeLog[entityId] = ChangeEntry.ReplaceEntity(
null,
ChangeEntry.ReplaceEntity.References(removedChildren = setOf(removedChildConnectionId to removedChildId), childrenOrdering = ordering)
ChangeEntry.ReplaceEntity.References(removedChildren = persistentHashSetOf(removedChildConnectionId to removedChildId), childrenOrdering = ordering)
)
}
else {
@@ -531,11 +525,11 @@ internal sealed class ChangeEntry {
)
data class References(
val newChildren: Set<Pair<ConnectionId, ChildEntityId>> = emptySet(),
val removedChildren: Set<Pair<ConnectionId, ChildEntityId>> = emptySet(),
val childrenOrdering: Map<ConnectionId, LinkedHashSet<ChildEntityId>> = emptyMap(),
val newParents: Map<ConnectionId, ParentEntityId> = emptyMap(),
val removedParents: Map<ConnectionId, ParentEntityId> = emptyMap(),
val newChildren: PersistentSet<Pair<ConnectionId, ChildEntityId>> = persistentHashSetOf(),
val removedChildren: PersistentSet<Pair<ConnectionId, ChildEntityId>> = persistentHashSetOf(),
val childrenOrdering: PersistentMap<ConnectionId, PersistentSet<ChildEntityId>> = persistentHashMapOf(),
val newParents: PersistentMap<ConnectionId, ParentEntityId> = persistentHashMapOf(),
val removedParents: PersistentMap<ConnectionId, ParentEntityId> = persistentHashMapOf(),
) {
fun isEmpty(): Boolean {
return newChildren.isEmpty()

View File

@@ -11,6 +11,9 @@ import com.intellij.platform.workspace.storage.testEntities.entities.AnotherSour
import com.intellij.platform.workspace.storage.testEntities.entities.MySource
import com.intellij.platform.workspace.storage.tests.createBuilderFrom
import com.intellij.platform.workspace.storage.tests.createEmptyBuilder
import kotlinx.collections.immutable.persistentHashMapOf
import kotlinx.collections.immutable.toPersistentHashSet
import kotlinx.collections.immutable.toPersistentMap
import org.jetbrains.jetCheck.Generator
import org.jetbrains.jetCheck.ImperativeCommand
import org.jetbrains.jetCheck.PropertyChecker
@@ -150,14 +153,14 @@ private class ApplyChangesFromCheckChangelog(val preBuilder: MutableEntityStorag
private fun assertEntries(updatedChangelog: Map<EntityId, ChangeEntry>, actualChangelog: Map<EntityId, ChangeEntry>) {
val left = updatedChangelog.mapValues { (k, v) ->
if (v is ChangeEntry.ReplaceEntity) {
val newRefs = v.references?.copy(childrenOrdering = emptyMap()).takeUnless { it?.isEmpty() == true }
val newRefs = v.references?.copy(childrenOrdering = persistentHashMapOf()).takeUnless { it?.isEmpty() == true }
v.copy(references = newRefs).takeUnless { it.data == null && it.references == null }
}
else v
}.filterValues { it != null }
val right = actualChangelog.mapValues { (k, v) ->
if (v is ChangeEntry.ReplaceEntity) {
val references = v.references?.copy(childrenOrdering = emptyMap()).takeUnless { it?.isEmpty() == true }
val references = v.references?.copy(childrenOrdering = persistentHashMapOf()).takeUnless { it?.isEmpty() == true }
v.copy(references = references).takeUnless { it.data == null && it.references == null }
}
else v
@@ -198,14 +201,14 @@ private class ApplyChangesFromCheckChangelog(val preBuilder: MutableEntityStorag
}
newEntry = newEntry.copy(
references = entry.references?.copy(
newChildren = entry.references.newChildren.mapTo(HashSet()) {
newChildren = entry.references.newChildren.map {
it.copy(second = replaceMap[it.second.id.notThis()]?.id?.asChild() ?: it.second)
},
removedChildren = entry.references.removedChildren.mapTo(HashSet()) {
}.toPersistentHashSet(),
removedChildren = entry.references.removedChildren.map {
it.copy(second = replaceMap[it.second.id.notThis()]?.id?.asChild() ?: it.second)
},
newParents = entry.references.newParents.mapValues { (_, v) -> replaceMap[v.id.notThis()]?.id?.asParent() ?: v },
removedParents = entry.references.removedParents.mapValues { (_, v) -> replaceMap[v.id.notThis()]?.id?.asParent() ?: v },
}.toPersistentHashSet(),
newParents = entry.references.newParents.mapValues { (_, v) -> replaceMap[v.id.notThis()]?.id?.asParent() ?: v }.toPersistentMap(),
removedParents = entry.references.removedParents.mapValues { (_, v) -> replaceMap[v.id.notThis()]?.id?.asParent() ?: v }.toPersistentMap(),
)
)
put(newId, newEntry)