mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[workspace-model] Optimize memory consumption by new VirtualFileUrlManagerImpl
GitOrigin-RevId: 97900049061297e1c32feb8c79570f4a6f0f2abf
This commit is contained in:
committed by
intellij-monorepo-bot
parent
325c9cf27e
commit
25af0077d0
+2
-2
@@ -29,7 +29,7 @@ class VirtualFileNameStoreTest {
|
||||
Assert.assertEquals(3, store.generateIdForName("c"))
|
||||
store.removeName("b")
|
||||
store.removeName("a")
|
||||
Assert.assertEquals(2, store.generateIdForName("e"))
|
||||
Assert.assertEquals(1, store.generateIdForName("f"))
|
||||
Assert.assertEquals(4, store.generateIdForName("e"))
|
||||
Assert.assertEquals(5, store.generateIdForName("f"))
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.workspace.ide
|
||||
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.util.*
|
||||
|
||||
internal class IdGenerator {
|
||||
private val freeIdsQueue: Queue<Int> = LinkedList()
|
||||
private var generator: Int = 0
|
||||
fun generateId() = freeIdsQueue.poll() ?: ++generator
|
||||
fun releaseId(id: Int) = freeIdsQueue.add(id)
|
||||
|
||||
@TestOnly
|
||||
fun clear() {
|
||||
generator = 0
|
||||
freeIdsQueue.clear()
|
||||
}
|
||||
}
|
||||
+23
-15
@@ -1,47 +1,45 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.workspace.ide
|
||||
|
||||
import com.intellij.util.containers.BidirectionalMap
|
||||
import gnu.trove.THashMap
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
|
||||
internal class VirtualFileNameStore {
|
||||
private val generator = IdGenerator()
|
||||
private val nameStore = BidirectionalMap<String, IdPerCount>()
|
||||
private val name2IdStore = THashMap<String, IdPerCount>()
|
||||
private val id2NameStore = THashMap<Int, String>()
|
||||
|
||||
fun generateIdForName(name: String): Int {
|
||||
val idPerCount = nameStore[name]
|
||||
val idPerCount = name2IdStore[name]
|
||||
if (idPerCount != null) {
|
||||
idPerCount.usageCount++
|
||||
return idPerCount.id
|
||||
} else {
|
||||
val id = generator.generateId()
|
||||
nameStore[name] = IdPerCount(id, 1)
|
||||
name2IdStore[name] = IdPerCount(id, 1)
|
||||
id2NameStore[id] = name
|
||||
return id
|
||||
}
|
||||
}
|
||||
|
||||
fun removeName(name: String) {
|
||||
val idPerCount = nameStore[name] ?: return
|
||||
val idPerCount = name2IdStore[name] ?: return
|
||||
if (idPerCount.usageCount == 1L) {
|
||||
nameStore.remove(name)
|
||||
generator.releaseId(idPerCount.id)
|
||||
name2IdStore.remove(name)
|
||||
id2NameStore.remove(idPerCount.id)
|
||||
} else {
|
||||
idPerCount.usageCount--
|
||||
}
|
||||
}
|
||||
|
||||
fun getNameForId(id: Int): String? {
|
||||
val list = nameStore.getKeysByValue(IdPerCount(id, 1)) ?: return null
|
||||
if (list.isEmpty()) return null
|
||||
assert(list.size == 1)
|
||||
return list[0]
|
||||
}
|
||||
fun getNameForId(id: Int): String? = id2NameStore[id]
|
||||
|
||||
fun getIdForName(name: String) = nameStore[name]?.id
|
||||
fun getIdForName(name: String) = name2IdStore[name]?.id
|
||||
|
||||
@TestOnly
|
||||
fun clear() {
|
||||
nameStore.clear()
|
||||
name2IdStore.clear()
|
||||
id2NameStore.clear()
|
||||
generator.clear()
|
||||
}
|
||||
}
|
||||
@@ -58,4 +56,14 @@ private data class IdPerCount(val id: Int, var usageCount: Long) {
|
||||
}
|
||||
|
||||
override fun hashCode() = 31 * id.hashCode()
|
||||
}
|
||||
|
||||
internal class IdGenerator {
|
||||
private var generator: Int = 0
|
||||
fun generateId() = ++generator
|
||||
|
||||
@TestOnly
|
||||
fun clear() {
|
||||
generator = 0
|
||||
}
|
||||
}
|
||||
+34
-14
@@ -4,16 +4,18 @@ package com.intellij.workspace.ide
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.workspace.api.VirtualFileUrl
|
||||
import com.intellij.workspace.api.VirtualFileUrlManager
|
||||
import gnu.trove.THashMap
|
||||
import kotlin.collections.set
|
||||
|
||||
class VirtualFileUrlManagerImpl: VirtualFileUrlManager() {
|
||||
private val idGenerator= IdGenerator()
|
||||
private val EMPTY_URL = VirtualFileUrl(0, this)
|
||||
private val fileNameStore = VirtualFileNameStore()
|
||||
private val id2NodeMapping = HashMap<Int, FilePathNode>()
|
||||
private var segmentId2RootNodeMapping = mutableMapOf<Int, FilePathNode>()
|
||||
private val id2NodeMapping = THashMap<Int, FilePathNode>()
|
||||
private var segmentId2RootNodeMapping = THashMap<Int, FilePathNode>()
|
||||
|
||||
companion object {
|
||||
fun getInstance(project: Project): VirtualFileUrlManager = project.service<VirtualFileUrlManagerImpl>()
|
||||
@@ -82,12 +84,12 @@ class VirtualFileUrlManagerImpl: VirtualFileUrlManager() {
|
||||
}
|
||||
}
|
||||
|
||||
val node = latestNode.children.find { it.contentId == nameId }
|
||||
val node = latestNode.findChild(nameId)
|
||||
if (node == null) {
|
||||
val nodeId = idGenerator.generateId()
|
||||
val newNode = FilePathNode(nodeId, nameId, latestNode)
|
||||
id2NodeMapping[nodeId] = newNode
|
||||
latestNode.children.add(newNode)
|
||||
latestNode.addChild(newNode)
|
||||
latestNode = newNode
|
||||
// If it's the latest name of folder or files, save entity Id as node value
|
||||
if (index == latestElement) return VirtualFileUrl(nodeId, this)
|
||||
@@ -106,27 +108,25 @@ class VirtualFileUrlManagerImpl: VirtualFileUrlManager() {
|
||||
println("File not found")
|
||||
return
|
||||
}
|
||||
if (node.children.isNotEmpty()) return
|
||||
if (!node.isEmpty()) return
|
||||
|
||||
var currentNode: FilePathNode = node
|
||||
do {
|
||||
val parent = currentNode.parent
|
||||
if (parent == null) {
|
||||
if (currentNode === findRootNode(currentNode.contentId) && currentNode.children.isEmpty()) {
|
||||
if (currentNode === findRootNode(currentNode.contentId) && currentNode.isEmpty()) {
|
||||
removeNameUsage(currentNode.contentId)
|
||||
idGenerator.releaseId(currentNode.nodeId)
|
||||
id2NodeMapping.remove(currentNode.nodeId)
|
||||
segmentId2RootNodeMapping.remove(currentNode.contentId)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
parent.children.remove(currentNode)
|
||||
parent.removeChild(currentNode)
|
||||
removeNameUsage(currentNode.contentId)
|
||||
idGenerator.releaseId(currentNode.nodeId)
|
||||
id2NodeMapping.remove(currentNode.nodeId)
|
||||
currentNode = parent
|
||||
} while (currentNode.children.isEmpty())
|
||||
} while (currentNode.isEmpty())
|
||||
}
|
||||
|
||||
internal fun update(oldPath: String, newPath: String) {
|
||||
@@ -157,7 +157,7 @@ class VirtualFileUrlManagerImpl: VirtualFileUrlManager() {
|
||||
}
|
||||
}
|
||||
|
||||
latestNode.children.find { it.contentId == nameId }?.let {
|
||||
latestNode.findChild(nameId)?.let {
|
||||
if (index == latestElement) return it
|
||||
latestNode = it
|
||||
} ?: return null
|
||||
@@ -202,7 +202,28 @@ class VirtualFileUrlManagerImpl: VirtualFileUrlManager() {
|
||||
}
|
||||
|
||||
private inner class FilePathNode(val nodeId: Int, val contentId: Int, val parent: FilePathNode? = null) {
|
||||
val children: MutableSet<FilePathNode> = mutableSetOf()
|
||||
private var children: MutableList<FilePathNode>? = null
|
||||
|
||||
internal fun findChild(nameId: Int): FilePathNode? {
|
||||
// If search of child node will be slow, replace SmartList to THashSet
|
||||
// For now SmartList reduce 500Kb memory on IDEA project
|
||||
return children?.find { it.contentId == nameId }
|
||||
}
|
||||
|
||||
internal fun addChild(newNode: FilePathNode) {
|
||||
createChildrenList()
|
||||
children!!.add(newNode)
|
||||
}
|
||||
|
||||
internal fun removeChild(node: FilePathNode) {
|
||||
children?.remove(node)
|
||||
}
|
||||
|
||||
internal fun isEmpty() = children == null || children!!.isEmpty()
|
||||
|
||||
private fun createChildrenList() {
|
||||
if (children == null) children = SmartList()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val buffer = StringBuilder()
|
||||
@@ -213,7 +234,7 @@ class VirtualFileUrlManagerImpl: VirtualFileUrlManager() {
|
||||
private fun print(buffer: StringBuilder, prefix: String, childrenPrefix: String) {
|
||||
val name = this@VirtualFileUrlManagerImpl.fileNameStore.getNameForId(contentId)
|
||||
buffer.append("$prefix $name\n")
|
||||
val iterator = children.iterator()
|
||||
val iterator = children?.iterator() ?: return
|
||||
while (iterator.hasNext()) {
|
||||
val next = iterator.next()
|
||||
if (iterator.hasNext()) {
|
||||
@@ -225,5 +246,4 @@ class VirtualFileUrlManagerImpl: VirtualFileUrlManager() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user