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

ERS optimizations #265

Merged
merged 2 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ interface Transaction : Closeable {
/**
* Returns set of blob names ever being set to an entity of specified `type`.
*/
fun getBlobNamesNames(type: String): Set<String> = emptySet()
fun getBlobNames(type: String): Set<String> = emptySet()

/**
* Returns set of link names ever being set to an entity of specified `type`.
*/
fun getLinkNamesNames(type: String): Set<String> = emptySet()
fun getLinkNames(type: String): Set<String> = emptySet()

fun all(type: String): EntityIterable

Expand Down
20 changes: 4 additions & 16 deletions jacodb-core/src/main/kotlin/org/jacodb/impl/Async.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,21 @@
fun <W, T> softLazy(getter: () -> T): ReadOnlyProperty<W, T> {
return object : ReadOnlyProperty<W, T> {
@Volatile
var softRef = SoftReference<T>(null)
var softRef: SoftReference<T>? = null

Check warning on line 43 in jacodb-core/src/main/kotlin/org/jacodb/impl/Async.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-core/src/main/kotlin/org/jacodb/impl/Async.kt#L43

Added line #L43 was not covered by tests

override fun getValue(thisRef: W, property: KProperty<*>): T {
var instance = softRef.get()
if (instance == null) {
instance = getter()
softRef = SoftReference(instance)
return instance
}
return instance
return softRef?.get() ?: getter().also { softRef = SoftReference(it) }
}
}
}

fun <W, T> weakLazy(getter: () -> T): ReadOnlyProperty<W, T> {
return object : ReadOnlyProperty<W, T> {
@Volatile
var weakRef = WeakReference<T>(null)
var weakRef: WeakReference<T>? = null

Check warning on line 54 in jacodb-core/src/main/kotlin/org/jacodb/impl/Async.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-core/src/main/kotlin/org/jacodb/impl/Async.kt#L54

Added line #L54 was not covered by tests

override fun getValue(thisRef: W, property: KProperty<*>): T {
var instance = weakRef.get()
if (instance == null) {
instance = getter()
weakRef = WeakReference(instance)
return instance
}
return instance
return weakRef?.get() ?: getter().also { weakRef = WeakReference(it) }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
override fun deleteEntity(id: EntityId) = delegate.deleteEntity(id)
override fun getTypeId(type: String): Int = delegate.getTypeId(type)
override fun getPropertyNames(type: String): Set<String> = delegate.getPropertyNames(type)
override fun getBlobNamesNames(type: String): Set<String> = delegate.getBlobNamesNames(type)
override fun getLinkNamesNames(type: String): Set<String> = delegate.getLinkNamesNames(type)
override fun getBlobNames(type: String): Set<String> = delegate.getBlobNames(type)
override fun getLinkNames(type: String): Set<String> = delegate.getLinkNames(type)

Check warning on line 40 in jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/decorators/AbstractDecorators.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/decorators/AbstractDecorators.kt#L39-L40

Added lines #L39 - L40 were not covered by tests
override fun all(type: String): EntityIterable = delegate.all(type)
override fun <T : Any> find(type: String, propertyName: String, value: T): EntityIterable =
delegate.find(type, propertyName, value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@
ers.getPropNameFromMapName(it)
}

override fun getBlobNamesNames(type: String): Set<String> = getAttributeName(type) {
override fun getBlobNames(type: String): Set<String> = getAttributeName(type) {

Check warning on line 92 in jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/kv/KVErsTransaction.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/kv/KVErsTransaction.kt#L92

Added line #L92 was not covered by tests
ers.getBlobNameFromMapName(it)
}

override fun getLinkNamesNames(type: String): Set<String> = getAttributeName(type) {
override fun getLinkNames(type: String): Set<String> = getAttributeName(type) {

Check warning on line 96 in jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/kv/KVErsTransaction.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/kv/KVErsTransaction.kt#L96

Added line #L96 was not covered by tests
ers.getLinkNameFromMapName(it)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2022 UnitTestBot contributors (utbot.org)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jacodb.impl.storage.ers.ram


fun ByteArray.probablyCached(): ByteArray {
return if (size == 1) {
theCache[this[0].toInt() and 0xff]
} else {
this
}
}

private val theCache = Array(256) { i ->
byteArrayOf(i.toByte())
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,16 @@ internal class CompactPersistentLongSet(private val value: Any? = null) : Collec
if (value == element) {
this
} else {
CompactPersistentLongSet(PackedPersistentLongSet().addAll(listOf(value, element)))
CompactPersistentLongSet(PackedPersistentLongSet().addAll(listOf(value, element.interned)))
}

is PackedPersistentLongSet -> {
val newValue = value.add(element)
val newValue = value.add(element.interned)
if (newValue === value) {
this
} else {
CompactPersistentLongSet(value.add(element))
CompactPersistentLongSet(newValue)
}
}

else -> throw illegalStateException()
}
}
Expand All @@ -85,16 +83,9 @@ internal class CompactPersistentLongSet(private val value: Any? = null) : Collec
if (newValue === value) {
this
} else {
newValue.run {
if (size == 1) {
CompactPersistentLongSet(first().interned)
} else {
CompactPersistentLongSet(newValue)
}
}
CompactPersistentLongSet(if (newValue.size == 1) newValue.first() else newValue)
}
}

else -> throw illegalStateException()
}
}
Expand All @@ -103,13 +94,13 @@ internal class CompactPersistentLongSet(private val value: Any? = null) : Collec
IllegalStateException("CompactPersistentLongSet.value can only be Long or PersistentLongSet")
}

private val Any?.interned: Any?
private val Long.interned: Long
get() =
if (this is Long && this >= 0 && this < LongInterner.boxedLongs.size) LongInterner.boxedLongs[this.toInt()]
if (this in 0 until LongInterner.boxedLongs.size) LongInterner.boxedLongs[this.toInt()]
else this

// TODO: remove this interner if specialized persistent collections would be used
object LongInterner {

val boxedLongs = Array<Any>(200000) { it.toLong() }
val boxedLongs = Array(200000) { it.toLong() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ internal class RAMPersistentDataContainer(
} else {
val blobs = blobs[blobsKey] ?: TransactionalPersistentLongMap()
blobs.withMutableBlobs(blobsKey) {
put(id.instanceId, value)
put(id.instanceId, value.probablyCached())
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@

override fun getPropertyNames(type: String): Set<String> = dataContainerChecked.getPropertyNames(type)

override fun getBlobNamesNames(type: String): Set<String> = dataContainerChecked.getBlobNames(type)
override fun getBlobNames(type: String): Set<String> = dataContainerChecked.getBlobNames(type)

Check warning on line 54 in jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/ram/RAMTransaction.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/ram/RAMTransaction.kt#L54

Added line #L54 was not covered by tests

override fun getLinkNamesNames(type: String): Set<String> = dataContainerChecked.getLinkNames(type)
override fun getLinkNames(type: String): Set<String> = dataContainerChecked.getLinkNames(type)

Check warning on line 56 in jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/ram/RAMTransaction.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/ram/RAMTransaction.kt#L56

Added line #L56 was not covered by tests

override fun all(type: String): EntityIterable = dataContainerChecked.all(this, type)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@
return getTypeIdOrNull(type) ?: return -1
}

override fun getPropertyNames(type: String): Set<String> {
TODO("Not yet implemented")

Check warning on line 79 in jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/sql/SqlErsTransaction.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/sql/SqlErsTransaction.kt#L79

Added line #L79 was not covered by tests
}

override fun getBlobNames(type: String): Set<String> {
TODO("Not yet implemented")

Check warning on line 83 in jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/sql/SqlErsTransaction.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/sql/SqlErsTransaction.kt#L83

Added line #L83 was not covered by tests
}

override fun getLinkNames(type: String): Set<String> {
TODO("Not yet implemented")

Check warning on line 87 in jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/sql/SqlErsTransaction.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-core/src/main/kotlin/org/jacodb/impl/storage/ers/sql/SqlErsTransaction.kt#L87

Added line #L87 was not covered by tests
}

override fun all(type: String): EntityIterable {
val typeId = getTypeIdOrNull(type) ?: return EntityIterable.EMPTY
val entityTable = getEntityTableByTypeIdOrNull(typeId) ?: return EntityIterable.EMPTY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@

package org.jacodb.impl.types.substition

import org.jacodb.api.jvm.*
import org.jacodb.api.jvm.JcClassOrInterface
import org.jacodb.api.jvm.JcGenericsSubstitutionFeature
import org.jacodb.api.jvm.JcSubstitutor
import org.jacodb.api.jvm.JvmType
import org.jacodb.api.jvm.JvmTypeParameterDeclaration
import org.jacodb.impl.cfg.util.OBJECT_CLASS
import org.jacodb.impl.features.classpaths.JcUnknownClass
import org.jacodb.impl.types.signature.JvmClassRefType
import org.jacodb.impl.types.typeParameters

Expand All @@ -40,27 +45,39 @@
outer: JcSubstitutor?
): JcSubstitutor {
val params = clazz.typeParameters
require(params.size == parameters.size) {
"Incorrect parameters specified for class ${clazz.name}: expected ${params.size} found ${parameters.size}"
return if (clazz is JcUnknownClass) {
ignoreProblemsAndSubstitute(params, parameters, outer)

Check warning on line 49 in jacodb-core/src/main/kotlin/org/jacodb/impl/types/substition/JcSubstitutors.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-core/src/main/kotlin/org/jacodb/impl/types/substition/JcSubstitutors.kt#L49

Added line #L49 was not covered by tests
} else {
require(params.size == parameters.size) {
"Incorrect parameters specified for class ${clazz.name}: expected ${params.size} found ${parameters.size}"

Check warning on line 52 in jacodb-core/src/main/kotlin/org/jacodb/impl/types/substition/JcSubstitutors.kt

View check run for this annotation

Codecov / codecov/patch

jacodb-core/src/main/kotlin/org/jacodb/impl/types/substition/JcSubstitutors.kt#L52

Added line #L52 was not covered by tests
}
params.substitute(parameters, outer)
}
return params.substitute(parameters, outer)
}
}

object IgnoreSubstitutionProblems : JcGenericsSubstitutionFeature {

private val jvmObjectType = JvmClassRefType(OBJECT_CLASS, true, emptyList())

override fun substitute(
clazz: JcClassOrInterface,
parameters: List<JvmType>,
outer: JcSubstitutor?
): JcSubstitutor {
val params = clazz.typeParameters
if (params.size == parameters.size) {
return params.substitute(parameters, outer)
}
val substitution = params.associateWith { it.bounds?.first() ?: jvmObjectType }
return (outer ?: JcSubstitutorImpl.empty).newScope(substitution)
return ignoreProblemsAndSubstitute(params, parameters, outer)
}
}

private val jvmObjectType = JvmClassRefType(OBJECT_CLASS, true, emptyList())

private fun ignoreProblemsAndSubstitute(
params: List<JvmTypeParameterDeclaration>,
parameters: List<JvmType>,
outer: JcSubstitutor?
): JcSubstitutor {
if (params.size == parameters.size) {
return params.substitute(parameters, outer)
}
val substitution = params.associateWith { it.bounds?.first() ?: jvmObjectType }
return (outer ?: JcSubstitutorImpl.empty).newScope(substitution)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package org.jacodb.testing.cfg
import org.jacodb.api.jvm.ext.findClass
import org.junit.jupiter.api.Assertions.assertArrayEquals
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test

class IincTest : BaseInstructionsTest() {
Expand Down Expand Up @@ -113,4 +114,7 @@ class IincTest : BaseInstructionsTest() {
@Test
fun `kotlin iinc4`() = runTest(Iinc4::class.java.name)

@Test
fun `kotlin iinc5`() = runTest(Iinc5::class.java.name)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2022 UnitTestBot contributors (utbot.org)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jacodb.testing.storage.ers

import org.jacodb.impl.storage.ers.ram.CompactPersistentLongSet
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class CompactPersistentLongSetTest {

@Test
fun `add remove`() {
var set = CompactPersistentLongSet()
set = set.add(1L)
set = set.add(2L)
set = set.add(3L)
assertEquals(set.size, 3)
assertEquals(setOf(1L, 2L, 3L), set.toSet())
set = set.remove(2L)
assertEquals(set.size, 2)
assertEquals(setOf(1L, 3L), set.toSet())
set = set.remove(3L)
assertEquals(set.size, 1)
assertEquals(setOf(1L), set.toSet())
}
}
19 changes: 19 additions & 0 deletions jacodb-core/src/testFixtures/kotlin/org/jacodb/testing/cfg/Iinc.kt
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,22 @@ class Iinc4 {
}

}

class Iinc5 {

fun box(): String {
val result = intArrayOf(0)
var i = 0

repeat(10) {
try {
result[i++]++
} catch (_: ArrayIndexOutOfBoundsException) {
result[0] += 2
i = 0
}
}

return if (result[0] == 15) "OK" else "Catch failed: ${result[0]}"
}
}
Loading