Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KTOR-6030 Migrate Ktor to kotlinx-io #4032

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

KTOR-6030 Migrate Ktor to kotlinx-io #4032

wants to merge 6 commits into from

Conversation

e5l
Copy link
Member

@e5l e5l commented May 15, 2024

Fix KTOR-6030 Migrate to new kotlinx.io library

@e5l e5l requested review from bjhham, marychatte and Stexxe May 15, 2024 08:59
@e5l e5l self-assigned this May 15, 2024
@e5l e5l changed the title Migrate Ktor to kotlinx-io KTOR-6030 Migrate Ktor to kotlinx-io May 15, 2024
@e5l e5l marked this pull request as ready for review May 17, 2024 08:16
Copy link
Contributor

@bjhham bjhham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A glorious amount of deleted code!

Seems that compilation is broken for common code in the CI. I also can't seem to build on my machine, I might need some instruction if there is any config changes or missing gradle configs.

@@ -138,6 +138,7 @@ internal actual class ConnectionPipeline actual constructor(
if (shouldClose) break
}
} finally {
@Suppress("DEPRECATION")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these close deprecation warnings something we should follow up on? Maybe create a task in YT? The recommendation seems to be using either flushAndClose or cancel.

@@ -214,7 +216,7 @@ class HttpTimeoutTest : ClientLoader() {
parameter("delay", 500)
}.body<ByteReadChannel>()

assertFailsWith<HttpRequestTimeoutException> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should consider wrapping this once again with the HttpRequestTimeoutException... Since we don't have checked exceptions, this could cause some tough-to-diagnose issues for consumers that rely on the current timeout exceptions.

Comment on lines 9 to 22
@Suppress("UnusedReceiverParameter", "UNUSED_PARAMETER")
public fun ByteChannel.attachJob(job: Job) {
job.invokeOnCompletion {
if (it != null) {
cancel(it)
}
}
}

public fun ByteChannel.attachJob(job: ChannelJob) {
attachJob(job.job)
}

public fun ByteChannel(@Suppress("UNUSED_PARAMETER") block: (Throwable?) -> Throwable?): ByteChannel = ByteChannel()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like these functions need some documentation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, will add


internal class SourceByteReadChannel(private val source: Source) : ByteReadChannel {

val created = Exception()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another created exception property?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, will fix

this[index + 1] = (value shr 16).toByte()
this[index + 2] = (value shr 8).toByte()
this[index + 3] = value.toByte()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be cool if kotlinx.io provided these kinds of random-access extensions for ByteArray too since they're all implemented for Buffer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as far as I see, it's used only in WebSocket implementation and can be rather easily replaced with operations on kotlinx-io primitives.
IMO, there is no need to have such functions exposed nor in ktor, nor in kotlinx-io, as more high level primitives should be used.
Additionally, there will be something like this for unsafe access described in Kotlin/kotlinx-io#135 (comment)

}

/**
* Resume waiter.
*/
fun resume() {
suspension.getAndSet(null)?.complete()
val continuation = suspension.getAndUpdate {
if (it == CLOSED) CLOSED else null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be it as? ClosedSlot so that we include the cause / new instance from line 44 val closeContinuation = if (cause != null) ClosedSlot(cause) else CLOSED.

Comment on lines 28 to +47
val fileLength = length()
return CoroutineScope(coroutineContext).writer(CoroutineName("file-reader") + coroutineContext, autoFlush = false) {
val randomAccessFile = RandomAccessFile(this@readChannel, "r")
val writer = CoroutineScope(coroutineContext).writer(CoroutineName("file-reader") + coroutineContext, autoFlush = false) {
require(start >= 0L) { "start position shouldn't be negative but it is $start" }
require(endInclusive <= fileLength - 1) {
"endInclusive points to the position out of the file: file size = $fileLength, endInclusive = $endInclusive"
}

@Suppress("BlockingMethodInNonBlockingContext")
RandomAccessFile(this@readChannel, "r").use { file ->
randomAccessFile.use { file ->
val fileChannel: FileChannel = file.channel
fileChannel.writeToScope(this, start, endInclusive)
}
}.channel
}

writer.invokeOnCompletion {
randomAccessFile.close()
}

return writer.channel
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not read directly with something like:

val source = SystemFileSystem.source(Path(absolutePath))
SourceByteReadChannel(source.buffered())

?

@e5l
Copy link
Member Author

e5l commented May 27, 2024

Hey @bjhham, thank you for the review. Indeed looks like compilation is broken since rebase. I'll check it and address the comments!

Copy link
Contributor

@whyoleg whyoleg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really a big step forward for the ecosystem!

Mostly skimmed though public declarations

/*
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package io.ktor.utils.io.core

public expect interface Closeable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it be replaced with AutoCloseable (with a deprecated typealias, same for use function) as it's stable in Kotlin 2.0?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, will replace this with 2.0.0 bump

}
@Deprecated(
"Use transferTo instead",
ReplaceWith("output.transferTo(this)", "kotlinx.io.transferTo"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace with is not the same as implementation transferFrom vs transferTo

this[index + 1] = (value shr 16).toByte()
this[index + 2] = (value shr 8).toByte()
this[index + 3] = value.toByte()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as far as I see, it's used only in WebSocket implementation and can be rather easily replaced with operations on kotlinx-io primitives.
IMO, there is no need to have such functions exposed nor in ktor, nor in kotlinx-io, as more high level primitives should be used.
Additionally, there will be something like this for unsafe access described in Kotlin/kotlinx-io#135 (comment)


package io.ktor.utils.io.errors

public typealias IOException = kotlinx.io.IOException
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may be those should be deprecated, so users will migrate to kotlinx.io.* types?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, good catch! Will add

private const val DEFAULT_POOL_ARRAY_SIZE = 4096
private const val DEFAULT_POOL_CAPACITY = 128

public val ByteArrayPool: ObjectPool<ByteArray> = object : DefaultPool<ByteArray>(DEFAULT_POOL_CAPACITY) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can it be deprecated and replaced with kotlinx-io APIs (I mean, creating Buffer and using it)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, it can be. Let me check

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It needs a huge rewrite in the other ktor modules. I prefer to keep it in the separate PR for stability

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to create YT issue and link it here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will add

ktor-io/js/src/io/ktor/utils/io/charsets/TextEncoder.js.kt Outdated Show resolved Hide resolved
@bjhham
Copy link
Contributor

bjhham commented May 28, 2024

Looks like ktor-benchmarks is missing the required repository for the snapshot of kotlinx-io?

14:56:11     Execution failed for task ':compileKotlin'.
14:56:11     > Could not resolve all files for configuration ':compileClasspath'.
14:56:11        > Could not find org.jetbrains.kotlinx:kotlinx-io-core:0.3.2-SNAPSHOT.
14:56:11          Searched in the following locations:
14:56:11            - file:/home/teamcity/.m2/repository/org/jetbrains/kotlinx/kotlinx-io-core/0.3.2-SNAPSHOT/maven-metadata.xml
14:56:11            - file:/home/teamcity/.m2/repository/org/jetbrains/kotlinx/kotlinx-io-core/0.3.2-SNAPSHOT/kotlinx-io-core-0.3.2-SNAPSHOT.pom
14:56:11            - https://repo.maven.apache.org/maven2/org/jetbrains/kotlinx/kotlinx-io-core/0.3.2-SNAPSHOT/maven-metadata.xml
14:56:11            - https://repo.maven.apache.org/maven2/org/jetbrains/kotlinx/kotlinx-io-core/0.3.2-SNAPSHOT/kotlinx-io-core-0.3.2-SNAPSHOT.pom
14:56:11            - https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/org/jetbrains/kotlinx/kotlinx-io-core/0.3.2-SNAPSHOT/maven-metadata.xml
14:56:11            - https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/org/jetbrains/kotlinx/kotlinx-io-core/0.3.2-SNAPSHOT/kotlinx-io-core-0.3.2-SNAPSHOT.pom
14:56:11            - https://maven.pkg.jetbrains.space/public/p/ktor/eap/org/jetbrains/kotlinx/kotlinx-io-core/0.3.2-SNAPSHOT/maven-metadata.xml
14:56:11            - https://maven.pkg.jetbrains.space/public/p/ktor/eap/org/jetbrains/kotlinx/kotlinx-io-core/0.3.2-SNAPSHOT/kotlinx-io-core-0.3.2-SNAPSHOT.pom
14:56:11          Required by:
14:56:11              project : > io.ktor:ktor-server-core:1.0.0-BENCHMARKS > io.ktor:ktor-server-core-jvm:1.0.0-BENCHMARKS > io.ktor:ktor-utils:1.0.0-BENCHMARKS > io.ktor:ktor-utils-jvm:1.0.0-BENCHMARKS > io.ktor:ktor-io:1.0.0-BENCHMARKS > io.ktor:ktor-io-jvm:1.0.0-BENCHMARKS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants