Skip to content

Commit

Permalink
CASL-598 fix txn on update
Browse files Browse the repository at this point in the history
  • Loading branch information
cyberhead-pl committed Oct 17, 2024
1 parent 67c2e0f commit 1229a1a
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 35 deletions.
14 changes: 12 additions & 2 deletions here-naksha-lib-model/src/commonMain/kotlin/naksha/model/Tuple.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import naksha.model.NakshaError.NakshaErrorCompanion.ILLEGAL_STATE
import naksha.model.NakshaError.NakshaErrorCompanion.MAP_NOT_FOUND
import naksha.model.objects.NakshaFeature
import kotlin.js.JsExport
import kotlin.js.JsStatic
import kotlin.jvm.JvmField

/**
Expand Down Expand Up @@ -111,7 +110,8 @@ data class Tuple(
fun toGuid(): Guid {
var g = guid
if (g == null) {
val meta = this.meta ?: throw NakshaException(ILLEGAL_STATE, "Without metadata it is not possible to generate the GUID from a tuple")
val meta =
this.meta ?: throw NakshaException(ILLEGAL_STATE, "Without metadata it is not possible to generate the GUID from a tuple")
val mapNumber = meta.storeNumber.mapNumber()
val mapId = storage.getMapId(mapNumber) ?: throw NakshaException(MAP_NOT_FOUND, "Map #$mapNumber not found")
val map = storage[mapId]
Expand Down Expand Up @@ -170,4 +170,14 @@ data class Tuple(
fun isComplete(): Boolean = fetchBits.isComplete()

override fun toTuple(): Tuple = this

/**
* @return previous tuple number if available
*/
fun getPrevTupleNumber(): TupleNumber? =
if (meta?.puid != null && meta.prevVersion != null) {
TupleNumber(storeNumber = tupleNumber.storeNumber, version = meta.prevVersion, uid = meta.puid)
} else {
null
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
package naksha.psql.executors

import naksha.base.Int64
import naksha.base.PlatformUtil
import naksha.jbon.JbDictionary
import naksha.model.*
import naksha.model.Naksha.NakshaCompanion.VIRT_COLLECTIONS
import naksha.model.Naksha.NakshaCompanion.VIRT_COLLECTIONS_QUOTED
import naksha.model.Naksha.NakshaCompanion.partitionNumber
import naksha.model.NakshaError.NakshaErrorCompanion.COLLECTION_NOT_FOUND
import naksha.model.NakshaError.NakshaErrorCompanion.ILLEGAL_ARGUMENT
import naksha.model.NakshaError.NakshaErrorCompanion.ILLEGAL_STATE
import naksha.model.NakshaError.NakshaErrorCompanion.MAP_NOT_FOUND
import naksha.model.NakshaError.NakshaErrorCompanion.UNSUPPORTED_OPERATION
import naksha.model.objects.NakshaCollection
Expand Down Expand Up @@ -196,10 +191,11 @@ class PgWriter(
upsertCollection(mapOf(write), write)
)

WriteOp.UPDATE -> cachedTupleNumber(
write,
updateCollection(mapOf(write), write)
)
WriteOp.UPDATE -> {
val updatedTuple = updateCollection(mapOf(write), write)
updatePrevTupleCache(updatedTuple)
cachedTupleNumber(write, updatedTuple)
}

WriteOp.DELETE, WriteOp.PURGE -> DropCollection(session).execute(
mapOf(write),
Expand Down Expand Up @@ -230,23 +226,10 @@ class PgWriter(
InsertFeature(session, writeExecutor).execute(collection, write)
)
} else {
cachedTupleNumber(
write,
UpdateFeature(
session,
previousMetadataProvider,
writeExecutor
).execute(collection, write)
)
updateFeature(collection, previousMetadataProvider, write)
}

WriteOp.UPDATE -> cachedTupleNumber(
write,
UpdateFeature(session, previousMetadataProvider, writeExecutor).execute(
collection,
write
)
)
WriteOp.UPDATE -> updateFeature(collection, previousMetadataProvider, write)

WriteOp.DELETE -> DeleteFeature(session, writeExecutor).execute(
collection,
Expand Down Expand Up @@ -287,6 +270,30 @@ class PgWriter(
return tuple.tupleNumber
}

/**
* Updates previous version of tuple in cache - based on its previous txn.
*/
private fun updatePrevTupleCache(newTuple: Tuple) {
val prevTupleNumber = newTuple.getPrevTupleNumber()
if (prevTupleNumber != null) {
val prevTuple = tupleCache[prevTupleNumber]
if (prevTuple != null) {
val updatedMeta = prevTuple.meta?.copy(nextVersion = newTuple.meta?.version)
tupleCache[prevTupleNumber] = prevTuple.copy(meta = updatedMeta)
}
}
}

private fun updateFeature(collection: PgCollection, previousMetadataProvider: ExistingMetadataProvider, write: WriteExt): TupleNumber {
val updatedTuple = UpdateFeature(
session,
previousMetadataProvider,
writeExecutor
).execute(collection, write)
updatePrevTupleCache(updatedTuple)
return cachedTupleNumber(write, updatedTuple)
}

private fun mapOf(write: WriteExt): PgMap {
val mapId = write.mapId
if (mapId !in storage) throw NakshaException(MAP_NOT_FOUND, "No such map: '$mapId'")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class UpdateFeature(
session.storage,
tupleNumber,
feature,
metadataForNewVersion(previousMetadata, previousMetadata.version, feature, flags),
metadataForNewVersion(previousMetadata, newVersion, feature, flags),
write.attachment,
flags
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import naksha.model.request.Write
import naksha.model.request.WriteRequest
import naksha.psql.assertions.NakshaFeatureFluidAssertions.Companion.assertThatFeature
import naksha.psql.base.PgTestBase
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals

class UpdateFeatureTest : PgTestBase(NakshaCollection("update_feature_test_c")) {

Expand Down Expand Up @@ -46,17 +46,17 @@ class UpdateFeatureTest : PgTestBase(NakshaCollection("update_feature_test_c"))
executeWrite(updateFeaturesReq)

// And: Retrieving feature by id
val retrievedFeature = executeRead(ReadFeatures().apply {
val retrievedTuples = executeRead(ReadFeatures().apply {
collectionIds += collection.id
featureIds += initialFeature.id
}).let { response ->
val responseFeatures = response.features
assertEquals(1, responseFeatures.size)
responseFeatures[0]!!
}
queryHistory = true
}).tuples

val retrievedUpdatedTuple = retrievedTuples.first { it?.tuple?.meta?.action() == Action.UPDATED }!!
val retrievedHstCreatedTuple = retrievedTuples.first { it?.tuple?.meta?.action() == Action.CREATED }!!

// Then
assertThatFeature(retrievedFeature)
assertThatFeature(retrievedUpdatedTuple.feature!!)
.isIdenticalTo(
other = initialFeature,
ignoreProps = true // we ignore properties because we want to examine them later
Expand All @@ -72,5 +72,12 @@ class UpdateFeatureTest : PgTestBase(NakshaCollection("update_feature_test_c"))
.hasProperty("changeCount", 2)
}
}

// also should have proper version in hst
assertNotEquals(retrievedUpdatedTuple.tupleNumber.version, retrievedHstCreatedTuple.tupleNumber.version)
assertEquals(retrievedUpdatedTuple.tuple?.meta?.prevVersion, retrievedHstCreatedTuple.tupleNumber.version)
assertEquals(retrievedUpdatedTuple.tuple?.meta?.version, retrievedUpdatedTuple.tupleNumber.version)
assertEquals(retrievedHstCreatedTuple.tuple?.meta?.version, retrievedHstCreatedTuple.tupleNumber.version)
assertEquals(retrievedHstCreatedTuple.tuple?.meta?.nextVersion, retrievedUpdatedTuple.tupleNumber.version)
}
}

0 comments on commit 1229a1a

Please sign in to comment.