11package org.javacs.kt.classpath
22
3- import kotlinx.serialization.Serializable
4- import org.javacs.kt.storage.SetOfPathsAsStringSerializer
5- import org.javacs.kt.storage.Storage
3+ import org.jetbrains.exposed.dao.IntEntity
4+ import org.jetbrains.exposed.dao.IntEntityClass
5+ import org.jetbrains.exposed.dao.id.EntityID
6+ import org.jetbrains.exposed.dao.id.IntIdTable
7+ import org.jetbrains.exposed.sql.*
8+ import org.jetbrains.exposed.sql.transactions.transaction
69import java.nio.file.Path
10+ import java.nio.file.Paths
11+
12+ private const val MAX_PATH_LENGTH = 255
13+
14+ private object ClassPathMetadataCache : IntIdTable() {
15+ val includesSources = bool(" includessources" )
16+ val buildFileVersion = long(" buidlfileversion" ).nullable()
17+ }
18+
19+ private object ClassPathCacheEntry : IntIdTable() {
20+ val compiledJar = varchar(" compiledjar" , length = MAX_PATH_LENGTH )
21+ val sourceJar = varchar(" sourcejar" , length = MAX_PATH_LENGTH ).nullable()
22+ }
23+
24+ private object BuildScriptClassPathCacheEntry : IntIdTable() {
25+ val jar = varchar(" jar" , length = MAX_PATH_LENGTH )
26+ }
27+
28+ class ClassPathMetadataCacheEntity (id : EntityID <Int >) : IntEntity(id) {
29+ companion object : IntEntityClass <ClassPathMetadataCacheEntity >(ClassPathMetadataCache )
30+
31+ var includesSources by ClassPathMetadataCache .includesSources
32+ var buildFileVersion by ClassPathMetadataCache .buildFileVersion
33+ }
34+
35+ class ClassPathCacheEntryEntity (id : EntityID <Int >) : IntEntity(id) {
36+ companion object : IntEntityClass <ClassPathCacheEntryEntity >(ClassPathCacheEntry )
37+
38+ var compiledJar by ClassPathCacheEntry .compiledJar
39+ var sourceJar by ClassPathCacheEntry .sourceJar
40+ }
41+
42+ class BuildScriptClassPathCacheEntryEntity (id : EntityID <Int >) : IntEntity(id) {
43+ companion object : IntEntityClass <BuildScriptClassPathCacheEntryEntity >(BuildScriptClassPathCacheEntry )
44+
45+ var jar by BuildScriptClassPathCacheEntry .jar
46+ }
747
848/* * A classpath resolver that caches another resolver */
9- internal class CachedClassPathResolver (private val wrapped : ClassPathResolver , private val storage : Storage ? ) : ClassPathResolver {
49+ internal class CachedClassPathResolver (private val wrapped : ClassPathResolver , private val db : Database ) : ClassPathResolver {
1050 override val resolverType: String get() = " Cached + ${wrapped.resolverType} "
1151
12- private var cachedClassPath: ClasspathCache ? = storage?.getObject(" cachedClasspath" )
13- private var cachedBuildScriptClassPath: Set <Path >? = storage?.getObject(" cachedBuildScriptClassPath" , SetOfPathsAsStringSerializer )
52+ private var cachedClassPathEntries: Set <ClassPathEntry >
53+ get() = transaction(db) { ClassPathCacheEntryEntity .all() }.map {
54+ ClassPathEntry (
55+ compiledJar = Paths .get(it.compiledJar),
56+ sourceJar = if (it.sourceJar != null ) Paths .get(it.sourceJar) else null
57+ )
58+ }.toSet()
59+ set(newEntries) = transaction(db) {
60+ ClassPathCacheEntry .deleteAll()
61+ newEntries.map {
62+ ClassPathCacheEntryEntity .new {
63+ compiledJar = it.compiledJar.toString()
64+ sourceJar = it.sourceJar.toString()
65+ }
66+ }
67+ }
68+
69+ private var cachedBuildScriptClassPathEntries: Set <Path >
70+ get() = transaction(db) { BuildScriptClassPathCacheEntryEntity .all() }.map { Paths .get(it.jar) }.toSet()
71+ set(newEntries) = transaction(db) {
72+ BuildScriptClassPathCacheEntry .deleteAll()
73+ newEntries.map { BuildScriptClassPathCacheEntryEntity .new { jar = it.toString() } }
74+ }
75+
76+ private var cachedClassPathMetadata
77+ get() = transaction(db) { ClassPathMetadataCacheEntity .all().map {
78+ ClasspathMetadata (
79+ includesSources = it.includesSources,
80+ buildFileVersion = it.buildFileVersion
81+ )
82+ }.firstOrNull() }
83+ set(newClassPathMetadata) = transaction(db) {
84+ ClassPathMetadataCache .deleteAll()
85+ val newClassPathMetadataRow = newClassPathMetadata ? : ClasspathMetadata ()
86+ ClassPathMetadataCacheEntity .new {
87+ includesSources = newClassPathMetadataRow.includesSources
88+ buildFileVersion = newClassPathMetadataRow.buildFileVersion
89+ }
90+ }
91+
92+ init {
93+ transaction(db) {
94+ SchemaUtils .createMissingTablesAndColumns(ClassPathMetadataCache , ClassPathCacheEntry , BuildScriptClassPathCacheEntry )
95+ }
96+ }
1497
1598 override val classpath: Set <ClassPathEntry > get() {
16- cachedClassPath? .let { if (! dependenciesChanged()) return it.classpathEntries }
99+ cachedClassPathEntries .let { if (! dependenciesChanged()) return it }
17100
18101 val newClasspath = wrapped.classpath
19- updateClasspathCache(ClasspathCache ( newClasspath, false ) )
102+ updateClasspathCache(newClasspath, false )
20103
21104 return newClasspath
22105 }
23106
24107 override val buildScriptClasspath: Set <Path > get() {
25- cachedBuildScriptClassPath?. let { if (! dependenciesChanged()) return it }
108+ if (! dependenciesChanged()) return cachedBuildScriptClassPathEntries
26109
27110 val newBuildScriptClasspath = wrapped.buildScriptClasspath
28111
@@ -31,35 +114,39 @@ internal class CachedClassPathResolver(private val wrapped: ClassPathResolver, p
31114 }
32115
33116 override val classpathWithSources: Set <ClassPathEntry > get() {
34- cachedClassPath ?.let { if (! dependenciesChanged() && it.includesSources) return it.classpathEntries }
117+ cachedClassPathMetadata ?.let { if (! dependenciesChanged() && it.includesSources) return cachedClassPathEntries }
35118
36119 val newClasspath = wrapped.classpathWithSources
37- updateClasspathCache(ClasspathCache ( newClasspath, true ) )
120+ updateClasspathCache(newClasspath, true )
38121
39122 return newClasspath
40123 }
41124
42125 override val currentBuildFileVersion: Long get() = wrapped.currentBuildFileVersion
43126
44- private fun updateClasspathCache (newClasspathCache : ClasspathCache ) {
45- storage?.setObject(" cachedClasspath" , newClasspathCache)
46- storage?.setObject(" cachedBuildFileVersion" , currentBuildFileVersion)
47- cachedClassPath = newClasspathCache
127+ private fun updateClasspathCache (newClasspathEntries : Set <ClassPathEntry >, includesSources : Boolean ) {
128+ transaction(db) {
129+ cachedClassPathEntries = newClasspathEntries
130+ cachedClassPathMetadata = cachedClassPathMetadata?.copy(
131+ includesSources = includesSources,
132+ buildFileVersion = currentBuildFileVersion
133+ ) ? : ClasspathMetadata ()
134+ }
48135 }
49136
50137 private fun updateBuildScriptClasspathCache (newClasspath : Set <Path >) {
51- storage?.setObject(" cachedBuildScriptClassPath" , newClasspath, SetOfPathsAsStringSerializer )
52- storage?.setObject(" cachedBuildFileVersion" , currentBuildFileVersion)
53- cachedBuildScriptClassPath = newClasspath
138+ transaction(db) {
139+ cachedBuildScriptClassPathEntries = newClasspath
140+ cachedClassPathMetadata = cachedClassPathMetadata?.copy(buildFileVersion = currentBuildFileVersion) ? : ClasspathMetadata ()
141+ }
54142 }
55143
56144 private fun dependenciesChanged (): Boolean {
57- return storage?.getObject< Long >( " cachedBuildFileVersion " ) ? : 0 < wrapped.currentBuildFileVersion
145+ return (cachedClassPathMetadata?.buildFileVersion ? : 0 ) < wrapped.currentBuildFileVersion
58146 }
59147}
60148
61- @Serializable
62- private data class ClasspathCache (
63- val classpathEntries : Set <ClassPathEntry >,
64- val includesSources : Boolean
149+ private data class ClasspathMetadata (
150+ val includesSources : Boolean = false ,
151+ val buildFileVersion : Long? = null
65152)
0 commit comments