Skip to content

Commit

Permalink
Replace bytearray creation to more optimal and more readable method.
Browse files Browse the repository at this point in the history
  • Loading branch information
jurmous committed Sep 28, 2024
1 parent 370395d commit cf64630
Show file tree
Hide file tree
Showing 25 changed files with 119 additions and 38 deletions.
29 changes: 29 additions & 0 deletions lib/src/commonMain/kotlin/maryk/lib/bytes/combineToByteArray.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package maryk.lib.bytes

fun combineToByteArray(vararg elements: Any): ByteArray {
val totalSize = elements.sumOf { element ->
when (element) {
is ByteArray -> element.size
is Byte -> 1
else -> throw IllegalArgumentException("Unsupported type: ${element::class.simpleName}")
}
}

val result = ByteArray(totalSize)
var offset = 0

elements.forEach { element ->
when (element) {
is ByteArray -> {
element.copyInto(result, offset)
offset += element.size
}
is Byte -> {
result[offset] = element
offset++
}
}
}

return result
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package maryk.lib.bytes

import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertFailsWith
import kotlin.test.expect

class CombineToByteArrayTest {
@Test
fun testCombineByteArrays() {
val result = combineToByteArray(
byteArrayOf(1, 2, 3),
byteArrayOf(4, 5),
byteArrayOf(6)
)
assertContentEquals(byteArrayOf(1, 2, 3, 4, 5, 6), result)
}

@Test
fun testCombineBytes() {
val result = combineToByteArray(1.toByte(), 2.toByte(), 3.toByte())
assertContentEquals(byteArrayOf(1, 2, 3), result)
}

@Test
fun testCombineMixed() {
val result = combineToByteArray(
byteArrayOf(1, 2),
3.toByte(),
byteArrayOf(4, 5),
6.toByte()
)
assertContentEquals(byteArrayOf(1, 2, 3, 4, 5, 6), result)
}

@Test
fun testEmptyInput() {
val result = combineToByteArray()
expect(0) { result.size }
}

@Test
fun testUnsupportedType() {
assertFailsWith<IllegalArgumentException> {
combineToByteArray(byteArrayOf(1, 2), "unsupported")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ private suspend fun <DM : IsRootDataModel> applyChanges(
if (validationExceptions == null) {
validationExceptions = mutableListOf()
}
validationExceptions!!.add(ve)
validationExceptions.add(ve)
}

var isChanged = false
Expand Down Expand Up @@ -734,14 +734,14 @@ private suspend fun <DM : IsRootDataModel> applyChanges(
if (newValue == null) {
if (oldValue != null) {
dependentPuts += Put(oldValue).setTimestamp(version.timestamp.toLong()).addColumn(family, key.bytes, softDeleteIndicator)
indexUpdates.add(IndexDelete(index.referenceStorageByteArray, Bytes(byteArrayOf(*oldValue, *key.bytes))))
indexUpdates.add(IndexDelete(index.referenceStorageByteArray, Bytes(oldValue + key.bytes)))
} // else ignore since did not exist
} else if (oldValue == null || !newValue.contentEquals(oldValue)) {
if (oldValue != null) {
dependentPuts += Put(oldValue).setTimestamp(version.timestamp.toLong()).addColumn(family, key.bytes, softDeleteIndicator)
}
dependentPuts += Put(newValue).setTimestamp(version.timestamp.toLong()).addColumn(family, key.bytes, trueIndicator)
indexUpdates.add(IndexUpdate(index.referenceStorageByteArray, Bytes(byteArrayOf(*newValue, *key.bytes)), oldValue?.let { Bytes(byteArrayOf(*oldValue, *key.bytes)) }))
indexUpdates.add(IndexUpdate(index.referenceStorageByteArray, Bytes(newValue + key.bytes), oldValue?.let { Bytes(oldValue + key.bytes) }))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ internal suspend fun <DM : IsRootDataModel> scanIndex(

add(
Get(cell.qualifierArray, cell.qualifierOffset, cell.qualifierLength).apply {
sortingKeys.add(byteArrayOf(*result.row, *this.row))
sortingKeys.add(result.row + this.row)

addFamily(dataColumnFamily)
readVersions(if (scanRequest is IsChangesRequest<*, *>) scanRequest.maxVersions.toInt() else 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ internal class DBAccessorStoreValuesGetter(
override fun <T : Any, D : IsPropertyDefinition<T>, C : Any> get(propertyReference: IsPropertyReference<T, D, C>): T? {
@Suppress("UNCHECKED_CAST")
return cache.getOrPut(propertyReference) {
dbAccessor.getValue(columnFamilies, readOptions, this.toVersion, byteArrayOf(*key, *propertyReference.toStorageByteArray())) { valueAsBytes, offset, length ->
dbAccessor.getValue(columnFamilies, readOptions, this.toVersion, key + propertyReference.toStorageByteArray()) { valueAsBytes, offset, length ->
(valueAsBytes.convertToValue(propertyReference, offset, length) as T?)?.also {
if (captureVersion) {
val version = valueAsBytes.readVersionBytes()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ internal class HistoricStoreIndexValuesWalker(
bytes.invert(versionIndex)
}
handleIndexReference(historicIndexReference)
} catch (e: Throwable) {
} catch (_: Throwable) {
// skip failing index reference generation
}
} while (getter.gotoNextVersion())
Expand Down Expand Up @@ -134,7 +134,7 @@ private class HistoricStoreIndexValuesGetter(
}
val iterator = iterableReference.iterator
val reference = iterableReference.referenceAsBytes
val keyAndReference = byteArrayOf(*key, *iterableReference.referenceAsBytes)
val keyAndReference = key + iterableReference.referenceAsBytes

// Only seek the first time
if (iterableReference.lastVersion == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ internal class StoreValuesGetter(
override fun <T : Any, D : IsPropertyDefinition<T>, C : Any> get(propertyReference: IsPropertyReference<T, D, C>): T? {
key?.let { currentKey ->
val valueAsBytes = cache.getOrPut(propertyReference) {
val reference = byteArrayOf(*currentKey, *propertyReference.toStorageByteArray())
val reference = currentKey + propertyReference.toStorageByteArray()

db.get(columnFamilies.table, readOptions, reference)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import maryk.datastore.rocksdb.Transaction
import org.rocksdb.ReadOptions

/**
* Set count for [reference] at [version] by applying [countChange] to current count read with [readOptions]
* Set count for [reference] at [versionBytes] by applying [countChange] to current count read with [readOptions]
*/
internal fun <T : Any> createCountUpdater(
transaction: Transaction,
Expand All @@ -23,7 +23,7 @@ internal fun <T : Any> createCountUpdater(
) {
val referenceToCompareTo = reference.toStorageByteArray()

val previousCount = transaction.getValue(columnFamilies, readOptions, null, byteArrayOf(*key.bytes, *referenceToCompareTo)) { b, o, _ ->
val previousCount = transaction.getValue(columnFamilies, readOptions, null, key.bytes + referenceToCompareTo) { b, o, _ ->
var readIndex = o
initIntByVar { b[readIndex++] }
} ?: 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ internal fun <T : Any> deleteByReference(
version: ByteArray,
handlePreviousValue: ((ByteArray, T?) -> Unit)?
): Boolean {
val referenceToCompareTo = byteArrayOf(*key.bytes, *referenceAsBytes)
val referenceToCompareTo = key.bytes + referenceAsBytes
var referenceOfParent: ByteArray? = null
var toShiftListCount = 0u

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import maryk.datastore.rocksdb.HistoricTableColumnFamilies
import maryk.datastore.rocksdb.TableColumnFamilies
import maryk.datastore.rocksdb.Transaction
import maryk.datastore.rocksdb.processors.FALSE_ARRAY
import maryk.lib.bytes.combineToByteArray

/** Delete the [indexReference] and [valueAndKey] for [version] */
internal fun deleteIndexValue(
Expand All @@ -15,11 +16,11 @@ internal fun deleteIndexValue(
version: ByteArray,
hardDelete: Boolean = false
) {
transaction.delete(columnFamilies.index, byteArrayOf(*indexReference, *valueAndKey))
transaction.delete(columnFamilies.index, indexReference + valueAndKey)

// Only delete with non hard deletes since with hard deletes all values are deleted
if (!hardDelete && columnFamilies is HistoricTableColumnFamilies) {
val historicReference = byteArrayOf(*indexReference, *valueAndKey, *version)
val historicReference = combineToByteArray(indexReference, valueAndKey, version)
// Invert so the time is sorted in reverse order with newest on top
historicReference.invert(historicReference.size - version.size)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ internal fun deleteUniqueIndexValue(

// Only add a delete marker when not a hard delete. With hard delete all historic values are deleted
if (!hardDelete && columnFamilies is HistoricTableColumnFamilies) {
val historicReference = byteArrayOf(*reference, *version)
val historicReference = reference + version
// Invert so the time is sorted in reverse order with newest on top
historicReference.invert(reference.size)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal fun deleteValue(
)

if (columnFamilies is HistoricTableColumnFamilies) {
val historicReference = byteArrayOf(*keyAndReference, *version)
val historicReference = keyAndReference + version
// Invert so the time is sorted in reverse order with newest on top
historicReference.invert(historicReference.size - version.size)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ internal fun getKeyByUniqueValue(
val versionBytes = toVersion.toReversedVersionBytes()

dbAccessor.getIterator(readOptions, columnFamilies.historic.unique).use { iterator ->
val toSeek = byteArrayOf(*reference, *versionBytes)
val toSeek = reference + versionBytes
iterator.seek(toSeek)
while (iterator.isValid()) {
val key = iterator.key()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ internal fun <T: Any> DBAccessor.getValue(
}

this.getIterator(readOptions, columnFamilies.historic.table).use { iterator ->
val toSeek = byteArrayOf(*keyAndReference, *versionBytes)
val toSeek = keyAndReference + versionBytes
iterator.seek(toSeek)
while (iterator.isValid()) {
val key = iterator.key()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal fun <R: Any> DBAccessor.iterateValues(
}
this.getIterator(readOptions, columnFamilies.historic.table).use { iterator ->
val toVersionBytes = toVersion.toReversedVersionBytes()
val toSeek = byteArrayOf(*reference, *toVersionBytes)
val toSeek = reference + toVersionBytes
iterator.seek(toSeek)
while (iterator.isValid()) {
val referenceBytes = iterator.key()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import maryk.datastore.rocksdb.HistoricTableColumnFamilies
import maryk.datastore.rocksdb.TableColumnFamilies
import maryk.datastore.rocksdb.Transaction
import maryk.datastore.rocksdb.processors.EMPTY_ARRAY
import maryk.lib.bytes.combineToByteArray

/** Set the [indexReference] and [valueAndKey] for [version] */
internal fun setIndexValue(
Expand All @@ -14,9 +15,9 @@ internal fun setIndexValue(
valueAndKey: ByteArray,
version: ByteArray
) {
transaction.put(columnFamilies.index, byteArrayOf(*indexReference, *valueAndKey), version)
transaction.put(columnFamilies.index, indexReference + valueAndKey, version)
if (columnFamilies is HistoricTableColumnFamilies) {
val historicReference = byteArrayOf(*indexReference, *valueAndKey, *version)
val historicReference = combineToByteArray(indexReference, valueAndKey, version)
// Invert so the time is sorted in reverse order with newest on top
historicReference.invert(historicReference.size - version.size)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package maryk.datastore.rocksdb.processors.helpers

import maryk.core.properties.types.Key
import maryk.datastore.rocksdb.TableColumnFamilies
import maryk.datastore.rocksdb.processors.LAST_VERSION_INDICATOR
import maryk.datastore.rocksdb.Transaction
import maryk.datastore.rocksdb.processors.LAST_VERSION_INDICATOR

/** Set the latest [version] for [key] */
internal fun setLatestVersion(
Expand All @@ -12,6 +12,6 @@ internal fun setLatestVersion(
key: Key<*>,
version: ByteArray
) {
val lastVersionRef = byteArrayOf(*key.bytes, LAST_VERSION_INDICATOR)
val lastVersionRef = key.bytes + LAST_VERSION_INDICATOR
transaction.put(columnFamilies.table, lastVersionRef, version)
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ internal fun setUniqueIndexValue(
version: ByteArray,
key: Key<*>
) {
transaction.put(columnFamilies.unique, uniqueReferenceWithValue, byteArrayOf(*version, *key.bytes))
transaction.put(columnFamilies.unique, uniqueReferenceWithValue, version + key.bytes)

if (columnFamilies is HistoricTableColumnFamilies) {
val historicReference = byteArrayOf(*uniqueReferenceWithValue, *version)
val historicReference = uniqueReferenceWithValue + version
// Invert so the time is sorted in reverse order with newest on top
historicReference.invert(historicReference.size - version.size)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import maryk.core.properties.types.Key
import maryk.datastore.rocksdb.HistoricTableColumnFamilies
import maryk.datastore.rocksdb.TableColumnFamilies
import maryk.datastore.rocksdb.Transaction
import maryk.lib.bytes.combineToByteArray

/** Set [reference] = [value] (ByteArray) at [version] for object at [key] */
internal fun setValue(
Expand All @@ -17,12 +18,12 @@ internal fun setValue(
) {
transaction.put(
columnFamilies.table,
byteArrayOf(*key.bytes, *reference),
byteArrayOf(*version, *value)
key.bytes + reference,
version + value
)

if (columnFamilies is HistoricTableColumnFamilies) {
val historicReference = byteArrayOf(*key.bytes, *reference, *version)
val historicReference = combineToByteArray(key.bytes, reference, version)
// Invert so the time is sorted in reverse order with newest on top
historicReference.invert(historicReference.size - version.size)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import maryk.datastore.rocksdb.HistoricTableColumnFamilies
import maryk.datastore.rocksdb.TableColumnFamilies
import maryk.datastore.rocksdb.Transaction

/** Set [keyAndReference] = [value] (ByteArray) at [version] for object at [key] */
/** Set [keyAndReference] = [value] (ByteArray) at [version] for object at [keyAndReference] */
internal fun setValue(
transaction: Transaction,
columnFamilies: TableColumnFamilies,
Expand All @@ -26,7 +26,7 @@ internal fun setValue(
)

if (columnFamilies is HistoricTableColumnFamilies) {
val historicReference = byteArrayOf(*keyAndReference, *version)
val historicReference = keyAndReference + version
// Invert so the time is sorted in reverse order with newest on top
historicReference.invert(historicReference.size - version.size)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ internal suspend fun <DM : IsRootDataModel> processAdd(

// If a unique index, check if exists, and then write
if ((definition is IsComparableDefinition<*, *>) && definition.unique) {
val uniqueReference = byteArrayOf(*reference, *valueBytes)
val uniqueReference = reference + valueBytes

checksBeforeWrite.add {
val uniqueCount =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ private fun createValueWriter(
columnFamilies,
dataStore.defaultReadOptions,
null,
byteArrayOf(*key.bytes, *reference)
key.bytes + reference
) { b, o, l ->
deleteUniqueIndexValue(transaction, columnFamilies, reference, b, o, l, versionBytes, false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import maryk.datastore.rocksdb.processors.helpers.setLatestVersion
import maryk.datastore.shared.Cache
import maryk.datastore.shared.updates.IsUpdateAction
import maryk.datastore.shared.updates.Update.Deletion
import maryk.lib.bytes.combineToByteArray
import maryk.lib.extensions.compare.matchPart
import maryk.lib.extensions.compare.nextByteInSameLength
import maryk.lib.recyclableByteArray
Expand Down Expand Up @@ -54,7 +55,7 @@ internal suspend fun <DM : IsRootDataModel> processDelete(
for (reference in dataStore.getUniqueIndices(
dbIndex, columnFamilies.unique
)) {
val referenceAndKey = byteArrayOf(*key.bytes, *reference)
val referenceAndKey = key.bytes + reference
val valueLength = transaction.get(
columnFamilies.table,
dataStore.defaultReadOptions,
Expand Down Expand Up @@ -147,13 +148,13 @@ internal suspend fun <DM : IsRootDataModel> processDelete(

transaction.put(
columnFamilies.table,
byteArrayOf(*key.bytes, SOFT_DELETE_INDICATOR),
byteArrayOf(*versionBytes, TRUE)
key.bytes + SOFT_DELETE_INDICATOR,
versionBytes + TRUE
)

if (columnFamilies is HistoricTableColumnFamilies) {
val historicReference =
byteArrayOf(*key.bytes, SOFT_DELETE_INDICATOR, *versionBytes)
combineToByteArray(key.bytes, SOFT_DELETE_INDICATOR, versionBytes)
// Invert so the time is sorted in reverse order with newest on top
historicReference.invert(historicReference.size - versionBytes.size)

Expand Down
Loading

0 comments on commit cf64630

Please sign in to comment.