Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ val applicationName = "kotlin-language-server"
application {
mainClass.set(serverMainClassName)
description = "Code completions, diagnostics and more for Kotlin"
applicationDefaultJvmArgs = listOf("-DkotlinLanguageServer.version=$version")
applicationDefaultJvmArgs = listOf(
"-DkotlinLanguageServer.version=$version",
"-Xms256m",
"-Xmx1024m",
"-XX:+UseG1GC",
"-XX:+UseStringDeduplication"
)
applicationDistribution.into("bin") { filePermissions { unix("755".toInt(radix = 8)) } }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import java.io.File
import java.nio.file.Paths

private val cachedTempFiles = mutableMapOf<KlsURI, Path>()
private val definitionPattern = Regex("(?:class|interface|object|fun)\\s+(\\w+)")
private val definitionPattern = Regex("(?:class|interface|object|fun|val|var)\\s+(\\w+)")

fun goToDefinition(
file: CompiledFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class ClassContentProvider(
) {
/** Maps recently used (source-)KLS-URIs to their source contents (e.g. decompiled code) and the file extension. */
private val cachedContents = object : LinkedHashMap<String, Pair<String, String>>() {
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<String, Pair<String, String>>) = size > 5
// Decompilation is expensive; larger cache reduces repeated decompilation overhead
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<String, Pair<String, String>>) = size > 50
}

/**
Expand Down
3 changes: 2 additions & 1 deletion shared/src/main/kotlin/org/javacs/kt/SourceExclusions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ class SourceExclusions(
val excludedPatterns = (listOf(
".git", ".hg", ".svn", // Version control systems
".idea", ".idea_modules", ".vs", ".vscode", ".code-workspace", ".settings", // IDEs
"bazel-*", "bin", "build", "node_modules", "target", // Build systems
"bazel-*", "bin", "node_modules", "target", // Build systems
"build/classes", "build/libs", "build/tmp", "build/reports", "build/kotlin", "build/resources", // Gradle build outputs (but allow build/generated-src)
) + when {
!scriptsConfig.enabled -> listOf("*.kts")
!scriptsConfig.buildScriptsEnabled -> listOf("*.gradle.kts")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,47 +55,63 @@ internal class CachedClassPathResolver(
) : ClassPathResolver {
override val resolverType: String get() = "Cached + ${wrapped.resolverType}"

// In-memory cache layer to avoid repeated DB transactions
private var inMemoryClassPathEntries: Set<ClassPathEntry>? = null
private var inMemoryBuildScriptEntries: Set<Path>? = null
private var inMemoryMetadata: ClasspathMetadata? = null

private var cachedClassPathEntries: Set<ClassPathEntry>
get() = transaction(db) {
get() = inMemoryClassPathEntries ?: transaction(db) {
ClassPathCacheEntryEntity.all().map {
ClassPathEntry(
compiledJar = Paths.get(it.compiledJar),
sourceJar = it.sourceJar?.let(Paths::get)
)
}.toSet()
}
set(newEntries) = transaction(db) {
ClassPathCacheEntry.deleteAll()
newEntries.map {
ClassPathCacheEntryEntity.new {
compiledJar = it.compiledJar.toString()
sourceJar = it.sourceJar?.toString()
}.also { inMemoryClassPathEntries = it }
set(newEntries) {
inMemoryClassPathEntries = newEntries
transaction(db) {
ClassPathCacheEntry.deleteAll()
newEntries.map {
ClassPathCacheEntryEntity.new {
compiledJar = it.compiledJar.toString()
sourceJar = it.sourceJar?.toString()
}
}
}
}

private var cachedBuildScriptClassPathEntries: Set<Path>
get() = transaction(db) { BuildScriptClassPathCacheEntryEntity.all().map { Paths.get(it.jar) }.toSet() }
set(newEntries) = transaction(db) {
BuildScriptClassPathCacheEntry.deleteAll()
newEntries.map { BuildScriptClassPathCacheEntryEntity.new { jar = it.toString() } }
get() = inMemoryBuildScriptEntries ?: transaction(db) {
BuildScriptClassPathCacheEntryEntity.all().map { Paths.get(it.jar) }.toSet()
}.also { inMemoryBuildScriptEntries = it }
set(newEntries) {
inMemoryBuildScriptEntries = newEntries
transaction(db) {
BuildScriptClassPathCacheEntry.deleteAll()
newEntries.map { BuildScriptClassPathCacheEntryEntity.new { jar = it.toString() } }
}
}

private var cachedClassPathMetadata
get() = transaction(db) {
private var cachedClassPathMetadata: ClasspathMetadata?
get() = inMemoryMetadata ?: transaction(db) {
ClassPathMetadataCacheEntity.all().map {
ClasspathMetadata(
includesSources = it.includesSources,
buildFileVersion = it.buildFileVersion
)
}.firstOrNull()
}
set(newClassPathMetadata) = transaction(db) {
ClassPathMetadataCache.deleteAll()
val newClassPathMetadataRow = newClassPathMetadata ?: ClasspathMetadata()
ClassPathMetadataCacheEntity.new {
includesSources = newClassPathMetadataRow.includesSources
buildFileVersion = newClassPathMetadataRow.buildFileVersion
}.also { inMemoryMetadata = it }
set(newClassPathMetadata) {
inMemoryMetadata = newClassPathMetadata
transaction(db) {
ClassPathMetadataCache.deleteAll()
val newClassPathMetadataRow = newClassPathMetadata ?: ClasspathMetadata()
ClassPathMetadataCacheEntity.new {
includesSources = newClassPathMetadataRow.includesSources
buildFileVersion = newClassPathMetadataRow.buildFileVersion
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,14 @@ class DatabaseService {
private fun getDbFromFile(storagePath: Path?): Database? {
return storagePath?.let {
if (Files.isDirectory(it)) {
Database.connect("jdbc:sqlite:${getDbFilePath(it)}")
Database.connect("jdbc:sqlite:${getDbFilePath(it)}").also { db ->
transaction(db) {
// WAL mode: better concurrent read performance
exec("PRAGMA journal_mode = WAL")
// Reduce fsync calls (safe with WAL mode)
exec("PRAGMA synchronous = NORMAL")
}
}
} else {
null
}
Expand Down