complete improvements in caches

This commit is contained in:
InsanusMokrassar 2022-06-30 02:44:44 +06:00
parent e55f60c30b
commit 23bcb26a58
11 changed files with 127 additions and 21 deletions

View File

@ -6,7 +6,9 @@
* `Cache`: * `Cache`:
* `KVCache` has been replaced to the package `dev.inmo.micro_utils.repos.cache` * `KVCache` has been replaced to the package `dev.inmo.micro_utils.repos.cache`
* `SimpleKVCache` has been replaced to the package `dev.inmo.micro_utils.repos.cache` * `SimpleKVCache` has been replaced to the package `dev.inmo.micro_utils.repos.cache`
* New `KVCache` - `UnlimitedKVCache` * New `KVCache` subtype - `FullKVCache`
* Add `Full*` variants of standard repos
* Add `cached`/`caching` (for write repos) extensions for all standard types of repos
## 0.11.9 ## 0.11.9

View File

@ -18,8 +18,13 @@ open class ReadCRUDCacheRepo<ObjectType, IdType>(
override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id) override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id)
} }
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
kvCache: KVCache<IdType, ObjectType>,
idGetter: (ObjectType) -> IdType
) = ReadCRUDCacheRepo(this, kvCache, idGetter)
open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>( open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
protected open val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>, protected open val parentRepo: WriteCRUDRepo<ObjectType, IdType, InputValueType>,
protected open val kvCache: KVCache<IdType, ObjectType>, protected open val kvCache: KVCache<IdType, ObjectType>,
protected open val scope: CoroutineScope = CoroutineScope(Dispatchers.Default), protected open val scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
protected open val idGetter: (ObjectType) -> IdType protected open val idGetter: (ObjectType) -> IdType
@ -61,6 +66,12 @@ open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
} }
} }
fun <ObjectType, IdType, InputType> WriteCRUDRepo<ObjectType, IdType, InputType>.caching(
kvCache: KVCache<IdType, ObjectType>,
scope: CoroutineScope,
idGetter: (ObjectType) -> IdType
) = WriteCRUDCacheRepo(this, kvCache, scope, idGetter)
open class CRUDCacheRepo<ObjectType, IdType, InputValueType>( open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>, override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
@ -79,3 +90,9 @@ open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
idGetter idGetter
), ),
CRUDRepo<ObjectType, IdType, InputValueType> CRUDRepo<ObjectType, IdType, InputValueType>
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
kvCache: KVCache<IdType, ObjectType>,
scope: CoroutineScope,
idGetter: (ObjectType) -> IdType
) = CRUDCacheRepo(this, kvCache, scope, idGetter)

View File

@ -16,6 +16,10 @@ open class ReadKeyValueCacheRepo<Key,Value>(
override suspend fun contains(key: Key): Boolean = kvCache.contains(key) || parentRepo.contains(key) override suspend fun contains(key: Key): Boolean = kvCache.contains(key) || parentRepo.contains(key)
} }
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
kvCache: KVCache<Key, Value>
) = ReadKeyValueCacheRepo(this, kvCache)
open class KeyValueCacheRepo<Key,Value>( open class KeyValueCacheRepo<Key,Value>(
parentRepo: KeyValueRepo<Key, Value>, parentRepo: KeyValueRepo<Key, Value>,
kvCache: KVCache<Key, Value>, kvCache: KVCache<Key, Value>,
@ -24,3 +28,8 @@ open class KeyValueCacheRepo<Key,Value>(
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.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 val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
} }
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
kvCache: KVCache<Key, Value>,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) = KeyValueCacheRepo(this, kvCache, scope)

View File

@ -30,6 +30,10 @@ open class ReadKeyValuesCacheRepo<Key,Value>(
override suspend fun contains(k: Key): Boolean = kvCache.contains(k) || parentRepo.contains(k) override suspend fun contains(k: Key): Boolean = kvCache.contains(k) || parentRepo.contains(k)
} }
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
kvCache: KVCache<Key, List<Value>>
) = ReadKeyValuesCacheRepo(this, kvCache)
open class KeyValuesCacheRepo<Key,Value>( open class KeyValuesCacheRepo<Key,Value>(
parentRepo: KeyValuesRepo<Key, Value>, parentRepo: KeyValuesRepo<Key, Value>,
kvCache: KVCache<Key, List<Value>>, kvCache: KVCache<Key, List<Value>>,
@ -39,3 +43,8 @@ open class KeyValuesCacheRepo<Key,Value>(
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.set(it.first, kvCache.get(it.first) ?.minus(it.second) ?: return@onEach) }.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) protected val onDataClearedJob = parentRepo.onDataCleared.onEach { kvCache.unset(it) }.launchIn(scope)
} }
fun <Key, Value> KeyValuesRepo<Key, Value>.cached(
kvCache: KVCache<Key, List<Value>>,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) = KeyValuesCacheRepo(this, kvCache, scope)

View File

@ -3,4 +3,6 @@ package dev.inmo.micro_utils.repos.cache.cache
/** /**
* This interface declares that current type of [KVCache] will contains all the data all the time of its life * This interface declares that current type of [KVCache] will contains all the data all the time of its life
*/ */
interface FullKVCache<K, V> : KVCache<K, V> interface FullKVCache<K, V> : KVCache<K, V> {
companion object
}

View File

@ -2,5 +2,6 @@ package dev.inmo.micro_utils.repos.cache.cache
import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.*
interface KVCache<K, V> : KeyValueRepo<K, V> interface KVCache<K, V> : KeyValueRepo<K, V> {
companion object
}

View File

@ -22,3 +22,7 @@ open class SimpleFullKVCache<K, V>(
} }
} }
} }
inline fun <K, V> FullKVCache(
kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
) = SimpleFullKVCache<K, V>(kvParent)

View File

@ -35,3 +35,8 @@ open class SimpleKVCache<K, V>(
syncMutex.withLock { makeUnset(toUnset) } syncMutex.withLock { makeUnset(toUnset) }
} }
} }
inline fun <K, V> KVCache(
cachedValuesCount: Int,
kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
) = SimpleKVCache<K, V>(cachedValuesCount, kvParent)

View File

@ -7,10 +7,10 @@ import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.*
import dev.inmo.micro_utils.repos.cache.* import dev.inmo.micro_utils.repos.cache.*
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
import dev.inmo.micro_utils.repos.cache.cache.KVCache
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
open class FullReadCRUDCacheRepo<ObjectType, IdType>( open class FullReadCRUDCacheRepo<ObjectType, IdType>(
protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>, protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
protected open val kvCache: FullKVCache<IdType, ObjectType>, protected open val kvCache: FullKVCache<IdType, ObjectType>,
@ -58,11 +58,18 @@ open class FullReadCRUDCacheRepo<ObjectType, IdType>(
{ if (it) parentRepo.getById(id) ?.let { set(id, it) } } { if (it) parentRepo.getById(id) ?.let { set(id, it) } }
) )
override suspend fun getById(id: IdType): ObjectType? { override suspend fun getById(id: IdType): ObjectType? = doOrTakeAndActualize(
TODO("Not yet implemented") { get(id) ?.optional ?: Optional.absent() },
} { getById(id) },
{ it ?.let { set(idGetter(it), it) } }
)
} }
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
kvCache: FullKVCache<IdType, ObjectType>,
idGetter: (ObjectType) -> IdType
) = FullReadCRUDCacheRepo(this, kvCache, idGetter)
open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>( open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>, override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
kvCache: FullKVCache<IdType, ObjectType>, kvCache: FullKVCache<IdType, ObjectType>,
@ -80,3 +87,9 @@ open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
idGetter idGetter
), ),
CRUDRepo<ObjectType, IdType, InputValueType> CRUDRepo<ObjectType, IdType, InputValueType>
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
kvCache: FullKVCache<IdType, ObjectType>,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
idGetter: (ObjectType) -> IdType
) = FullCRUDCacheRepo(this, kvCache, scope, idGetter)

View File

@ -70,6 +70,10 @@ open class FullReadKeyValueCacheRepo<Key,Value>(
) )
} }
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
kvCache: FullKVCache<Key, Value>
) = FullReadKeyValueCacheRepo(this, kvCache)
open class FullWriteKeyValueCacheRepo<Key,Value>( open class FullWriteKeyValueCacheRepo<Key,Value>(
protected open val parentRepo: WriteKeyValueRepo<Key, Value>, protected open val parentRepo: WriteKeyValueRepo<Key, Value>,
protected open val kvCache: FullKVCache<Key, Value>, protected open val kvCache: FullKVCache<Key, Value>,
@ -79,6 +83,11 @@ open class FullWriteKeyValueCacheRepo<Key,Value>(
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope) protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope)
} }
fun <Key, Value> WriteKeyValueRepo<Key, Value>.caching(
kvCache: FullKVCache<Key, Value>,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) = FullWriteKeyValueCacheRepo(this, kvCache, scope)
open class FullKeyValueCacheRepo<Key,Value>( open class FullKeyValueCacheRepo<Key,Value>(
parentRepo: KeyValueRepo<Key, Value>, parentRepo: KeyValueRepo<Key, Value>,
kvCache: FullKVCache<Key, Value>, kvCache: FullKVCache<Key, Value>,
@ -88,3 +97,8 @@ open class FullKeyValueCacheRepo<Key,Value>(
ReadKeyValueRepo<Key, Value> by FullReadKeyValueCacheRepo(parentRepo, kvCache) { ReadKeyValueRepo<Key, Value> by FullReadKeyValueCacheRepo(parentRepo, kvCache) {
override suspend fun unsetWithValues(toUnset: List<Value>) = parentRepo.unsetWithValues(toUnset) override suspend fun unsetWithValues(toUnset: List<Value>) = parentRepo.unsetWithValues(toUnset)
} }
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
kvCache: FullKVCache<Key, Value>,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) = FullKeyValueCacheRepo(this, kvCache, scope)

View File

@ -104,21 +104,51 @@ open class FullReadKeyValuesCacheRepo<Key,Value>(
} }
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
kvCache: FullKVCache<Key, List<Value>>
) = FullReadKeyValuesCacheRepo(this, kvCache)
open class FullWriteKeyValuesCacheRepo<Key,Value>( open class FullWriteKeyValuesCacheRepo<Key,Value>(
protected open val parentRepo: WriteKeyValueRepo<Key, Value>, protected open val parentRepo: WriteKeyValuesRepo<Key, Value>,
protected open val kvCache: FullKVCache<Key, Value>, protected open val kvCache: FullKVCache<Key, List<Value>>,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default) scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) : WriteKeyValueRepo<Key, Value> by parentRepo { ) : WriteKeyValuesRepo<Key, Value> by parentRepo {
protected val onNewJob = parentRepo.onNewValue.onEach { kvCache.set(it.first, it.second) }.launchIn(scope) protected val onNewJob = parentRepo.onNewValue.onEach {
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope) 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)
} }
open class FullKeyValuesCacheRepo<Key,Value>( fun <Key, Value> WriteKeyValuesRepo<Key, Value>.caching(
parentRepo: KeyValueRepo<Key, Value>, kvCache: FullKVCache<Key, List<Value>>,
kvCache: FullKVCache<Key, Value>,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default) scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) : FullWriteKeyValueCacheRepo<Key,Value>(parentRepo, kvCache, scope), ) = FullWriteKeyValuesCacheRepo(this, kvCache, scope)
KeyValueRepo<Key,Value>,
ReadKeyValueRepo<Key, Value> by FullReadKeyValueCacheRepo(parentRepo, kvCache) { open class FullKeyValuesCacheRepo<Key,Value>(
override suspend fun unsetWithValues(toUnset: List<Value>) = parentRepo.unsetWithValues(toUnset) parentRepo: KeyValuesRepo<Key, Value>,
kvCache: FullKVCache<Key, List<Value>>,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) : FullWriteKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, scope),
KeyValuesRepo<Key, Value>,
ReadKeyValuesRepo<Key, Value> by FullReadKeyValuesCacheRepo(parentRepo, kvCache) {
override suspend fun clearWithValue(v: Value) {
doAllWithCurrentPaging {
keys(v, it).also {
remove(it.results.associateWith { listOf(v) })
}
}
}
} }
fun <Key, Value> KeyValuesRepo<Key, Value>.caching(
kvCache: FullKVCache<Key, List<Value>>,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) = FullKeyValuesCacheRepo(this, kvCache, scope)