[fleet] filter out optional transient scalar attributes from db snapshot

GitOrigin-RevId: c2e20bc0f84337de1c46d8f8ef3dd5c17ceb7e86
This commit is contained in:
Alexander Shparun
2025-09-03 15:41:56 +00:00
committed by intellij-monorepo-bot
parent b57f03d3b7
commit ae9fd63d67
4 changed files with 61 additions and 49 deletions
@@ -8,6 +8,7 @@ import com.jetbrains.rhizomedb.Schema.Companion.NothingMask
import com.jetbrains.rhizomedb.Schema.Companion.RefMask
import com.jetbrains.rhizomedb.Schema.Companion.RequiredMask
import com.jetbrains.rhizomedb.Schema.Companion.UniqueMask
import com.jetbrains.rhizomedb.impl.attributeSerializer
import com.jetbrains.rhizomedb.impl.generateSeed
import fleet.kernel.rebase.deserialize
import fleet.kernel.rebase.encodeDbValue
@@ -120,33 +121,41 @@ fun DbContext<Q>.buildDurableSnapshot(
}
}
}) {
datoms.filter { it.attr != Entity.EntityObject.attr }.forEach { datom ->
val (e, a, v, t) = datom
curDatom = datom
val uid = requireNotNull(getOne(e, uidAttribute)) { "datom is not durable: ${displayDatom(datom)}" }
entities.computeShim(uid) { _: UID, m: MutableMap<DurableSnapshot.Attr, DurableSnapshot.OneOrMany>? ->
val map = (m ?: hashMapOf())
val attr = DurableSnapshot.Attr(attributeIdent(a)!!, a.schema.value)
when (a.schema.cardinality) {
Cardinality.One -> {
map[attr] = DurableSnapshot.OneOrMany.One(DurableSnapshot.VersionedValue(encodeDbValue(uidAttribute, a, v), t))
}
Cardinality.Many -> {
map.computeShim(attr) { _, existingValue ->
existingValue as DurableSnapshot.OneOrMany.Many?
val value = encodeDbValue(uidAttribute, a, v)
if (existingValue != null) {
DurableSnapshot.OneOrMany.Many(existingValue.values + DurableSnapshot.VersionedValue(value, t))
}
else {
DurableSnapshot.OneOrMany.Many(listOf(DurableSnapshot.VersionedValue(value, t)))
datoms
.filter { it.attr != Entity.EntityObject.attr }
.filterNot {
val optional = !it.attr.schema.required
val scalar = !it.attr.schema.isRef
val transient = attributeSerializer(it.attr) == null
scalar && optional && transient
}
.forEach { datom ->
val (e, a, v, t) = datom
curDatom = datom
val uid = requireNotNull(getOne(e, uidAttribute)) { "datom is not durable: ${displayDatom(datom)}" }
entities.computeShim(uid) { _: UID, m: MutableMap<DurableSnapshot.Attr, DurableSnapshot.OneOrMany>? ->
val map = (m ?: hashMapOf())
val attr = DurableSnapshot.Attr(attributeIdent(a)!!, a.schema.value)
when (a.schema.cardinality) {
Cardinality.One -> {
map[attr] = DurableSnapshot.OneOrMany.One(DurableSnapshot.VersionedValue(encodeDbValue(uidAttribute, a, v), t))
}
Cardinality.Many -> {
map.computeShim(attr) { _, existingValue ->
existingValue as DurableSnapshot.OneOrMany.Many?
val value = encodeDbValue(uidAttribute, a, v)
if (existingValue != null) {
DurableSnapshot.OneOrMany.Many(existingValue.values + DurableSnapshot.VersionedValue(value, t))
}
else {
DurableSnapshot.OneOrMany.Many(listOf(DurableSnapshot.VersionedValue(value, t)))
}
}
}
}
map
}
map
}
}
}
return DurableSnapshot(entities = entities.map { DurableSnapshot.DurableEntity(it.key, it.value) })
}
@@ -105,7 +105,7 @@ suspend fun <T> withStorage(
val entitiesCount = snapshot.snapshot.entities.size
Storage.logger.debug { "snapshot for $storageKey built with $entitiesCount entities, took $snapshotBuildDuration" }
val savingDuration = measureTime {
saveSnapshot(snapshot)
coroutineScope { saveSnapshot(snapshot) }
}
Storage.logger.debug { "successfully saved snapshot for $storageKey, written in $savingDuration" }
}
@@ -16,9 +16,11 @@ fun DbContext<Q>.sharedId(eid: EID, uidAttribute: Attribute<UID>): UID? =
else -> null
}
internal fun DbContext<Q>.encodeDbValue(uidAttribute: Attribute<UID>,
a: Attribute<*>,
v: Any): DurableDbValue =
internal fun DbContext<Q>.encodeDbValue(
uidAttribute: Attribute<UID>,
a: Attribute<*>,
v: Any,
): DurableDbValue =
when {
a.schema.isRef -> {
when (val typeIdent = getOne(v as EID, EntityType.Ident.attr as Attribute<String>)) {
@@ -52,7 +54,7 @@ internal fun DbContext<Q>.deserialize(
internal fun DbContext<Q>.serialize1(
eidToUid: DbContext<Q>.(EID) -> UID?,
a: Attribute<*>,
v: Any
v: Any,
): DurableDbValue? =
when {
a.schema.isRef ->
@@ -65,7 +67,7 @@ internal fun DbContext<Q>.serialize1(
private fun DbContext<Q>.serializeScalar(
attribute: Attribute<*>,
value: Any
value: Any,
): DurableDbValue.Scalar =
when (value) {
is JsonElement -> DurableDbValue.Scalar(lazyOf(value))
@@ -21,7 +21,7 @@ fun attr(ident: String, schema: Schema): Attribute<*> =
sealed class Attributes<E : Entity>(
val namespace: String,
val module: String,
initial: Map<String, EntityAttribute<in E, *>>
initial: Map<String, EntityAttribute<in E, *>>,
) {
private val mutableAttrInfos: MutableMap<String, EntityAttribute<in E, *>> = HashMap(initial)
@@ -45,7 +45,7 @@ sealed class Attributes<E : Entity>(
ident: String,
attr: Attribute<*>,
serializer: Lazy<KSerializer<V>>?,
defaultValue: DefaultValue<V>?
defaultValue: DefaultValue<V>?,
) : EntityAttribute<E, V>(ident, attr, serializer, defaultValue) {
operator fun invoke(entity: E): V = entity[this]
operator fun getValue(entity: E, property: KProperty<*>): V = entity[this]
@@ -55,7 +55,7 @@ sealed class Attributes<E : Entity>(
ident: String,
attr: Attribute<*>,
serializer: Lazy<KSerializer<V>>?,
defaultValue: DefaultValue<V>?
defaultValue: DefaultValue<V>?,
) : EntityAttribute<E, V>(ident, attr, serializer, defaultValue) {
operator fun invoke(entity: E): V? = entity[this]
operator fun getValue(entity: E, property: KProperty<*>): V? = entity[this]
@@ -65,7 +65,7 @@ sealed class Attributes<E : Entity>(
ident: String,
attr: Attribute<*>,
serializer: Lazy<KSerializer<V>>?,
defaultValue: DefaultValue<V>?
defaultValue: DefaultValue<V>?,
) : EntityAttribute<E, V>(ident, attr, serializer, defaultValue) {
operator fun invoke(entity: E): Set<V> = entity[this]
operator fun getValue(entity: E, property: KProperty<*>): Set<V> = entity[this]
@@ -82,7 +82,7 @@ sealed class Attributes<E : Entity>(
name: String,
serializer: KSerializer<T>,
valueFlags: Indexing = Indexing.NOT_INDEXED,
defaultValueProvider: DefaultValue<T>? = null
defaultValueProvider: DefaultValue<T>? = null,
): Required<T> =
addAttr(Required(
ident = "$namespace/$name",
@@ -110,7 +110,7 @@ sealed class Attributes<E : Entity>(
name: String,
serializer: KSerializer<T>,
valueFlags: Indexing = Indexing.NOT_INDEXED,
defaultValueProvider: DefaultValue<T>? = null
defaultValueProvider: DefaultValue<T>? = null,
): Optional<T> =
addAttr(Optional(
ident = "$namespace/$name",
@@ -165,7 +165,7 @@ sealed class Attributes<E : Entity>(
protected fun <T : Any> requiredTransient(
name: String,
valueFlags: Indexing = Indexing.NOT_INDEXED,
defaultValueProvider: DefaultValue<T>? = null
defaultValueProvider: DefaultValue<T>? = null,
): Required<T> =
addAttr(Required(
ident = "$namespace/$name",
@@ -192,19 +192,20 @@ sealed class Attributes<E : Entity>(
protected fun <T : Any> optionalTransient(
name: String,
valueFlags: Indexing = Indexing.NOT_INDEXED,
defaultValueProvider: DefaultValue<T>? = null
defaultValueProvider: DefaultValue<T>? = null,
): Optional<T> =
addAttr(Optional(
ident = "$namespace/$name",
attr("$namespace/$name", schema = Schema(
cardinality = Cardinality.One,
isRef = false,
indexed = Indexing.INDEXED == valueFlags,
unique = Indexing.UNIQUE == valueFlags,
cascadeDelete = false,
cascadeDeleteBy = false,
required = false
)),
attr = attr(ident = "$namespace/$name",
schema = Schema(
cardinality = Cardinality.One,
isRef = false,
indexed = Indexing.INDEXED == valueFlags,
unique = Indexing.UNIQUE == valueFlags,
cascadeDelete = false,
cascadeDeleteBy = false,
required = false
)),
serializer = null,
defaultValue = defaultValueProvider
))
@@ -247,7 +248,7 @@ sealed class Attributes<E : Entity>(
* */
protected fun <T : Entity> requiredRef(
name: String,
vararg refFlags: RefFlags
vararg refFlags: RefFlags,
): Required<T> =
addAttr(Required(
ident = "$namespace/$name",
@@ -272,7 +273,7 @@ sealed class Attributes<E : Entity>(
* */
protected fun <T : Entity> optionalRef(
name: String,
vararg refFlags: RefFlags
vararg refFlags: RefFlags,
): Optional<T> =
addAttr(Optional(
ident = "$namespace/$name",
@@ -296,7 +297,7 @@ sealed class Attributes<E : Entity>(
* */
protected fun <T : Entity> manyRef(
name: String,
vararg refFlags: RefFlags
vararg refFlags: RefFlags,
): Many<T> =
addAttr(Many(
ident = "$namespace/$name",
@@ -352,7 +353,7 @@ enum class RefFlags {
CASCADE_DELETE_BY
}
internal fun<E: Entity> merge(attrs: List<Attributes<in E>>): Map<String, EntityAttribute<in E, *>> =
internal fun <E : Entity> merge(attrs: List<Attributes<in E>>): Map<String, EntityAttribute<in E, *>> =
buildMap {
attrs.forEach { m ->
m.entityAttributes.forEach { (k, v) ->