diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2022-11-01 10:38:26 +0100 |
|---|---|---|
| committer | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2022-11-27 20:49:33 +0000 |
| commit | 6bbfbd7aeb99475308a140222316f3e9006aeec3 (patch) | |
| tree | ab590fa208cb98edd419fa55873a01d17ee67433 /opendc-compute/opendc-compute-service | |
| parent | 2ca72c0b62e08efd244eba1723bc4fc65d30eed2 (diff) | |
refactor(compute/api): Do not suspend in compute API
This change updates the API interface of the OpenDC Compute service to
not suspend execution using Kotlin Coroutines.
The suspending modifiers were introduced in case the ComputeClient would
communicate with the service over a network connection. However, the main
use-case has been together with the ComputeService, where the suspending
modifiers only frustrate the user experience when writing experiments.
Furthermore, with the advent of Project Loom, it is not necessarily a
problem to block the (virtual) thread during network communications.
Diffstat (limited to 'opendc-compute/opendc-compute-service')
8 files changed, 150 insertions, 145 deletions
diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt index 4a8d3046..45a3d472 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientFlavor.kt @@ -46,12 +46,12 @@ internal class ClientFlavor(private val delegate: Flavor) : Flavor { override var meta: Map<String, Any> = delegate.meta.toMap() private set - override suspend fun delete() { + override fun delete() { delegate.delete() } - override suspend fun refresh() { - delegate.refresh() + override fun reload() { + delegate.reload() name = delegate.name cpuCount = delegate.cpuCount diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientImage.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientImage.kt index f0032acf..eb963f0e 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientImage.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientImage.kt @@ -40,13 +40,13 @@ internal class ClientImage(private val delegate: Image) : Image { override var meta: Map<String, Any> = delegate.meta.toMap() private set - override suspend fun delete() { + override fun delete() { delegate.delete() - refresh() + reload() } - override suspend fun refresh() { - delegate.refresh() + override fun reload() { + delegate.reload() name = delegate.name labels = delegate.labels diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt index 6cd7d30f..f2248466 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ClientServer.kt @@ -59,19 +59,19 @@ internal class ClientServer(private val delegate: Server) : Server, ServerWatche override var launchedAt: Instant? = null private set - override suspend fun start() { + override fun start() { delegate.start() - refresh() + reload() } - override suspend fun stop() { + override fun stop() { delegate.stop() - refresh() + reload() } - override suspend fun delete() { + override fun delete() { delegate.delete() - refresh() + reload() } override fun watch(watcher: ServerWatcher) { @@ -90,8 +90,8 @@ internal class ClientServer(private val delegate: Server) : Server, ServerWatche } } - override suspend fun refresh() { - delegate.refresh() + override fun reload() { + delegate.reload() name = delegate.name flavor = delegate.flavor diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt index 77932545..ffebd5fa 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/ComputeServiceImpl.kt @@ -122,118 +122,7 @@ internal class ComputeServiceImpl( override fun newClient(): ComputeClient { check(!isClosed) { "Service is already closed" } - return object : ComputeClient { - private var isClosed: Boolean = false - - override suspend fun queryFlavors(): List<Flavor> { - check(!isClosed) { "Client is already closed" } - - return flavorById.values.map { ClientFlavor(it) } - } - - override suspend fun findFlavor(id: UUID): Flavor? { - check(!isClosed) { "Client is already closed" } - - return flavorById[id]?.let { ClientFlavor(it) } - } - - override suspend fun newFlavor( - name: String, - cpuCount: Int, - memorySize: Long, - labels: Map<String, String>, - meta: Map<String, Any> - ): Flavor { - check(!isClosed) { "Client is already closed" } - - val uid = UUID(clock.millis(), random.nextLong()) - val flavor = InternalFlavor( - this@ComputeServiceImpl, - uid, - name, - cpuCount, - memorySize, - labels, - meta - ) - - flavorById[uid] = flavor - - return ClientFlavor(flavor) - } - - override suspend fun queryImages(): List<Image> { - check(!isClosed) { "Client is already closed" } - - return imageById.values.map { ClientImage(it) } - } - - override suspend fun findImage(id: UUID): Image? { - check(!isClosed) { "Client is already closed" } - - return imageById[id]?.let { ClientImage(it) } - } - - override suspend fun newImage(name: String, labels: Map<String, String>, meta: Map<String, Any>): Image { - check(!isClosed) { "Client is already closed" } - - val uid = UUID(clock.millis(), random.nextLong()) - val image = InternalImage(this@ComputeServiceImpl, uid, name, labels, meta) - - imageById[uid] = image - - return ClientImage(image) - } - - override suspend fun newServer( - name: String, - image: Image, - flavor: Flavor, - labels: Map<String, String>, - meta: Map<String, Any>, - start: Boolean - ): Server { - check(!isClosed) { "Client is closed" } - - val uid = UUID(clock.millis(), random.nextLong()) - val server = InternalServer( - this@ComputeServiceImpl, - uid, - name, - requireNotNull(flavorById[flavor.uid]) { "Unknown flavor" }, - requireNotNull(imageById[image.uid]) { "Unknown image" }, - labels.toMutableMap(), - meta.toMutableMap() - ) - - serverById[uid] = server - servers.add(server) - - if (start) { - server.start() - } - - return ClientServer(server) - } - - override suspend fun findServer(id: UUID): Server? { - check(!isClosed) { "Client is already closed" } - - return serverById[id]?.let { ClientServer(it) } - } - - override suspend fun queryServers(): List<Server> { - check(!isClosed) { "Client is already closed" } - - return serverById.values.map { ClientServer(it) } - } - - override fun close() { - isClosed = true - } - - override fun toString(): String = "ComputeClient" - } + return Client(this) } override fun addHost(host: Host) { @@ -460,4 +349,120 @@ internal class ComputeServiceImpl( requestSchedulingCycle() } } + + /** + * Implementation of [ComputeClient] using a [ComputeService]. + */ + private class Client(private val service: ComputeServiceImpl) : ComputeClient { + private var isClosed: Boolean = false + + override fun queryFlavors(): List<Flavor> { + check(!isClosed) { "Client is already closed" } + + return service.flavorById.values.map { ClientFlavor(it) } + } + + override fun findFlavor(id: UUID): Flavor? { + check(!isClosed) { "Client is already closed" } + + return service.flavorById[id]?.let { ClientFlavor(it) } + } + + override fun newFlavor( + name: String, + cpuCount: Int, + memorySize: Long, + labels: Map<String, String>, + meta: Map<String, Any> + ): Flavor { + check(!isClosed) { "Client is already closed" } + + val uid = UUID(service.clock.millis(), service.random.nextLong()) + val flavor = InternalFlavor( + service, + uid, + name, + cpuCount, + memorySize, + labels, + meta + ) + + service.flavorById[uid] = flavor + + return ClientFlavor(flavor) + } + + override fun queryImages(): List<Image> { + check(!isClosed) { "Client is already closed" } + + return service.imageById.values.map { ClientImage(it) } + } + + override fun findImage(id: UUID): Image? { + check(!isClosed) { "Client is already closed" } + + return service.imageById[id]?.let { ClientImage(it) } + } + + override fun newImage(name: String, labels: Map<String, String>, meta: Map<String, Any>): Image { + check(!isClosed) { "Client is already closed" } + + val uid = UUID(service.clock.millis(), service.random.nextLong()) + val image = InternalImage(service, uid, name, labels, meta) + + service.imageById[uid] = image + + return ClientImage(image) + } + + override fun newServer( + name: String, + image: Image, + flavor: Flavor, + labels: Map<String, String>, + meta: Map<String, Any>, + start: Boolean + ): Server { + check(!isClosed) { "Client is closed" } + + val uid = UUID(service.clock.millis(), service.random.nextLong()) + val server = InternalServer( + service, + uid, + name, + requireNotNull(service.flavorById[flavor.uid]) { "Unknown flavor" }, + requireNotNull(service.imageById[image.uid]) { "Unknown image" }, + labels.toMutableMap(), + meta.toMutableMap() + ) + + service.serverById[uid] = server + service.servers.add(server) + + if (start) { + server.start() + } + + return ClientServer(server) + } + + override fun findServer(id: UUID): Server? { + check(!isClosed) { "Client is already closed" } + + return service.serverById[id]?.let { ClientServer(it) } + } + + override fun queryServers(): List<Server> { + check(!isClosed) { "Client is already closed" } + + return service.serverById.values.map { ClientServer(it) } + } + + override fun close() { + isClosed = true + } + + override fun toString(): String = "ComputeService.Client" + } } diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt index acd87dfc..077ec865 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalFlavor.kt @@ -50,11 +50,11 @@ internal class InternalFlavor( override val meta: MutableMap<String, Any> = meta.toMutableMap() - override suspend fun refresh() { + override fun reload() { // No-op: this object is the source-of-truth } - override suspend fun delete() { + override fun delete() { service.delete(this) } diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt index a0a35a55..b27ef33a 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalImage.kt @@ -40,11 +40,11 @@ internal class InternalImage( override val meta: MutableMap<String, Any> = meta.toMutableMap() - override suspend fun refresh() { + override fun reload() { // No-op: this object is the source-of-truth } - override suspend fun delete() { + override fun delete() { service.delete(this) } diff --git a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt index e3bae405..c1353ba1 100644 --- a/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt +++ b/opendc-compute/opendc-compute-service/src/main/kotlin/org/opendc/compute/service/internal/InternalServer.kt @@ -67,7 +67,7 @@ internal class InternalServer( */ private var request: ComputeServiceImpl.SchedulingRequest? = null - override suspend fun start() { + override fun start() { when (state) { ServerState.RUNNING -> { logger.debug { "User tried to start server but server is already running" } @@ -90,7 +90,7 @@ internal class InternalServer( } } - override suspend fun stop() { + override fun stop() { when (state) { ServerState.PROVISIONING -> { cancelProvisioningRequest() @@ -104,7 +104,7 @@ internal class InternalServer( } } - override suspend fun delete() { + override fun delete() { when (state) { ServerState.PROVISIONING, ServerState.TERMINATED -> { cancelProvisioningRequest() @@ -129,7 +129,7 @@ internal class InternalServer( watchers -= watcher } - override suspend fun refresh() { + override fun reload() { // No-op: this object is the source-of-truth } diff --git a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt index b5685aba..13b926e8 100644 --- a/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt +++ b/opendc-compute/opendc-compute-service/src/test/kotlin/org/opendc/compute/service/ComputeServiceTest.kt @@ -170,7 +170,7 @@ internal class ComputeServiceTest { server.start() delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.TERMINATED, server.state) } @@ -183,7 +183,7 @@ internal class ComputeServiceTest { server.start() delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.TERMINATED, server.state) } @@ -196,7 +196,7 @@ internal class ComputeServiceTest { server.start() delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.TERMINATED, server.state) } @@ -210,7 +210,7 @@ internal class ComputeServiceTest { server.start() server.stop() delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.TERMINATED, server.state) } @@ -231,7 +231,7 @@ internal class ComputeServiceTest { server.start() delay(10L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.PROVISIONING, server.state) verify { host.canFit(server) } @@ -262,7 +262,7 @@ internal class ComputeServiceTest { listeners.forEach { it.onStateChanged(host, HostState.UP) } delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.PROVISIONING, server.state) verify { host.canFit(server) } @@ -293,7 +293,7 @@ internal class ComputeServiceTest { server.start() delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.PROVISIONING, server.state) verify(exactly = 0) { host.canFit(server) } @@ -351,7 +351,7 @@ internal class ComputeServiceTest { listeners.forEach { it.onStateChanged(host, slot.captured, ServerState.RUNNING) } - server.refresh() + server.reload() assertEquals(ServerState.RUNNING, server.state) verify { watcher.onStateChanged(server, ServerState.RUNNING) } @@ -359,7 +359,7 @@ internal class ComputeServiceTest { // Stop server listeners.forEach { it.onStateChanged(host, slot.captured, ServerState.TERMINATED) } - server.refresh() + server.reload() assertEquals(ServerState.TERMINATED, server.state) verify { watcher.onStateChanged(server, ServerState.TERMINATED) } @@ -387,7 +387,7 @@ internal class ComputeServiceTest { server.start() delay(5L * 60 * 1000) - server.refresh() + server.reload() assertEquals(ServerState.PROVISIONING, server.state) } } |
