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

Rework encoding to reduce lambdas usage #258

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ ij_editorconfig_spaces_around_assignment_operators = true

[{*.kt,*.kts}]
ktlint_standard_filename = disabled
ktlint_standard_class-signature = disabled
ktlint_standard_function-signature = disabled
ktlint_standard_chain-method-continuation = disabled
ktlint_standard_function-expression-body = disabled
ij_kotlin_align_in_columns_case_branch = false
ij_kotlin_align_multiline_binary_operation = false
ij_kotlin_align_multiline_extends_list = false
Expand Down
21 changes: 2 additions & 19 deletions api/avro4k-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public abstract class com/github/avrokotlin/avro4k/Avro : kotlinx/serialization/
public fun encodeToByteArray (Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)[B
public final fun encodeToByteArray (Lorg/apache/avro/Schema;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)[B
public final fun getConfiguration ()Lcom/github/avrokotlin/avro4k/AvroConfiguration;
public fun getSerializersModule ()Lkotlinx/serialization/modules/SerializersModule;
public final fun getSerializersModule ()Lkotlinx/serialization/modules/SerializersModule;
public final fun schema (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lorg/apache/avro/Schema;
}

Expand Down Expand Up @@ -113,10 +113,9 @@ public synthetic class com/github/avrokotlin/avro4k/AvroDoc$Impl : com/github/av
}

public abstract interface class com/github/avrokotlin/avro4k/AvroEncoder : kotlinx/serialization/encoding/Encoder {
public abstract fun encodeBytes (Ljava/nio/ByteBuffer;)V
public abstract fun encodeBytes ([B)V
public abstract fun encodeFixed (Lorg/apache/avro/generic/GenericFixed;)V
public abstract fun encodeFixed ([B)V
public abstract fun encodeUnionIndex (I)V
public abstract fun getCurrentWriterSchema ()Lorg/apache/avro/Schema;
}

Expand All @@ -127,11 +126,6 @@ public final class com/github/avrokotlin/avro4k/AvroEncoder$DefaultImpls {
public static fun encodeSerializableValue (Lcom/github/avrokotlin/avro4k/AvroEncoder;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V
}

public final class com/github/avrokotlin/avro4k/AvroEncoderKt {
public static final fun encodeResolving (Lcom/github/avrokotlin/avro4k/AvroEncoder;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun resolveUnion (Lcom/github/avrokotlin/avro4k/AvroEncoder;Lorg/apache/avro/Schema;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
}

public abstract interface annotation class com/github/avrokotlin/avro4k/AvroEnumDefault : java/lang/annotation/Annotation {
}

Expand Down Expand Up @@ -330,17 +324,6 @@ public final class com/github/avrokotlin/avro4k/UnionDecoder$DefaultImpls {
public static fun decodeSerializableValue (Lcom/github/avrokotlin/avro4k/UnionDecoder;Lkotlinx/serialization/DeserializationStrategy;)Ljava/lang/Object;
}

public abstract interface class com/github/avrokotlin/avro4k/UnionEncoder : com/github/avrokotlin/avro4k/AvroEncoder {
public abstract fun encodeUnionIndex (I)V
}

public final class com/github/avrokotlin/avro4k/UnionEncoder$DefaultImpls {
public static fun beginCollection (Lcom/github/avrokotlin/avro4k/UnionEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;I)Lkotlinx/serialization/encoding/CompositeEncoder;
public static fun encodeNotNullMark (Lcom/github/avrokotlin/avro4k/UnionEncoder;)V
public static fun encodeNullableSerializableValue (Lcom/github/avrokotlin/avro4k/UnionEncoder;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V
public static fun encodeSerializableValue (Lcom/github/avrokotlin/avro4k/UnionEncoder;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V
}

public final class com/github/avrokotlin/avro4k/serializer/AvroDuration {
public static final field Companion Lcom/github/avrokotlin/avro4k/serializer/AvroDuration$Companion;
public synthetic fun <init> (IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
Expand Down
30 changes: 15 additions & 15 deletions benchmark/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,25 @@ Computer: Macbook air M2

```
Benchmark Mode Cnt Score Error Units Relative Difference (%)
c.g.a.b.complex.Avro4kBenchmark.read thrpt 5 23897.142 ± 565.722 ops/s 0.00%
c.g.a.b.complex.ApacheAvroReflectBenchmark.read thrpt 5 21609.748 ± 194.480 ops/s -9.57%
c.g.a.b.complex.Avro4kGenericWithApacheAvroBenchmark.read thrpt 5 14003.544 ± 41.383 ops/s -41.42%
c.g.a.b.complex.Avro4kBenchmark.read thrpt 5 23698.026 ± 460.150 ops/s 0.00%
c.g.a.b.complex.ApacheAvroReflectBenchmark.read thrpt 5 21124.413 ± 274.425 ops/s -10.90%
c.g.a.b.complex.Avro4kGenericWithApacheAvroBenchmark.read thrpt 5 14314.182 ± 455.019 ops/s -39.60%

c.g.a.b.complex.Avro4kBenchmark.write thrpt 5 54174.691 ± 79.533 ops/s 0.00%
c.g.a.b.complex.ApacheAvroReflectBenchmark.write thrpt 5 48289.132 ± 1718.797 ops/s -10.85%
c.g.a.b.complex.JacksonAvroBenchmark.write thrpt 5 36604.599 ± 242.069 ops/s -32.43%
c.g.a.b.complex.Avro4kGenericWithApacheAvroBenchmark.write thrpt 5 28092.785 ± 1267.990 ops/s -48.15%
c.g.a.b.complex.Avro4kBenchmark.write thrpt 5 54341.631 ± 1033.605 ops/s 0.00%
c.g.a.b.complex.ApacheAvroReflectBenchmark.write thrpt 5 49805.980 ± 1783.130 ops/s -8.35%
c.g.a.b.complex.JacksonAvroBenchmark.write thrpt 5 34076.802 ± 1358.108 ops/s -37.31%
c.g.a.b.complex.Avro4kGenericWithApacheAvroBenchmark.write thrpt 5 23874.900 ± 7088.413 ops/s -56.06%


c.g.a.b.simple.Avro4kSimpleBenchmark.read thrpt 5 174063.241 ± 7852.646 ops/s 0.00%
c.g.a.b.simple.ApacheAvroReflectSimpleBenchmark.read thrpt 5 159204.806 ± 413.516 ops/s -8.54%
c.g.a.b.simple.Avro4kGenericWithApacheAvroSimpleBenchmark.read thrpt 5 114511.133 ± 227.407 ops/s -34.23%
c.g.a.b.simple.JacksonAvroSimpleBenchmark.read thrpt 5 67811.540 ± 212.367 ops/s -61.05%
c.g.a.b.simple.Avro4kSimpleBenchmark.read thrpt 5 144353.049 ± 3769.344 ops/s 0.00%
c.g.a.b.simple.ApacheAvroReflectSimpleBenchmark.read thrpt 5 138120.480 ± 4272.476 ops/s -4.32%
c.g.a.b.simple.Avro4kGenericWithApacheAvroSimpleBenchmark.read thrpt 5 108761.202 ± 2228.366 ops/s -24.65%
c.g.a.b.simple.JacksonAvroSimpleBenchmark.read thrpt 5 67907.379 ± 1626.214 ops/s -52.98%

c.g.a.b.simple.Avro4kSimpleBenchmark.write thrpt 5 459751.939 ± 46513.718 ops/s 0.00%
c.g.a.b.simple.ApacheAvroReflectSimpleBenchmark.write thrpt 5 355544.645 ± 14835.972 ops/s -22.65%
c.g.a.b.simple.Avro4kGenericWithApacheAvroSimpleBenchmark.write thrpt 5 190365.959 ± 1014.944 ops/s -58.60%
c.g.a.b.simple.JacksonAvroSimpleBenchmark.write thrpt 5 131492.564 ± 10888.843 ops/s -71.40%
c.g.a.b.simple.Avro4kSimpleBenchmark.write thrpt 5 403931.630 ± 5276.622 ops/s 0.00%
c.g.a.b.simple.ApacheAvroReflectSimpleBenchmark.write thrpt 5 244455.414 ± 3681.089 ops/s -39.46%
c.g.a.b.simple.Avro4kGenericWithApacheAvroSimpleBenchmark.write thrpt 5 153565.472 ± 1900.814 ops/s -61.99%
c.g.a.b.simple.JacksonAvroSimpleBenchmark.write thrpt 5 129912.932 ± 2788.534 ops/s -67.84%
```

> [!WARNING]
Expand Down
10 changes: 5 additions & 5 deletions benchmark/api/benchmark.api
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,25 @@ public final class com/github/avrokotlin/benchmark/internal/Partner$Companion {
public final class com/github/avrokotlin/benchmark/internal/SimpleDataClass {
public static final field Companion Lcom/github/avrokotlin/benchmark/internal/SimpleDataClass$Companion;
public fun <init> ()V
public fun <init> (ZBSIJFDLjava/lang/String;[B)V
public fun <init> (ZBSLjava/lang/Integer;JFDLjava/lang/String;[B)V
public final fun component1 ()Z
public final fun component2 ()B
public final fun component3 ()S
public final fun component4 ()I
public final fun component4 ()Ljava/lang/Integer;
public final fun component5 ()J
public final fun component6 ()F
public final fun component7 ()D
public final fun component8 ()Ljava/lang/String;
public final fun component9 ()[B
public final fun copy (ZBSIJFDLjava/lang/String;[B)Lcom/github/avrokotlin/benchmark/internal/SimpleDataClass;
public static synthetic fun copy$default (Lcom/github/avrokotlin/benchmark/internal/SimpleDataClass;ZBSIJFDLjava/lang/String;[BILjava/lang/Object;)Lcom/github/avrokotlin/benchmark/internal/SimpleDataClass;
public final fun copy (ZBSLjava/lang/Integer;JFDLjava/lang/String;[B)Lcom/github/avrokotlin/benchmark/internal/SimpleDataClass;
public static synthetic fun copy$default (Lcom/github/avrokotlin/benchmark/internal/SimpleDataClass;ZBSLjava/lang/Integer;JFDLjava/lang/String;[BILjava/lang/Object;)Lcom/github/avrokotlin/benchmark/internal/SimpleDataClass;
public fun equals (Ljava/lang/Object;)Z
public final fun getBool ()Z
public final fun getByte ()B
public final fun getBytes ()[B
public final fun getDouble ()D
public final fun getFloat ()F
public final fun getInt ()I
public final fun getInt ()Ljava/lang/Integer;
public final fun getLong ()J
public final fun getShort ()S
public final fun getString ()Ljava/lang/String;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.github.avrokotlin.benchmark

import com.github.avrokotlin.benchmark.complex.Avro4kBenchmark
import com.github.avrokotlin.benchmark.simple.JacksonAvroSimpleBenchmark

internal object ManualProfilingWrite {
@JvmStatic
fun main(vararg args: String) {
JacksonAvroSimpleBenchmark().apply {
Avro4kBenchmark().apply {
initTestData()
for (i in 0 until 1_000_000) {
if (i % 1_000 == 0) println("Iteration $i")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ data class SimpleDataClass(
val bool: Boolean,
val byte: Byte,
val short: Short,
val int: Int,
val int: Int?,
val long: Long,
val float: Float,
val double: Double,
val string: String,
val string: String?,
val bytes: ByteArray,
) {
companion object {
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ dependencies {
testImplementation(libs.kotest.core)
testImplementation(libs.kotest.json)
testImplementation(libs.kotest.property)
testImplementation(kotlin("reflect"))
}

kotlin {
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/github/avrokotlin/avro4k/Avro.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import java.io.ByteArrayInputStream
*/
public sealed class Avro(
public val configuration: AvroConfiguration,
public override val serializersModule: SerializersModule,
public final override val serializersModule: SerializersModule,
) : BinaryFormat {
// We use the identity hash map because we could have multiple descriptors with the same name, especially
// when having 2 different version of the schema for the same name. kotlinx-serialization is instantiating the descriptors
Expand Down
11 changes: 11 additions & 0 deletions src/main/kotlin/com/github/avrokotlin/avro4k/AvroDecoder.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.avrokotlin.avro4k

import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerializationException
import kotlinx.serialization.encoding.Decoder
import org.apache.avro.Schema
import org.apache.avro.generic.GenericFixed
Expand Down Expand Up @@ -317,4 +318,14 @@ internal inline fun <T : Any> AvroDecoder.findValueDecoder(
resolver(schema)
}
return foundResolver ?: throw error()
}

internal fun AvroDecoder.unsupportedWriterTypeError(
mainType: Schema.Type,
vararg fallbackTypes: Schema.Type,
): Throwable {
val fallbacksStr = if (fallbackTypes.isNotEmpty()) ", and also not matching to any compatible type (one of ${fallbackTypes.joinToString()})." else ""
return SerializationException(
"Unsupported schema '${currentWriterSchema.fullName}' for decoded type of ${mainType.getName()}$fallbacksStr. Actual schema: $currentWriterSchema"
)
}
Loading