mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-10-23 16:20:33 +00:00
huge update with crud caching, common doForAll/getAll and deprecations in old ones doForAll
This commit is contained in:
1
repos/cache/build.gradle
vendored
1
repos/cache/build.gradle
vendored
@@ -11,6 +11,7 @@ kotlin {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api internalProject("micro_utils.repos.common")
|
||||
api internalProject("micro_utils.repos.inmemory")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
24
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/CRUDCacheRepo.kt
vendored
Normal file
24
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/CRUDCacheRepo.kt
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package dev.inmo.micro_utils.repos.cache
|
||||
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||
protected val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
|
||||
protected val kvCache: KVCache<IdType, ObjectType>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
protected val idGetter: (ObjectType) -> IdType
|
||||
) : CRUDRepo<ObjectType, IdType, InputValueType> by parentRepo {
|
||||
protected val onNewJob = parentRepo.newObjectsFlow.onEach { kvCache.set(idGetter(it), it) }.launchIn(scope)
|
||||
protected val onUpdatedJob = parentRepo.updatedObjectsFlow.onEach { kvCache.set(idGetter(it), it) }.launchIn(scope)
|
||||
protected val onRemoveJob = parentRepo.deletedObjectsIdsFlow.onEach { kvCache.unset(it) }.launchIn(scope)
|
||||
|
||||
override suspend fun getById(id: IdType): ObjectType? = kvCache.get(id) ?: (parentRepo.getById(id) ?.also {
|
||||
kvCache.set(id, it)
|
||||
})
|
||||
|
||||
override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id)
|
||||
}
|
41
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KVCache.kt
vendored
Normal file
41
repos/cache/src/commonMain/kotlin/dev/inmo/micro_utils/repos/cache/KVCache.kt
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package dev.inmo.micro_utils.repos.cache
|
||||
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.micro_utils.repos.pagination.getAllWithNextPaging
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
interface KVCache<K, V> : KeyValueRepo<K, V>
|
||||
|
||||
open class SimpleKVCache<K, V>(
|
||||
protected val cachedValuesCount: Int,
|
||||
private val kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
|
||||
) : KVCache<K, V>, KeyValueRepo<K, V> by kvParent {
|
||||
protected open val cacheStack = ArrayList<K>(cachedValuesCount)
|
||||
protected val syncMutex = Mutex()
|
||||
|
||||
protected suspend fun makeUnset(toUnset: List<K>) {
|
||||
cacheStack.removeAll(toUnset)
|
||||
kvParent.unset(toUnset)
|
||||
}
|
||||
|
||||
override suspend fun set(toSet: Map<K, V>) {
|
||||
syncMutex.withLock {
|
||||
if (toSet.size > cachedValuesCount) {
|
||||
cacheStack.clear()
|
||||
|
||||
kvParent.unset(getAllWithNextPaging { kvParent.keys(it) })
|
||||
val keysToInclude = toSet.keys.drop(toSet.size - cachedValuesCount)
|
||||
|
||||
cacheStack.addAll(keysToInclude)
|
||||
kvParent.set(keysToInclude.associateWith { toSet.getValue(it) })
|
||||
} else {
|
||||
makeUnset(cacheStack.take(toSet.size))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun unset(toUnset: List<K>) {
|
||||
syncMutex.withLock { makeUnset(toUnset) }
|
||||
}
|
||||
}
|
@@ -9,34 +9,12 @@ import kotlinx.coroutines.sync.withLock
|
||||
|
||||
open class KeyValueCacheRepo<Key,Value>(
|
||||
protected val parentRepo: KeyValueRepo<Key, Value>,
|
||||
protected val cachedValuesCount: Int,
|
||||
protected val kvCache: KVCache<Key, Value>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
) : KeyValueRepo<Key,Value> by parentRepo {
|
||||
protected open val cache = mutableMapOf<Key,Value>()
|
||||
protected open val cacheStack = ArrayList<Key>(cachedValuesCount)
|
||||
protected val syncMutex = Mutex()
|
||||
protected val onNewJob = parentRepo.onNewValue.onEach { putCacheValue(it.first, it.second) }.launchIn(scope)
|
||||
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { removeCacheValue(it) }.launchIn(scope)
|
||||
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope)
|
||||
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
|
||||
|
||||
protected suspend fun putCacheValue(k: Key, v: Value) = syncMutex.withLock {
|
||||
if (cache.size >= cachedValuesCount) {
|
||||
val key = cacheStack.removeAt(0)
|
||||
cache.remove(key)
|
||||
}
|
||||
cacheStack.add(k)
|
||||
cache[k] = v
|
||||
}
|
||||
|
||||
protected suspend fun removeCacheValue(k: Key) = syncMutex.withLock {
|
||||
val i = cacheStack.indexOf(k)
|
||||
if (i >= 0) {
|
||||
val key = cacheStack.removeAt(i)
|
||||
cache.remove(key)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun get(k: Key): Value? = syncMutex.withLock {
|
||||
cache[k] ?: parentRepo.get(k) ?.also { cache[k] = it }
|
||||
}
|
||||
override suspend fun contains(key: Key): Boolean = cache.containsKey(key) || parentRepo.contains(key)
|
||||
override suspend fun get(k: Key): Value? = kvCache.get(k) ?: parentRepo.get(k) ?.also { kvCache.set(k, it) }
|
||||
override suspend fun contains(key: Key): Boolean = kvCache.contains(key) || parentRepo.contains(key)
|
||||
}
|
||||
|
@@ -13,62 +13,25 @@ import kotlinx.coroutines.sync.withLock
|
||||
|
||||
open class KeyValuesCacheRepo<Key,Value>(
|
||||
protected val parentRepo: KeyValuesRepo<Key, Value>,
|
||||
protected val cachedValuesCount: Int,
|
||||
protected val kvCache: KVCache<Key, List<Value>>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
) : KeyValuesRepo<Key,Value> by parentRepo {
|
||||
protected open val cache = mutableMapOf<Key, List<Value>>()
|
||||
protected open val cacheStack = ArrayList<Key>(cachedValuesCount)
|
||||
protected val syncMutex = Mutex()
|
||||
protected val onNewJob = parentRepo.onNewValue.onEach { putCacheValue(it.first, it.second) }.launchIn(scope)
|
||||
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { removeCacheValue(it.first, it.second) }.launchIn(scope)
|
||||
protected val onDataClearedJob = parentRepo.onDataCleared.onEach { clearCacheValues(it) }.launchIn(scope)
|
||||
|
||||
protected suspend fun putCacheValues(k: Key, v: List<Value>) = syncMutex.withLock {
|
||||
if (cache.size >= cachedValuesCount) {
|
||||
val key = cacheStack.removeAt(0)
|
||||
cache.remove(key)
|
||||
}
|
||||
cacheStack.add(k)
|
||||
cache[k] = v
|
||||
}
|
||||
protected suspend fun putCacheValue(k: Key, v: Value) = syncMutex.withLock {
|
||||
cache[k] ?.let {
|
||||
cache[k] = it + v
|
||||
}
|
||||
} ?: putCacheValues(k, listOf(v))
|
||||
|
||||
protected suspend fun removeCacheValue(k: Key, v: Value) = syncMutex.withLock {
|
||||
cache[k] ?.let {
|
||||
val newList = it - v
|
||||
if (newList.isEmpty()) {
|
||||
cache.remove(k)
|
||||
cacheStack.remove(k)
|
||||
} else {
|
||||
cache[k] = newList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected suspend fun clearCacheValues(k: Key) = syncMutex.withLock {
|
||||
val i = cacheStack.indexOf(k)
|
||||
if (i >= 0) {
|
||||
val key = cacheStack.removeAt(i)
|
||||
cache.remove(key)
|
||||
}
|
||||
}
|
||||
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, kvCache.get(it.first) ?.plus(it.second) ?: listOf(it.second)) }.launchIn(scope)
|
||||
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.set(it.first, kvCache.get(it.first) ?.minus(it.second) ?: return@onEach) }.launchIn(scope)
|
||||
protected val onDataClearedJob = parentRepo.onDataCleared.onEach { kvCache.unset(it) }.launchIn(scope)
|
||||
|
||||
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
|
||||
return cache[k] ?.paginate(
|
||||
return kvCache.get(k) ?.paginate(
|
||||
pagination.let { if (reversed) it.reverse(count(k)) else it }
|
||||
) ?.let {
|
||||
if (reversed) it.copy(results = it.results.reversed()) else it
|
||||
} ?: parentRepo.get(k, pagination, reversed)
|
||||
}
|
||||
override suspend fun getAll(k: Key, reversed: Boolean): List<Value> {
|
||||
return cache[k] ?.let {
|
||||
return kvCache.get(k) ?.let {
|
||||
if (reversed) it.reversed() else it
|
||||
} ?: parentRepo.getAll(k, reversed)
|
||||
}
|
||||
override suspend fun contains(k: Key, v: Value): Boolean = cache[k] ?.contains(v) ?: parentRepo.contains(k, v)
|
||||
override suspend fun contains(k: Key): Boolean = cache.containsKey(k) || parentRepo.contains(k)
|
||||
override suspend fun contains(k: Key, v: Value): Boolean = kvCache.get(k) ?.contains(v) ?: parentRepo.contains(k, v)
|
||||
override suspend fun contains(k: Key): Boolean = kvCache.contains(k) || parentRepo.contains(k)
|
||||
}
|
||||
|
Reference in New Issue
Block a user