From b79abdb2f8e34e7f193ab48b4a36dfc1e429a390 Mon Sep 17 00:00:00 2001 From: Leonid Stryuk Date: Thu, 17 Oct 2024 17:13:24 +0200 Subject: [PATCH 1/2] Updated api for removedSync and removedSyncBeforeConstraints. Updated kotlin version --- build.gradle | 2 +- .../jetbrains/exodus/database/DNQListener.kt | 85 ++++++++++++++++--- .../exodus/database/TransientStoreSession.kt | 5 +- .../dnq/database/DnqListenerStoreImpl.kt | 53 ------------ .../PersistentEntityIterableWrapper.kt | 4 +- .../dnq/database/ReadOnlyTransientSession.kt | 22 ++--- .../dnq/database/RemovedTransientEntity.kt | 10 ++- .../dnq/database/TransientEntityIterable.kt | 4 + .../dnq/database/TransientSessionImpl.kt | 18 ++-- .../TransientChangesMultiplexer.kt | 14 ++- .../listener/XdChangesTrackerMultiplexer.kt | 57 ++++++++----- .../kotlinx/dnq/listener/XdEntityListener.kt | 7 +- .../kotlinx/dnq/events/ListenersTest.kt | 85 ++++++++++--------- 13 files changed, 196 insertions(+), 170 deletions(-) delete mode 100644 dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/DnqListenerStoreImpl.kt diff --git a/build.gradle b/build.gradle index efa73e21..f3bfe89d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { ext.kotlin_version = '1.8.10' - ext.exodus_version = '9.9.105' + ext.exodus_version = '9.9.109' ext.dokka_version = '1.7.20' ext.log4j_version = '2.17.1' ext.google_truth_version = '1.4.2' diff --git a/dnq-open-api/src/main/kotlin/jetbrains/exodus/database/DNQListener.kt b/dnq-open-api/src/main/kotlin/jetbrains/exodus/database/DNQListener.kt index f09fec24..09bb5cbc 100644 --- a/dnq-open-api/src/main/kotlin/jetbrains/exodus/database/DNQListener.kt +++ b/dnq-open-api/src/main/kotlin/jetbrains/exodus/database/DNQListener.kt @@ -15,7 +15,7 @@ */ package jetbrains.exodus.database -import jetbrains.exodus.entitystore.orientdb.OEntityId +import jetbrains.exodus.entitystore.EntityId import kotlin.reflect.KProperty interface DNQListener { @@ -26,21 +26,86 @@ interface DNQListener { fun updatedSyncBeforeConstraints(old: T, current: T) fun updatedSync(old: T, current: T) - fun removedSyncBeforeConstraints(removed: T, requestListenerStorage: () -> DnqListenerTransientData) - fun removedSync(removed: OEntityId, requestListenerStorage: () -> DnqListenerTransientData) + /** + * Processes an entity that has been removed before applying constraints. Links and properties of the removed entity are still available and can be stored in removedEntityData for further use. + * + * @param removed The entity that has been removed. + * @param removedEntityData Data related to the removed entity. + */ + fun removedSyncBeforeConstraints(removed: T, removedEntityData: RemovedEntityData) + /** + * Processes an entity that has been removed. If any property or link is required in the removedSync handler, it should be stored in the removedSyncBeforeConstraints with removedEntityData.storeValue(...) + * + * @param removedEntityData Data related to the removed entity. + */ + fun removedSync(removedEntityData: RemovedEntityData) } -interface DnqListenerTransientData { +/** + * Interface representing data related to a removed entity. + * + * @param E The type of the removed entity. + */ +interface RemovedEntityData { + + /** + * The entity that has been removed. Mostly it's {@link com.jetbrains.teamsys.dnq.database.RemovedTransientEntity}. Fields and links should be accessed only within removedSyncBeforeConstraints + */ + val removed: E + /** + * Unique identifier of the removed entity. + */ + val removedId: EntityId + /** + * Retrieves the value associated with the given property name. + * + * @param name The name of the property whose value is to be retrieved. + * @return The value of the specified property, or null if not found. + */ fun getValue(name: String): T? + /** + * Retrieves the value associated with the specified property. + * + * @param T the type of the property. + * @param property the property whose value is to be retrieved. + * @return the value of the specified property, or null if the property does not have a value. + */ + fun getValue(property: KProperty): T? + /** + * Stores a value associated with the given name. + * + * @param name The name with which the specified value is to be associated. + * @param value The value to be stored. + */ fun storeValue(name: String, value: T) - fun getRemoved(): T - fun setRemoved(entity: Any) + /** + * Stores a given value associated with the specified property. + * + * @param T The type of the property and value. + * @param property The property, whose associated value is to be stored. + * @param value The value to be stored. + */ + fun storeValue(property: KProperty, value: T) +} + +open class BasicRemovedEntityData(override val removed: E, override val removedId: EntityId) : RemovedEntityData { + private val data = HashMap() + + override fun getValue(name: String): T? { + @Suppress("UNCHECKED_CAST") + return data[name] as? T + } + + override fun getValue(property: KProperty): T? { + @Suppress("UNCHECKED_CAST") + return data[property.name] as T? + } - fun getValue(property: KProperty): T? { - return getValue(property.name) as T? + override fun storeValue(name: String, value: T) { + data[name] = value as Any } - fun storeValue(property: KProperty, value: T) { - storeValue(property.name, value) + override fun storeValue(property: KProperty, value: T) { + data[property.name] = value as Any } } diff --git a/dnq-open-api/src/main/kotlin/jetbrains/exodus/database/TransientStoreSession.kt b/dnq-open-api/src/main/kotlin/jetbrains/exodus/database/TransientStoreSession.kt index b9a9a0a9..2159def3 100644 --- a/dnq-open-api/src/main/kotlin/jetbrains/exodus/database/TransientStoreSession.kt +++ b/dnq-open-api/src/main/kotlin/jetbrains/exodus/database/TransientStoreSession.kt @@ -16,6 +16,7 @@ package jetbrains.exodus.database import jetbrains.exodus.entitystore.Entity +import jetbrains.exodus.entitystore.EntityId import jetbrains.exodus.entitystore.EntityIterable import jetbrains.exodus.entitystore.StoreTransaction @@ -75,7 +76,9 @@ interface TransientStoreSession : StoreTransaction { fun setUpgradeHook(hook: Runnable?) - fun getListenerTransientData(listener: DNQListener<*>): DnqListenerTransientData + fun createRemovedEntityData(listener: DNQListener<*>, entity: TransientEntity): BasicRemovedEntityData + + fun getRemovedEntityData(listener: DNQListener<*>, entityId: EntityId): BasicRemovedEntityData val originalValuesProvider: TransientEntityOriginalValuesProvider } diff --git a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/DnqListenerStoreImpl.kt b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/DnqListenerStoreImpl.kt deleted file mode 100644 index 2ab1ebe5..00000000 --- a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/DnqListenerStoreImpl.kt +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright 2006 - 2024 JetBrains s.r.o. - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * 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 com.jetbrains.teamsys.dnq.database - -import jetbrains.exodus.database.DnqListenerTransientData -import kotlin.reflect.KProperty - - -class DnqListenerTransientDataImpl : DnqListenerTransientData { - private val data = HashMap() - private var removed: Any? = null - - override fun getValue(name: String): T? { - @Suppress("UNCHECKED_CAST") - return data[name] as? T - } - - override fun storeValue(name: String, value: T) { - data[name] = value as Any - } - - override fun getRemoved(): E { - @Suppress("UNCHECKED_CAST") - return removed as E - } - - override fun setRemoved(entity: Any) { - removed = entity - } - - override fun getValue(property: KProperty): T? { - @Suppress("UNCHECKED_CAST") - return data[property.name] as T? - } - - override fun storeValue(property: KProperty, value: T) { - data[property.name] = value as Any - } -} diff --git a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/PersistentEntityIterableWrapper.kt b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/PersistentEntityIterableWrapper.kt index 4b237609..23d0f1a7 100644 --- a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/PersistentEntityIterableWrapper.kt +++ b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/PersistentEntityIterableWrapper.kt @@ -86,7 +86,7 @@ open class PersistentEntityIterableWrapper( return wrappedIterable.take(number) } - fun findLinks(entities: EntityIterable, linkName: String): EntityIterable { + override fun findLinks(entities: EntityIterable, linkName: String): EntityIterable { //TODO move findLinks to interface return (wrappedIterable as? OEntityIterableBase)?.findLinks(entities, linkName) ?: OEntityIterableBase.EMPTY } @@ -144,4 +144,4 @@ open class PersistentEntityIterableWrapper( } } -} \ No newline at end of file +} diff --git a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/ReadOnlyTransientSession.kt b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/ReadOnlyTransientSession.kt index d640cf31..e3917c92 100644 --- a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/ReadOnlyTransientSession.kt +++ b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/ReadOnlyTransientSession.kt @@ -19,7 +19,6 @@ import jetbrains.exodus.database.* import jetbrains.exodus.entitystore.* import jetbrains.exodus.entitystore.orientdb.OStoreTransaction import jetbrains.exodus.entitystore.orientdb.OVertexEntity -import kotlin.reflect.KProperty class ReadOnlyTransientSession( private val store: TransientEntityStoreImpl, @@ -132,24 +131,13 @@ class ReadOnlyTransientSession( override val entitiesUpdater = ReadonlyTransientEntitiesUpdater() - override fun getListenerTransientData(listener: DNQListener<*>): DnqListenerTransientData { - return object :DnqListenerTransientData { - override fun getValue(name: String) = null - override fun storeValue(name: String, value: T) = Unit - - override fun getRemoved(): T { - throw IllegalStateException("") - } - - override fun getValue(property: KProperty): T? = null - - override fun storeValue(property: KProperty, value: T) { - throw IllegalStateException("") - } + override fun createRemovedEntityData(listener: DNQListener<*>, entity: TransientEntity): BasicRemovedEntityData { + throw IllegalStateException("Transient session is readonly. There should not be any changes") + } - override fun setRemoved(entity: Any) = Unit - } + override fun getRemovedEntityData(listener: DNQListener<*>, entityId: EntityId): BasicRemovedEntityData { + throw IllegalStateException("Transient session is readonly. There should not be any changes") } override val originalValuesProvider = TransientEntityOriginalValuesProviderImpl(this) diff --git a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/RemovedTransientEntity.kt b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/RemovedTransientEntity.kt index 7b528557..e653b8dc 100644 --- a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/RemovedTransientEntity.kt +++ b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/RemovedTransientEntity.kt @@ -21,7 +21,6 @@ import jetbrains.exodus.database.LinkChangeType import jetbrains.exodus.database.TransientEntity import jetbrains.exodus.database.TransientEntityStore import jetbrains.exodus.entitystore.* -import jetbrains.exodus.entitystore.iterate.EntityIterableBase import jetbrains.exodus.entitystore.orientdb.OEntity import jetbrains.exodus.entitystore.orientdb.iterate.OEntityIterableBase import java.io.File @@ -225,9 +224,6 @@ open class RemovedTransientEntity( //region simple unwrapping - - //endregion - override fun getProperty(propertyName: String): Comparable<*>? { return entity.getProperty(propertyName) } @@ -272,6 +268,8 @@ open class RemovedTransientEntity( return OEntityIterableBase.EMPTY } + //endregion + override fun getLinks(linkNames: MutableCollection): EntityIterable { throw IllegalStateException("Entity is removed") } @@ -392,6 +390,7 @@ internal class RemovedLinksEntityIterable( throw IllegalStateException("Must not be called") } + override fun getFirst(): Entity { return entities.first() } @@ -416,5 +415,8 @@ internal class RemovedLinksEntityIterable( throw IllegalStateException("Must not be called") } + override fun findLinks(entities: EntityIterable, linkName: String): EntityIterable { + throw IllegalStateException("Must not be called") + } } diff --git a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/TransientEntityIterable.kt b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/TransientEntityIterable.kt index 7b6ae6f4..3e9738f5 100644 --- a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/TransientEntityIterable.kt +++ b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/TransientEntityIterable.kt @@ -68,6 +68,10 @@ open class TransientEntityIterable(protected val values: Set) : override fun minus(right: EntityIterable): EntityIterable = throw UnsupportedOperationException("Not supported by TransientEntityIterable") + override fun findLinks(entities: EntityIterable, linkName: String) = + throw UnsupportedOperationException("Not supported by TransientEntityIterable") + + override fun concat(right: EntityIterable): EntityIterable { if (right !is TransientEntityIterable) throw UnsupportedOperationException("Not supported by TransientEntityIterable") diff --git a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/TransientSessionImpl.kt b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/TransientSessionImpl.kt index 1026850b..5127c7e4 100644 --- a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/TransientSessionImpl.kt +++ b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/TransientSessionImpl.kt @@ -60,8 +60,8 @@ class TransientSessionImpl( private var loadedIds: EntityIdSet = EntityIdSetFactory.newSet() private val hashCode = (Math.random() * Integer.MAX_VALUE).toInt() private var allowRunnables = true - internal val sessionListenersData = - IdentityHashMap, DnqListenerTransientData<*>>() + internal val removedEntitiesData = + IdentityHashMap, MutableMap>>() val stack = if (TransientEntityStoreImpl.logger.isDebugEnabled) Throwable() else null @@ -540,13 +540,19 @@ class TransientSessionImpl( } } - override fun getListenerTransientData(listener: DNQListener<*>): DnqListenerTransientData { - val result = sessionListenersData.getOrPut(listener) { - DnqListenerTransientDataImpl() + override fun createRemovedEntityData(listener: DNQListener<*>, entity: TransientEntity): BasicRemovedEntityData { + val map = removedEntitiesData.getOrPut(listener) { + hashMapOf() } + val data = BasicRemovedEntityData(entity, entity.id) + map[entity.id] = data + @Suppress("UNCHECKED_CAST") + return data as BasicRemovedEntityData + } + override fun getRemovedEntityData(listener: DNQListener<*>, entityId: EntityId): BasicRemovedEntityData { @Suppress("UNCHECKED_CAST") - return result as DnqListenerTransientData + return removedEntitiesData[listener]?.get(entityId) as BasicRemovedEntityData } private fun addLoadedId(id: EntityId) { diff --git a/dnq-transient-store/src/main/kotlin/jetbrains/exodus/entitystore/TransientChangesMultiplexer.kt b/dnq-transient-store/src/main/kotlin/jetbrains/exodus/entitystore/TransientChangesMultiplexer.kt index 7cec06ce..967088eb 100644 --- a/dnq-transient-store/src/main/kotlin/jetbrains/exodus/entitystore/TransientChangesMultiplexer.kt +++ b/dnq-transient-store/src/main/kotlin/jetbrains/exodus/entitystore/TransientChangesMultiplexer.kt @@ -18,7 +18,6 @@ package jetbrains.exodus.entitystore import jetbrains.exodus.core.dataStructures.hash.HashMap import jetbrains.exodus.database.* import jetbrains.exodus.database.exceptions.DataIntegrityViolationException -import jetbrains.exodus.entitystore.orientdb.OEntityId import mu.KLogging import java.util.* import java.util.concurrent.ConcurrentLinkedQueue @@ -130,6 +129,7 @@ open class TransientChangesMultiplexer : } } + @Suppress("unused") fun close() { logger.debug { "Cleaning EventsMultiplexer listeners" } @@ -204,20 +204,16 @@ open class TransientChangesMultiplexer : Where.SYNC_BEFORE_FLUSH_BEFORE_CONSTRAINTS -> when (c.changeType) { EntityChangeType.ADD -> listeners.visit(true) { it.addedSyncBeforeConstraints(c.transientEntity) } EntityChangeType.UPDATE -> listeners.visit(true) { it.updatedSyncBeforeConstraints(c.snapshotEntity, c.transientEntity) } - EntityChangeType.REMOVE -> listeners.visit(true) { - it.removedSyncBeforeConstraints(c.snapshotEntity) { - session.getListenerTransientData(it) - } + EntityChangeType.REMOVE -> listeners.visit(true) { listener -> + listener.removedSyncBeforeConstraints(c.snapshotEntity, session.createRemovedEntityData(listener, c.snapshotEntity)) } } Where.SYNC_AFTER_FLUSH -> when (c.changeType) { EntityChangeType.ADD -> listeners.visit { it.addedSync(c.transientEntity) } EntityChangeType.UPDATE -> listeners.visit { it.updatedSync(c.snapshotEntity, c.transientEntity) } - EntityChangeType.REMOVE -> listeners.visit { - it.removedSync(c.snapshotEntity.id as OEntityId) { - session.getListenerTransientData(it) - } + EntityChangeType.REMOVE -> listeners.visit { listener -> + listener.removedSync(session.getRemovedEntityData(listener, c.snapshotEntity.id)) } } } diff --git a/dnq/src/main/kotlin/kotlinx/dnq/listener/XdChangesTrackerMultiplexer.kt b/dnq/src/main/kotlin/kotlinx/dnq/listener/XdChangesTrackerMultiplexer.kt index 84bf5553..f2ed0704 100644 --- a/dnq/src/main/kotlin/kotlinx/dnq/listener/XdChangesTrackerMultiplexer.kt +++ b/dnq/src/main/kotlin/kotlinx/dnq/listener/XdChangesTrackerMultiplexer.kt @@ -15,21 +15,27 @@ */ package kotlinx.dnq.listener -import jetbrains.exodus.database.DnqListenerTransientData import jetbrains.exodus.database.IEntityListener import jetbrains.exodus.database.ITransientChangesMultiplexer +import jetbrains.exodus.database.RemovedEntityData import jetbrains.exodus.database.TransientEntityStore import jetbrains.exodus.entitystore.Entity -import jetbrains.exodus.entitystore.orientdb.OEntityId import kotlinx.dnq.XdEntity import kotlinx.dnq.XdEntityType import kotlinx.dnq.toXd +import kotlin.reflect.KProperty -fun ITransientChangesMultiplexer.addListener(entityType: XdEntityType, listener: XdEntityListener) { +fun ITransientChangesMultiplexer.addListener( + entityType: XdEntityType, + listener: XdEntityListener +) { this.addListener(entityType.entityType, listener.asEntityListener()) } -fun ITransientChangesMultiplexer.removeListener(entityType: XdEntityType, listener: XdEntityListener) { +fun ITransientChangesMultiplexer.removeListener( + entityType: XdEntityType, + listener: XdEntityListener +) { this.removeListener(entityType.entityType, listener.asEntityListener()) } @@ -43,7 +49,7 @@ fun ITransientChangesMultiplexer.removeListener(xd: XD, listener fun XdEntityType.addListener(store: TransientEntityStore, listener: XdEntityListener) { val eventsMultiplexer = store.changesMultiplexer - ?: throw IllegalStateException("Cannot access eventsMultiplexer") + ?: throw IllegalStateException("Cannot access eventsMultiplexer") eventsMultiplexer.addListener(this, listener) } @@ -58,35 +64,44 @@ internal class EntityListenerWrapper(val wrapped: XdEntityList override fun addedSyncBeforeConstraints(added: Entity) = wrapped.addedSyncBeforeConstraints(added.toXd()) override fun addedSync(added: Entity) = wrapped.addedSync(added.toXd()) - override fun updatedSyncBeforeConstraints(old: Entity, current: Entity) = wrapped.updatedSyncBeforeConstraints(old.toXd(), current.toXd()) + override fun updatedSyncBeforeConstraints(old: Entity, current: Entity) = + wrapped.updatedSyncBeforeConstraints(old.toXd(), current.toXd()) + override fun updatedSync(old: Entity, current: Entity) = wrapped.updatedSync(old.toXd(), current.toXd()) - override fun removedSyncBeforeConstraints( - removed: Entity, - requestListenerStorage: () -> DnqListenerTransientData - ) { - wrapped.removedSyncBeforeConstraints(removed.toXd()) { XdDnqListenerTransientData(requestListenerStorage) } + override fun removedSyncBeforeConstraints(removed: Entity, removedEntityData: RemovedEntityData) { + wrapped.removedSyncBeforeConstraints(removed.toXd(), XdRemovedEntityData(removedEntityData)) } - override fun removedSync(removed: OEntityId, requestListenerStorage: () -> DnqListenerTransientData) { - wrapped.removedSync(removed) { XdDnqListenerTransientData(requestListenerStorage) } + override fun removedSync(removedEntityData: RemovedEntityData) { + wrapped.removedSync(XdRemovedEntityData(removedEntityData)) } override fun hashCode() = wrapped.hashCode() override fun equals(other: Any?) = other is EntityListenerWrapper<*> && wrapped == other.wrapped } -internal class XdDnqListenerTransientData(private val requestData: () -> DnqListenerTransientData): DnqListenerTransientData { - override fun getValue(name: String) = requestData().getValue(name) +internal class XdRemovedEntityData(private val data: RemovedEntityData) : + RemovedEntityData { + override val removed = data.removed.toXd() + override val removedId = data.removedId + + override fun getValue(name: String): T? { + return data.getValue(name) + } - override fun storeValue(name: String, value: T) = requestData().storeValue(name, value) + override fun getValue(property: KProperty): T? { + return data.getValue(property) + } - override fun getRemoved(): XD { - return requestData().getRemoved().toXd() + override fun storeValue(name: String, value: T) { + return data.storeValue(name, value) } - override fun setRemoved(entity: Any) { - @Suppress("UNCHECKED_CAST") - requestData().setRemoved((entity as XD).entity) + override fun storeValue(property: KProperty, value: T) { + return data.storeValue(property, value) } } + + + diff --git a/dnq/src/main/kotlin/kotlinx/dnq/listener/XdEntityListener.kt b/dnq/src/main/kotlin/kotlinx/dnq/listener/XdEntityListener.kt index dc2772c2..aa47cca8 100644 --- a/dnq/src/main/kotlin/kotlinx/dnq/listener/XdEntityListener.kt +++ b/dnq/src/main/kotlin/kotlinx/dnq/listener/XdEntityListener.kt @@ -16,8 +16,7 @@ package kotlinx.dnq.listener import jetbrains.exodus.database.DNQListener -import jetbrains.exodus.database.DnqListenerTransientData -import jetbrains.exodus.entitystore.orientdb.OEntityId +import jetbrains.exodus.database.RemovedEntityData import kotlinx.dnq.XdEntity interface XdEntityListener : DNQListener { @@ -28,6 +27,6 @@ interface XdEntityListener : DNQListener { override fun updatedSyncBeforeConstraints(old: XD, current: XD) = Unit override fun updatedSync(old: XD, current: XD) = Unit - override fun removedSyncBeforeConstraints(removed: XD, requestListenerStorage: () -> DnqListenerTransientData) = Unit - override fun removedSync(removed: OEntityId, requestListenerStorage: () -> DnqListenerTransientData) = Unit + override fun removedSyncBeforeConstraints(removed: XD, removedEntityData: RemovedEntityData) = Unit + override fun removedSync(removedEntityData: RemovedEntityData) = Unit } diff --git a/dnq/src/test/kotlin/kotlinx/dnq/events/ListenersTest.kt b/dnq/src/test/kotlin/kotlinx/dnq/events/ListenersTest.kt index c0cf1160..5dbbf2e2 100644 --- a/dnq/src/test/kotlin/kotlinx/dnq/events/ListenersTest.kt +++ b/dnq/src/test/kotlin/kotlinx/dnq/events/ListenersTest.kt @@ -16,11 +16,8 @@ package kotlinx.dnq.events import com.google.common.truth.Truth -import com.jetbrains.teamsys.dnq.database.TransientSessionImpl -import com.jetbrains.teamsys.dnq.database.threadSessionOrThrow -import jetbrains.exodus.database.DnqListenerTransientData -import jetbrains.exodus.database.TransientEntity -import jetbrains.exodus.entitystore.orientdb.OEntityId +import jetbrains.exodus.database.RemovedEntityData +import jetbrains.exodus.entitystore.EntityId import kotlinx.dnq.DBTest import kotlinx.dnq.XdModel import kotlinx.dnq.listener.XdEntityListener @@ -28,7 +25,6 @@ import kotlinx.dnq.listener.addListener import kotlinx.dnq.query.asSequence import kotlinx.dnq.query.size import kotlinx.dnq.query.toList -import kotlinx.dnq.toXd import org.junit.Assert import org.junit.Test import java.util.concurrent.atomic.AtomicInteger @@ -60,10 +56,7 @@ class ListenersTest : DBTest() { @Test fun removedSyncBeforeConstraint() { Foo.addListener(store, object : XdEntityListener { - override fun removedSyncBeforeConstraints( - removed: Foo, - requestListenerStorage: () -> DnqListenerTransientData - ) { + override fun removedSyncBeforeConstraints(removed: Foo, removedEntityData: RemovedEntityData) { ref.set(2) } }) @@ -101,10 +94,7 @@ class ListenersTest : DBTest() { @Test fun removedTest() { Foo.addListener(store, object : XdEntityListener { - override fun removedSync( - removed: OEntityId, - requestListenerStorage: () -> DnqListenerTransientData - ) { + override fun removedSync(removedEntityData: RemovedEntityData) { ref.set(239) } }) @@ -124,16 +114,9 @@ class ListenersTest : DBTest() { fun removedTestWithLinksTest() { var failedInWriteInOnRemoveHandler = false Goo.addListener(store, object : XdEntityListener { - override fun removedSync( - removed: OEntityId, - requestListenerStorage: () -> DnqListenerTransientData - ) { + override fun removedSync(removedEntityData: RemovedEntityData) { try { - val goo = store.threadSessionOrThrow.getEntity(removed).toXd() - goo.content.asSequence().forEach { - it.intField = 11 - } - ref.set(goo.content.size()) + removedEntityData.removed.content.clear() } catch (_: Throwable) { failedInWriteInOnRemoveHandler = true } @@ -167,11 +150,7 @@ class ListenersTest : DBTest() { fun removedTransientEntityEqualsToPrototype() { val data = hashMapOf() Foo.addListener(store, object : XdEntityListener { - override fun removedSyncBeforeConstraints( - removed: Foo, - requestListenerStorage: () -> DnqListenerTransientData - ) { - println(removed.hashCode()) + override fun removedSyncBeforeConstraints(removed: Foo, removedEntityData: RemovedEntityData) { data.remove(removed) } }) @@ -183,7 +162,6 @@ class ListenersTest : DBTest() { foo } transactional { - println(foo.hashCode()) foo.delete() } Assert.assertEquals(0, data.size) @@ -219,22 +197,13 @@ class ListenersTest : DBTest() { @Test fun removedTestWithLinksTestWithStore() { Goo.addListener(store, object : XdEntityListener { - override fun removedSyncBeforeConstraints( - removed: Goo, - requestListenerStorage: () -> DnqListenerTransientData - ) { + override fun removedSyncBeforeConstraints(removed: Goo, removedEntityData: RemovedEntityData) { val links = removed.content.toList() - - requestListenerStorage().apply { - storeValue("list", links) - } + removedEntityData.storeValue("list", links) } - override fun removedSync( - removed: OEntityId, - requestListenerStorage: () -> DnqListenerTransientData - ) { - val list: List = requestListenerStorage().getValue("list") ?: throw NoSuchElementException() + override fun removedSync(removedEntityData: RemovedEntityData) { + val list: List = removedEntityData.getValue("list") ?: throw NoSuchElementException() list.forEach { it.intField = 11 } @@ -264,5 +233,37 @@ class ListenersTest : DBTest() { ).isTrue() } + @Test + fun multipleObjectsRemovedInSingleTransaction(){ + val idToValue = hashMapOf() + val idToValueProof = hashMapOf() + Foo.addListener(store, object :XdEntityListener{ + override fun removedSyncBeforeConstraints(removed: Foo, removedEntityData: RemovedEntityData) { + removedEntityData.storeValue(Foo::intField, removed.intField) + } + override fun removedSync(removedEntityData: RemovedEntityData) { + idToValueProof[removedEntityData.removedId] = removedEntityData.getValue(Foo::intField)!! + } + }) + transactional { + (0..100).forEach { + Foo.new { + intField = it + } + } + } + transactional { + Foo.all().asSequence().forEach { foo-> + idToValue[foo.entityId] = foo.intField + } + } + transactional { + val list = Foo.all().toList().toMutableList().apply { + shuffle() + } + list.forEach { it.delete() } + } + Assert.assertEquals(idToValue, idToValueProof) + } } From 45d9ecf5236cf3da2c4aafa06216b127fba97c1b Mon Sep 17 00:00:00 2001 From: Leonid Stryuk Date: Thu, 17 Oct 2024 18:11:07 +0200 Subject: [PATCH 2/2] Fixed compilation --- .../jetbrains/teamsys/dnq/database/RemovedTransientEntity.kt | 3 --- .../jetbrains/teamsys/dnq/database/TransientEntityIterable.kt | 4 ---- 2 files changed, 7 deletions(-) diff --git a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/RemovedTransientEntity.kt b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/RemovedTransientEntity.kt index ab6cf9ae..7e472709 100644 --- a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/RemovedTransientEntity.kt +++ b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/RemovedTransientEntity.kt @@ -420,8 +420,5 @@ internal class RemovedLinksEntityIterable( throw IllegalStateException("Must not be called") } - override fun findLinks(entities: EntityIterable, linkName: String): EntityIterable { - throw IllegalStateException("Must not be called") - } } diff --git a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/TransientEntityIterable.kt b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/TransientEntityIterable.kt index e5d33d10..30c27d28 100644 --- a/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/TransientEntityIterable.kt +++ b/dnq-transient-store/src/main/kotlin/com/jetbrains/teamsys/dnq/database/TransientEntityIterable.kt @@ -72,10 +72,6 @@ open class TransientEntityIterable(protected val values: Set) : override fun minus(right: EntityIterable): EntityIterable = throw UnsupportedOperationException("Not supported by TransientEntityIterable") - override fun findLinks(entities: EntityIterable, linkName: String) = - throw UnsupportedOperationException("Not supported by TransientEntityIterable") - - override fun concat(right: EntityIterable): EntityIterable { if (right !is TransientEntityIterable) throw UnsupportedOperationException("Not supported by TransientEntityIterable")