From 0e43a1e2dd3d49c2b81410817c1163b6dcecd34c Mon Sep 17 00:00:00 2001 From: Kate Botsman Date: Mon, 19 Aug 2024 17:20:08 +0200 Subject: [PATCH] RDCT-1444 Add TaskStorage implementations for frontend.split and backend `TaskStorage` service is responsible for storing/updating/removing tasks from Rhizome DB. There are two implementations of the service - backend (available in mononlith and backend.split) and frontend.split The backend implementation stores `TaskInfoEntity` into a shared partition of DB, so the tasks can be available both on backend and all connected frontends. Frontend split implementation stores `TaskInfoEntity` into a local partition of DB, so the tasks produced by one of the frontends won't be available for backend or other frontends. Consider "Code With Me" case here: when one of the guests starts some tasks, it shouldn't be visible to other guests. However, if the host starts a task - all guests should see it. GitOrigin-RevId: a020d871d2f5f88809dfed551f511b116e8ff550 --- .../intellij.platform.progress.backend.iml | 3 + .../intellij.platform.progress.backend.xml | 8 ++ .../backend/src/BackendTaskStorage.kt | 37 ++++++ platform/progress/shared/src/TaskStorage.kt | 112 ++++++++++++++++++ 4 files changed, 160 insertions(+) create mode 100644 platform/progress/backend/src/BackendTaskStorage.kt create mode 100644 platform/progress/shared/src/TaskStorage.kt diff --git a/platform/progress/backend/intellij.platform.progress.backend.iml b/platform/progress/backend/intellij.platform.progress.backend.iml index cc47feec4168..02178f3399b6 100644 --- a/platform/progress/backend/intellij.platform.progress.backend.iml +++ b/platform/progress/backend/intellij.platform.progress.backend.iml @@ -10,5 +10,8 @@ + + + \ No newline at end of file diff --git a/platform/progress/backend/resources/intellij.platform.progress.backend.xml b/platform/progress/backend/resources/intellij.platform.progress.backend.xml index 5d5af172a5ae..1d9ab52d2645 100644 --- a/platform/progress/backend/resources/intellij.platform.progress.backend.xml +++ b/platform/progress/backend/resources/intellij.platform.progress.backend.xml @@ -3,4 +3,12 @@ + + + + + + + diff --git a/platform/progress/backend/src/BackendTaskStorage.kt b/platform/progress/backend/src/BackendTaskStorage.kt new file mode 100644 index 000000000000..f2e442430480 --- /dev/null +++ b/platform/progress/backend/src/BackendTaskStorage.kt @@ -0,0 +1,37 @@ +// 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.progress.backend + +import com.intellij.platform.ide.progress.TaskInfoEntity +import com.intellij.platform.ide.progress.TaskStorage +import com.jetbrains.rhizomedb.ChangeScope +import fleet.kernel.change +import fleet.kernel.delete +import fleet.kernel.shared +import org.jetbrains.annotations.ApiStatus + +@ApiStatus.Internal +class BackendTaskStorage : TaskStorage() { + override suspend fun createTaskInfoEntity(provider: ChangeScope.() -> TaskInfoEntity): TaskInfoEntity { + return change { + shared { + provider() + } + } + } + + override suspend fun removeTaskInfoEntity(taskInfoEntity: TaskInfoEntity) { + change { + shared { + delete(taskInfoEntity) + } + } + } + + override suspend fun updateTaskInfoEntity(updater: ChangeScope.() -> Unit) { + change { + shared { + updater() + } + } + } +} diff --git a/platform/progress/shared/src/TaskStorage.kt b/platform/progress/shared/src/TaskStorage.kt new file mode 100644 index 000000000000..9e094b5b9c09 --- /dev/null +++ b/platform/progress/shared/src/TaskStorage.kt @@ -0,0 +1,112 @@ +// 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.ide.progress + +import com.intellij.openapi.components.service +import com.intellij.platform.kernel.KernelService +import com.intellij.platform.util.progress.ProgressState +import com.jetbrains.rhizomedb.ChangeScope +import fleet.kernel.withEntities +import kotlinx.coroutines.withContext +import org.jetbrains.annotations.ApiStatus + +/** + * Provides the ability to control how tasks are stored in Rhizome DB + * The implementation can decide where to store an object - in shared or local DB + * See [fleet.kernel.change] and [fleet.kernel.shared] + */ +@ApiStatus.Internal +abstract class TaskStorage { + + /** + * Adds a new task to the storage and returns the created [TaskInfoEntity]. + * + * @param title The title of the task. + * @param cancellation Specifies if the task can be canceled. + * @return The created [TaskInfoEntity]. + */ + suspend fun addTask( + title: String, + cancellation: TaskCancellation, + ): TaskInfoEntity = withContext(KernelService.kernelCoroutineContext()) { + createTaskInfoEntity { + TaskInfoEntity.new { + it[TaskInfoEntity.Title] = title + it[TaskInfoEntity.TaskCancellationType] = cancellation + it[TaskInfoEntity.ProgressStateType] = null + it[TaskInfoEntity.TaskStatusType] = TaskStatus.RUNNING + } + } + } + + /** + * Creates a new [TaskInfoEntity] using [provider] lambda + * The implementation can decide whether the entity should be created locally on in the shared DB scope. + * + * It's guaranteed that the method is called in the correct coroutine context, + * which includes kernel (see [KernelService.kernelCoroutineContext]) + * + * @param provider The provider used to create the [TaskInfoEntity]. + * @return The created [TaskInfoEntity]. + */ + protected abstract suspend fun createTaskInfoEntity(provider: ChangeScope.() -> TaskInfoEntity): TaskInfoEntity + + /** + * Removes a task from Rhizome DB. + * NOTE: this doesn't cancel a running task, to cancel a task use [TaskManager.cancelTask] + * + * @param taskInfoEntity The task to be removed. + */ + suspend fun removeTask(taskInfoEntity: TaskInfoEntity): Unit = withContext(KernelService.kernelCoroutineContext()) { + withEntities(taskInfoEntity) { + removeTaskInfoEntity(taskInfoEntity) + } + } + + /** + * Removes the specified task from the storage. + * The implementation should use the same scope as in [createTaskInfoEntity] to remove the entity. + * + * It's guaranteed that only the task created by this instance of [TaskStorage] + * are going to be passed to this method. + * + * It is also guaranteed that the method is called in the correct coroutine context, + * which includes kernel (see [KernelService.kernelCoroutineContext]) + * + * @param taskInfoEntity The task entity to be removed. + */ + protected abstract suspend fun removeTaskInfoEntity(taskInfoEntity: TaskInfoEntity) + + /** + * Updates the progress state of the given task. + * Old state is going to be overwritten, to receive all state updates use [updates] + * + * @param taskInfoEntity The task to be updated. + * @param state The new progress state to set on the task. + * @return Unit + */ + suspend fun updateTask(taskInfoEntity: TaskInfoEntity, state: ProgressState): Unit = withContext(KernelService.kernelCoroutineContext()) { + withEntities(taskInfoEntity) { + updateTaskInfoEntity { + taskInfoEntity[TaskInfoEntity.ProgressStateType] = state + } + } + } + + /** + * Updates a [TaskInfoEntity] in the storage using provided [updater] + * + * It's guaranteed that only the task created by this instance of [TaskStorage] + * are going to be passed to this method. + * + * It is also guaranteed that the method is called in the correct coroutine context, + * which includes kernel (see [KernelService.kernelCoroutineContext]) + * + * @param updater A lambda provided with a [ChangeScope] receiver to modify the task information. + */ + protected abstract suspend fun updateTaskInfoEntity(updater: ChangeScope.() -> Unit) + + companion object { + @JvmStatic + fun getInstance(): TaskStorage = service() + } +}