IJPL-872 fix kernel and rpc services

GitOrigin-RevId: 80c6c0abcf68359e4c55b81560debef9e98ba808
This commit is contained in:
Vladimir Koshelev
2024-03-22 21:48:15 +01:00
committed by intellij-monorepo-bot
parent b7a6cb6d63
commit 82f8055fea
19 changed files with 329 additions and 62 deletions

View File

@@ -1224,6 +1224,9 @@ object CommunityLibraryLicenses {
jetbrainsLibrary("find-classes-model-experimental"), jetbrainsLibrary("find-classes-model-experimental"),
jetbrainsLibrary("find-file-model"), jetbrainsLibrary("find-file-model"),
jetbrainsLibrary("find-file-model-experimental"), jetbrainsLibrary("find-file-model-experimental"),
jetbrainsLibrary("jetbrains.fleet.kernel"),
jetbrainsLibrary("jetbrains.fleet.rpc"),
jetbrainsLibrary("jetbrains.fleet.rpc.server"),
jetbrainsLibrary("git-learning-project"), jetbrainsLibrary("git-learning-project"),
jetbrainsLibrary("intellij.remoterobot.remote.fixtures"), jetbrainsLibrary("intellij.remoterobot.remote.fixtures"),
jetbrainsLibrary("intellij.remoterobot.robot.server.core"), jetbrainsLibrary("intellij.remoterobot.robot.server.core"),

View File

@@ -1,22 +0,0 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.fleet.rpc
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.client.ClientAppSession
import com.intellij.openapi.client.currentSession
import com.intellij.openapi.components.service
import fleet.rpc.core.FleetTransportFactory
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
@ApiStatus.Experimental
interface FleetRpc {
companion object {
fun getInstance(session: ClientAppSession): FleetRpc = session.service()
fun getCurrentInstance(): FleetRpc = ApplicationManager.getApplication().currentSession.service()
}
fun getTransportFactory(): FleetTransportFactory
}

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="com.intellij.platform.kernel.backend" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="intellij.platform.kernel" />
<orderEntry type="module" module-name="intellij.platform.extensions" />
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="library" name="kotlinx-collections-immutable" level="project" />
<orderEntry type="library" name="jetbrains-annotations" level="project" />
</component>
</module>

View File

@@ -0,0 +1,17 @@
<idea-plugin package="com.intellij.platform.kernel.backend">
<dependencies>
<module name="intellij.platform.kernel"/>
</dependencies>
<extensionPoints>
<extensionPoint qualifiedName="com.intellij.platform.kernel.backend.remoteApiProvider"
interface="com.intellij.platform.kernel.backend.RemoteApiProvider"
dynamic="true"/>
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">
<!--suppress PluginXmlValidity -->
<applicationService serviceInterface="com.intellij.platform.kernel.rpc.RemoteApiProviderService"
serviceImplementation="com.intellij.platform.kernel.backend.RemoteApiRegistry"/>
</extensions>
</idea-plugin>

View File

@@ -0,0 +1,18 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.kernel.backend
import com.intellij.openapi.extensions.ExtensionPointName
import fleet.rpc.RemoteApi
import org.jetbrains.annotations.ApiStatus
import kotlin.reflect.KClass
interface RemoteApiProvider {
data class RemoteApiDescriptor<T : RemoteApi<Unit>>(val klass: KClass<T>, val service: () -> T)
fun getApis(): List<RemoteApiDescriptor<*>>
companion object {
@ApiStatus.Internal
val EP_NAME = ExtensionPointName<RemoteApiProvider>("com.intellij.platform.kernel.backend.remoteApiProvider")
}
}

View File

@@ -0,0 +1,56 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.kernel.backend
import com.intellij.openapi.extensions.ExtensionPointListener
import com.intellij.openapi.extensions.PluginDescriptor
import com.intellij.platform.kernel.backend.RemoteApiProvider.Companion.EP_NAME
import com.intellij.platform.kernel.rpc.RemoteApiProviderService
import com.intellij.util.containers.ContainerUtil
import fleet.rpc.RemoteApi
import fleet.rpc.core.InstanceId
import kotlinx.coroutines.CoroutineScope
import java.util.concurrent.ConcurrentHashMap
import kotlin.collections.set
import kotlin.reflect.KClass
class RemoteApiRegistry(private val coroutineScope: CoroutineScope) : RemoteApiProviderService {
private val remoteApis = ConcurrentHashMap<InstanceId, Pair<KClass<out RemoteApi<Unit>>, RemoteApi<Unit>>>()
private val visitedEPs = ContainerUtil.createConcurrentWeakKeyWeakValueMap<RemoteApiProvider, Unit>()
init {
EP_NAME.addExtensionPointListener(coroutineScope, object : ExtensionPointListener<RemoteApiProvider> {
override fun extensionAdded(extension: RemoteApiProvider, pluginDescriptor: PluginDescriptor) {
if (visitedEPs.putIfAbsent(extension, Unit) == null) {
val apis = extension.getApis()
for (api in apis) {
remoteApis[api.klass.toInstanceId] = api.klass to api.service()
}
}
}
override fun extensionRemoved(extension: RemoteApiProvider, pluginDescriptor: PluginDescriptor) {
visitedEPs.remove(extension)
val apis = extension.getApis()
synchronized(this) {
apis.forEach { api ->
remoteApis.remove(api.klass.toInstanceId)
}
}
}
})
EP_NAME.extensions.filter { visitedEPs.putIfAbsent(it, Unit) == null }.flatMap { it.getApis() }.forEach { api ->
remoteApis[api.klass.toInstanceId] = api.klass to api.service()
}
}
override fun <T : RemoteApi<Unit>> resolve(kclass: KClass<T>): T {
return remoteApis[kclass.toInstanceId]?.second as? T ?: throw IllegalStateException("No remote API found for $kclass")
}
fun resolve(instanceId: InstanceId): Pair<KClass<out RemoteApi<Unit>>, RemoteApi<Unit>> {
return remoteApis[instanceId] ?: throw IllegalStateException("No remote API found for $instanceId")
}
}
private val KClass<out RemoteApi<Unit>>.toInstanceId: InstanceId
get() = InstanceId(this.qualifiedName!!)

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="com.intellij.platform.kernel.monolith" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="intellij.platform.kernel" />
</component>
</module>

View File

@@ -0,0 +1,11 @@
<idea-plugin package="com.intellij.platform.kernel.monolith">
<dependencies>
<module name="intellij.platform.kernel"/>
</dependencies>
<extensions defaultExtensionNs="com.intellij">
<!--suppress PluginXmlValidity -->
<applicationService serviceInterface="com.intellij.platform.kernel.KernelService"
serviceImplementation="com.intellij.platform.kernel.monolith.MonolithKernelService"/>
</extensions>
</idea-plugin>

View File

@@ -0,0 +1,35 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.kernel.monolith
import com.intellij.platform.kernel.KernelService
import com.intellij.platform.kernel.util.CommonInstructionSet
import com.intellij.platform.kernel.util.KernelRpcSerialization
import com.intellij.platform.kernel.util.ReadTracker
import com.intellij.platform.kernel.util.withKernel
import fleet.kernel.Kernel
import fleet.kernel.kernel
import fleet.kernel.rebase.LeaderKernelMiddleware
import fleet.kernel.rebase.encoder
import fleet.kernel.rete.Rete
import kotlinx.coroutines.*
internal class MonolithKernelService(coroutineScope: CoroutineScope) : KernelService {
override val kernel: Kernel
override val rete: Rete
init {
val kernelDeferred: CompletableDeferred<Kernel> = CompletableDeferred()
val reteDeferred : CompletableDeferred<Rete> = CompletableDeferred()
coroutineScope.launch(start = CoroutineStart.UNDISPATCHED) {
withKernel(middleware = LeaderKernelMiddleware(KernelRpcSerialization, CommonInstructionSet.encoder())) {
kernelDeferred.complete(kernel())
reteDeferred.complete(currentCoroutineContext()[Rete]!!)
ReadTracker.subscribeForChanges()
}
}
kernel = kernelDeferred.getCompleted()
rete = reteDeferred.getCompleted()
}
}

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="5" platform="JVM 17" allPlatforms="JVM [17]" useProjectSettings="false">
<compilerSettings>
<option name="additionalArguments" value="-Xjvm-default=all" />
</compilerSettings>
<compilerArguments>
<stringArguments>
<stringArg name="jvmTarget" arg="17" />
<stringArg name="apiVersion" arg="1.9" />
<stringArg name="languageVersion" arg="1.9" />
</stringArguments>
<arrayArguments>
<arrayArg name="pluginClasspaths">
<args>
<arg>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</arg>
<arg>$MAVEN_REPOSITORY$/jetbrains/fleet/rhizomedb-compiler-plugin/1.9.20-0.17/rhizomedb-compiler-plugin-1.9.20-0.17.jar</arg>
</args>
</arrayArg>
<arrayArg name="pluginOptions" />
</arrayArguments>
</compilerArguments>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/" isTestSource="false" packagePrefix="com.intellij.platform.kernel" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="kotlin-stdlib" level="project" />
<orderEntry type="library" exported="" name="jetbrains.fleet.rpc" level="project" />
<orderEntry type="library" exported="" name="jetbrains.fleet.kernel" level="project" />
<orderEntry type="library" exported="" name="kotlinx-coroutines-core" level="project" />
<orderEntry type="library" exported="" name="io.lacuna:bifurcan" level="project" />
<orderEntry type="library" name="kotlinx-collections-immutable" level="project" />
<orderEntry type="library" name="kotlinx-serialization-core" level="project" />
<orderEntry type="library" name="kotlinx-serialization-json" level="project" />
<orderEntry type="library" name="fastutil-min" level="project" />
<orderEntry type="module" module-name="intellij.platform.core" />
</component>
</module>

View File

@@ -0,0 +1 @@
com.intellij.platform.kernel.util.IjLoggerFactory

View File

@@ -0,0 +1,2 @@
<idea-plugin package="com.intellij.platform.kernel">
</idea-plugin>

View File

@@ -1,5 +1,5 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.fleet.kernel package com.intellij.platform.kernel
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import fleet.kernel.DbSource import fleet.kernel.DbSource
@@ -7,10 +7,8 @@ import fleet.kernel.Kernel
import fleet.kernel.rete.Rete import fleet.kernel.rete.Rete
import fleet.kernel.withCondition import fleet.kernel.withCondition
import kotlinx.coroutines.* import kotlinx.coroutines.*
import org.jetbrains.annotations.ApiStatus import kotlin.coroutines.CoroutineContext
@ApiStatus.Internal
@ApiStatus.Experimental
interface KernelService { interface KernelService {
val kernel: Kernel val kernel: Kernel
val rete: Rete val rete: Rete
@@ -18,9 +16,11 @@ interface KernelService {
val instance: KernelService val instance: KernelService
get() = ApplicationManager.getApplication().getService(KernelService::class.java) get() = ApplicationManager.getApplication().getService(KernelService::class.java)
val kernelCoroutineContext: CoroutineContext
get() = instance.kernel + instance.rete + DbSource(instance.kernel.dbState, instance.kernel.toString())
fun <T> CoroutineScope.saga(condition: () -> Boolean = { true }, block: suspend CoroutineScope.() -> T): Deferred<T> { fun <T> CoroutineScope.saga(condition: () -> Boolean = { true }, block: suspend CoroutineScope.() -> T): Deferred<T> {
val instance = instance return async(kernelCoroutineContext) {
return async(instance.kernel + instance.rete + DbSource(instance.kernel.dbState, instance.kernel.toString())) {
withCondition(condition, block) withCondition(condition, block)
} }
} }

View File

@@ -0,0 +1,16 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.kernel.rpc
import com.intellij.openapi.application.ApplicationManager
import fleet.rpc.RemoteApi
import kotlin.reflect.KClass
interface RemoteApiProviderService {
fun <T : RemoteApi<Unit>> resolve(klass: KClass<T>): T
companion object {
fun <T : RemoteApi<Unit>> resolve(klass: KClass<T>): T {
return ApplicationManager.getApplication().getService(RemoteApiProviderService::class.java).resolve(klass)
}
}
}

View File

@@ -0,0 +1,79 @@
package com.intellij.platform.kernel.util
import com.intellij.openapi.diagnostic.Logger
import fleet.util.logging.*
import kotlin.reflect.KClass
class IjLogger(private val logger: Logger) : BaseLogger {
override val isTraceEnabled: Boolean
get() = logger.isTraceEnabled
override val isDebugEnabled: Boolean
get() = logger.isDebugEnabled
override val isInfoEnabled: Boolean
get() = true
override val isWarnEnabled: Boolean
get() = true
override val isErrorEnabled: Boolean
get() = true
override fun trace(message: Any?) {
logger.trace(message?.toString() ?: "null")
}
override fun trace(t: Throwable?, message: Any?) {
logger.trace(message?.toString() ?: "null")
if (t != null) {
logger.trace(t)
}
}
override fun debug(message: Any?) {
logger.debug(message?.toString() ?: "null")
}
override fun debug(t: Throwable?, message: Any?) {
logger.debug(message?.toString() ?: "null", t)
}
override fun info(message: Any?) {
logger.info(message?.toString() ?: "null")
}
override fun info(t: Throwable?, message: Any?) {
logger.info(message?.toString() ?: "null", t)
}
override fun warn(message: Any?) {
logger.warn(message?.toString() ?: "null")
}
override fun warn(t: Throwable?, message: Any?) {
logger.warn(message?.toString() ?: "null", t)
}
override fun error(message: Any?) {
logger.error(message.toString())
}
override fun error(t: Throwable?, message: Any?) {
logger.error(message?.toString() ?: "null", t)
}
}
class IjLoggerFactory : KLoggerFactory {
override fun logger(owner: KClass<*>): KLogger {
return KLogger(IjLogger(Logger.getInstance(owner.java)))
}
override fun logger(owner: Class<*>): KLogger {
return KLogger(IjLogger(Logger.getInstance(owner)))
}
override fun logger(owner: Any): KLogger {
return KLogger(IjLogger(Logger.getInstance(owner.toString())))
}
override fun logger(name: String): KLogger {
return KLogger(IjLogger(Logger.getInstance(name)))
}
}

View File

@@ -1,5 +1,5 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.kernel package com.intellij.platform.kernel.util
import com.jetbrains.rhizomedb.Datom import com.jetbrains.rhizomedb.Datom
import com.jetbrains.rhizomedb.Pattern import com.jetbrains.rhizomedb.Pattern
@@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.ints.IntConsumer
import it.unimi.dsi.fastutil.ints.IntOpenHashSet import it.unimi.dsi.fastutil.ints.IntOpenHashSet
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
import it.unimi.dsi.fastutil.longs.LongOpenHashSet import it.unimi.dsi.fastutil.longs.LongOpenHashSet
import kotlin.collections.set
internal class ReadTrackingIndex : ReadTrackingContext { internal class ReadTrackingIndex : ReadTrackingContext {
companion object { companion object {

View File

@@ -1,5 +1,5 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.kernel package com.intellij.platform.kernel.util
import com.jetbrains.rhizomedb.CascadeDeleteBy import com.jetbrains.rhizomedb.CascadeDeleteBy
import com.jetbrains.rhizomedb.Unique import com.jetbrains.rhizomedb.Unique

View File

@@ -1,7 +1,6 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.kernel package com.intellij.platform.kernel.util
import com.intellij.fleet.kernel.KernelService
import com.intellij.openapi.application.ModalityState import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.asContextElement import com.intellij.openapi.application.asContextElement
import com.intellij.util.concurrency.annotations.RequiresEdt import com.intellij.util.concurrency.annotations.RequiresEdt
@@ -11,7 +10,6 @@ import fleet.kernel.Kernel
import fleet.kernel.KernelMiddleware import fleet.kernel.KernelMiddleware
import fleet.kernel.kernel import fleet.kernel.kernel
import fleet.kernel.rebase.* import fleet.kernel.rebase.*
import fleet.kernel.rete.Rete
import fleet.kernel.rete.withRete import fleet.kernel.rete.withRete
import fleet.kernel.subscribe import fleet.kernel.subscribe
import fleet.rpc.core.Serialization import fleet.rpc.core.Serialization
@@ -26,7 +24,7 @@ import java.util.concurrent.atomic.AtomicInteger
@ApiStatus.Internal @ApiStatus.Internal
@ApiStatus.Experimental @ApiStatus.Experimental
suspend fun <T> withKernel(scope: CoroutineScope, middleware: KernelMiddleware, body: suspend () -> T) { suspend fun <T> withKernel(middleware: KernelMiddleware, body: suspend () -> T) {
val entityClasses = listOf(Kernel::class.java.classLoader).flatMap(::collectEntityClasses) val entityClasses = listOf(Kernel::class.java.classLoader).flatMap(::collectEntityClasses)
fleet.kernel.withKernel(entityClasses, middleware = middleware) { currentKernel -> fleet.kernel.withKernel(entityClasses, middleware = middleware) { currentKernel ->
withRete { withRete {
@@ -99,30 +97,6 @@ object ReadTracker {
} }
} }
val FleetRpcSerialization = Serialization(SerializersModule { val KernelRpcSerialization = Serialization(SerializersModule {
registerCRUDInstructions() registerCRUDInstructions()
}) })
class BaseKernelService(coroutineScope: CoroutineScope) : KernelService {
private val kernelDeferred: CompletableDeferred<Kernel> = CompletableDeferred()
private val reteDeferred : CompletableDeferred<Rete> = CompletableDeferred()
init {
coroutineScope.launch(start = CoroutineStart.ATOMIC) {
withKernel(this, middleware = LeaderKernelMiddleware(FleetRpcSerialization, CommonInstructionSet.encoder())) {
kernelDeferred.complete(kernel())
reteDeferred.complete(currentCoroutineContext()[Rete]!!)
ReadTracker.subscribeForChanges()
}
}
runBlocking {
kernelDeferred.await()
reteDeferred.await()
}
}
override val kernel: Kernel
get() = kernelDeferred.getCompleted()
override val rete: Rete
get() = reteDeferred.getCompleted()
}

View File

@@ -1,7 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.kernel package com.intellij.platform.kernel.util
import com.intellij.fleet.kernel.KernelService import com.intellij.platform.kernel.KernelService
import com.intellij.util.concurrency.annotations.RequiresEdt import com.intellij.util.concurrency.annotations.RequiresEdt
import com.jetbrains.rhizomedb.EID import com.jetbrains.rhizomedb.EID
import com.jetbrains.rhizomedb.entity import com.jetbrains.rhizomedb.entity
@@ -153,7 +153,6 @@ private class ModelChangeScopeImpl(val sharedChangeScope: SharedChangeScope) : M
val value = serialization.json.encodeToJsonElement(serialization.kSerializer(ktype), value) val value = serialization.json.encodeToJsonElement(serialization.kSerializer(ktype), value)
val viewModel = lookupOne(ViewModelEntity::modelId, id) val viewModel = lookupOne(ViewModelEntity::modelId, id)
if (viewModel == null) { if (viewModel == null) {
println("Aha")
throw IllegalStateException("ViewModelEntity not found for model $id") throw IllegalStateException("ViewModelEntity not found for model $id")
} }
val alreadyExist = lookupOne(ModelPropertyEntity::id, fqn) val alreadyExist = lookupOne(ModelPropertyEntity::id, fqn)