From b18628f27069740eb84bd7aac415c59675b1b49c Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Thu, 1 Aug 2024 18:12:34 +0530 Subject: [PATCH] fix(level-hash): allow configuring load factor threshold for auto expand --- .../com/itsaky/androidide/levelhash/LevelHash.kt | 7 ++++++- .../com/itsaky/androidide/levelhash/builders.kt | 5 ++++- .../levelhash/internal/AbstractLevelHash.kt | 3 ++- .../levelhash/internal/InMemoryLevelHash.kt | 12 ++++++++++-- .../levelhash/internal/PersistentLevelHash.kt | 13 ++++++++++--- .../levelhash/internal/PersistentLevelHashIO.kt | 1 + 6 files changed, 33 insertions(+), 8 deletions(-) diff --git a/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/LevelHash.kt b/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/LevelHash.kt index 3037ffabe..ef736d78c 100644 --- a/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/LevelHash.kt +++ b/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/LevelHash.kt @@ -39,7 +39,7 @@ import androidx.annotation.FloatRange * as well. This results in decreased access performance and insertion failures. * It is **recommended** to enable [AbstractLevelHashBuilder.autoExpand] which * will automatically expand the level hash when the load factor reaches a certain - * threshold (specifically, when the top level is full). + * threshold ([LevelHash.loadFactor]). * * @param K The key type. * @param V The value type. @@ -164,6 +164,11 @@ interface LevelHash : AutoCloseable { */ const val BUCKET_SIZE_DEFAULT = 4 + /** + * Default load factor threshold for auto expand. + */ + const val AUTO_EXPAND_LOAD_FACTOR_THRESHOLD: Float = 0.92f + /** * Build an in-memory level hash. */ diff --git a/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/builders.kt b/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/builders.kt index 087986708..07061c318 100644 --- a/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/builders.kt +++ b/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/builders.kt @@ -33,6 +33,7 @@ abstract class AbstractLevelHashBuilder { protected var hashFn: LevelHashFn? = null protected var uniqueKeys = false protected var autoExpand = true + protected var loadFactorForAutoExpand = LevelHash.AUTO_EXPAND_LOAD_FACTOR_THRESHOLD protected var seedGenerator: SeedGeneratorFn = ::levelHashDefaultSeeds /** @@ -112,7 +113,8 @@ class InMemoryHashBuilder : levelHashFn = hashFn!!, seeds = seedGenerator(), uniqueKeys = uniqueKeys, - autoExpand = autoExpand + autoExpand = autoExpand, + loadFactorForAutoExpand = loadFactorForAutoExpand, ) } } @@ -170,6 +172,7 @@ class PersistentHashBuilder : bucketSize = bucketSize, uniqueKeys = uniqueKeys, autoExpand = autoExpand, + loadFactorForAutoExpand = loadFactorForAutoExpand, levelHashFn = hashFn!!, seeds = seeds, keyExternalizer = keyExternalizer, diff --git a/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/AbstractLevelHash.kt b/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/AbstractLevelHash.kt index 62dd6873b..3eb374670 100644 --- a/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/AbstractLevelHash.kt +++ b/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/AbstractLevelHash.kt @@ -38,6 +38,7 @@ internal abstract class AbstractLevelHash internal constructo final override val bucketSize: Int, protected val uniqueKeys: Boolean, protected val autoExpand: Boolean, + protected val loadFactorForAutoExpand: Float, protected val levelHashFn: LevelHashFn, protected val seeds: Pair, ) : LevelHash { @@ -123,7 +124,7 @@ internal abstract class AbstractLevelHash internal constructo override fun insert(key: K, value: V): Boolean { - if (loadFactor() >= 0.92 && autoExpand) { + if (loadFactor() >= loadFactorForAutoExpand && autoExpand) { check(expand()) { "Failed to expand the level hash" } diff --git a/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/InMemoryLevelHash.kt b/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/InMemoryLevelHash.kt index 481075d85..872b08a91 100644 --- a/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/InMemoryLevelHash.kt +++ b/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/InMemoryLevelHash.kt @@ -34,10 +34,18 @@ internal class InMemoryLevelHash( bucketSize: Int, uniqueKeys: Boolean, autoExpand: Boolean, + loadFactorForAutoExpand: Float, levelHashFn: LevelHashFn, seeds: Pair, -) : AbstractLevelHash(levelSize, bucketSize, uniqueKeys, autoExpand, - levelHashFn, seeds) { +) : AbstractLevelHash( + levelSize, + bucketSize, + uniqueKeys, + autoExpand, + loadFactorForAutoExpand, + levelHashFn, + seeds +) { private val levels = Array(LEVEL_COUNT) { levelIndex -> allocateLevel(levelSize, levelIndex, bucketSize) diff --git a/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/PersistentLevelHash.kt b/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/PersistentLevelHash.kt index 30c00a45c..f739197a7 100644 --- a/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/PersistentLevelHash.kt +++ b/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/PersistentLevelHash.kt @@ -34,14 +34,21 @@ internal class PersistentLevelHash( bucketSize: Int, uniqueKeys: Boolean, autoExpand: Boolean, + loadFactorForAutoExpand: Float, levelHashFn: LevelHashFn, seeds: Pair, keyExternalizer: DataExternalizer, valueExternalizer: DataExternalizer, indexFile: File, -) : AbstractLevelHash(levelSize = levelSize, bucketSize = bucketSize, - uniqueKeys = uniqueKeys, autoExpand = autoExpand, levelHashFn = levelHashFn, - seeds = seeds) { +) : AbstractLevelHash( + levelSize = levelSize, + bucketSize = bucketSize, + uniqueKeys = uniqueKeys, + autoExpand = autoExpand, + loadFactorForAutoExpand = loadFactorForAutoExpand, + levelHashFn = levelHashFn, + seeds = seeds +) { @VisibleForTesting internal val io = PersistentLevelHashIO(indexFile, levelSize, bucketSize, keyExternalizer, diff --git a/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/PersistentLevelHashIO.kt b/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/PersistentLevelHashIO.kt index d5ba9b4f1..d97a68f57 100644 --- a/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/PersistentLevelHashIO.kt +++ b/utilities/level-hash/src/main/java/com/itsaky/androidide/levelhash/internal/PersistentLevelHashIO.kt @@ -42,6 +42,7 @@ private val logger = LoggerFactory.getLogger(PersistentLevelHashIO::class.java) // improved performance when seeking through the file. // TODO: The above is also applicable for the keymap file when the level hash is // expanded and new regions for the levels are allocated. +// TODO: Allow concurrent access to the level hash. /** * This class is responsible for performing the IO operations for the level hash