mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-11-14 19:10:29 +00:00
start 0.20.2 and all main repos uses 'SmartRWLocker'
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
package dev.inmo.micro_utils.repos.cache
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||
@@ -10,32 +13,47 @@ import kotlinx.coroutines.flow.*
|
||||
open class ReadCRUDCacheRepo<ObjectType, IdType>(
|
||||
protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
|
||||
protected open val kvCache: KVCache<IdType, ObjectType>,
|
||||
protected val locker: SmartRWLocker = SmartRWLocker(),
|
||||
protected open val idGetter: (ObjectType) -> IdType
|
||||
) : ReadCRUDRepo<ObjectType, IdType> by parentRepo, CommonCacheRepo {
|
||||
override suspend fun getById(id: IdType): ObjectType? = kvCache.get(id) ?: (parentRepo.getById(id) ?.also {
|
||||
kvCache.set(id, it)
|
||||
override suspend fun getById(id: IdType): ObjectType? = locker.withReadAcquire {
|
||||
kvCache.get(id)
|
||||
} ?: (parentRepo.getById(id) ?.also {
|
||||
locker.withWriteLock {
|
||||
kvCache.set(id, it)
|
||||
}
|
||||
})
|
||||
|
||||
override suspend fun getAll(): Map<IdType, ObjectType> {
|
||||
return kvCache.getAll().takeIf { it.size.toLong() == count() } ?: parentRepo.getAll().also {
|
||||
kvCache.actualizeAll(true) { it }
|
||||
return locker.withReadAcquire {
|
||||
kvCache.getAll()
|
||||
}.takeIf { it.size.toLong() == count() } ?: parentRepo.getAll().also {
|
||||
locker.withWriteLock {
|
||||
kvCache.actualizeAll(true) { it }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun contains(id: IdType): Boolean = kvCache.contains(id) || parentRepo.contains(id)
|
||||
override suspend fun contains(id: IdType): Boolean = locker.withReadAcquire {
|
||||
kvCache.contains(id)
|
||||
} || parentRepo.contains(id)
|
||||
|
||||
override suspend fun invalidate() = kvCache.clear()
|
||||
override suspend fun invalidate() = locker.withWriteLock {
|
||||
kvCache.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
|
||||
kvCache: KVCache<IdType, ObjectType>,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
idGetter: (ObjectType) -> IdType
|
||||
) = ReadCRUDCacheRepo(this, kvCache, idGetter)
|
||||
) = ReadCRUDCacheRepo(this, kvCache, locker, idGetter)
|
||||
|
||||
open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||
protected open val parentRepo: WriteCRUDRepo<ObjectType, IdType, InputValueType>,
|
||||
protected open val kvCache: KVCache<IdType, ObjectType>,
|
||||
protected open val kvCache: KeyValueRepo<IdType, ObjectType>,
|
||||
protected open val scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
protected val locker: SmartRWLocker = SmartRWLocker(),
|
||||
protected open val idGetter: (ObjectType) -> IdType
|
||||
) : WriteCRUDRepo<ObjectType, IdType, InputValueType>, CommonCacheRepo {
|
||||
override val newObjectsFlow: Flow<ObjectType> by parentRepo::newObjectsFlow
|
||||
@@ -43,15 +61,15 @@ open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||
override val deletedObjectsIdsFlow: Flow<IdType> by parentRepo::deletedObjectsIdsFlow
|
||||
|
||||
val createdObjectsFlowJob = parentRepo.newObjectsFlow.onEach {
|
||||
kvCache.set(idGetter(it), it)
|
||||
locker.withWriteLock { kvCache.set(idGetter(it), it) }
|
||||
}.launchIn(scope)
|
||||
|
||||
val updatedObjectsFlowJob = parentRepo.updatedObjectsFlow.onEach {
|
||||
kvCache.set(idGetter(it), it)
|
||||
locker.withWriteLock { kvCache.set(idGetter(it), it) }
|
||||
}.launchIn(scope)
|
||||
|
||||
val deletedObjectsFlowJob = parentRepo.deletedObjectsIdsFlow.onEach {
|
||||
kvCache.unset(it)
|
||||
locker.withWriteLock { kvCache.unset(it) }
|
||||
}.launchIn(scope)
|
||||
|
||||
override suspend fun deleteById(ids: List<IdType>) = parentRepo.deleteById(ids)
|
||||
@@ -59,53 +77,65 @@ open class WriteCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||
override suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType> {
|
||||
val updated = parentRepo.update(values)
|
||||
|
||||
kvCache.unset(values.map { it.id })
|
||||
kvCache.set(updated.associateBy { idGetter(it) })
|
||||
locker.withWriteLock {
|
||||
kvCache.unset(values.map { it.id })
|
||||
kvCache.set(updated.associateBy { idGetter(it) })
|
||||
}
|
||||
|
||||
return updated
|
||||
}
|
||||
|
||||
override suspend fun update(id: IdType, value: InputValueType): ObjectType? {
|
||||
return parentRepo.update(id, value) ?.also {
|
||||
kvCache.unset(id)
|
||||
kvCache.set(idGetter(it), it)
|
||||
locker.withWriteLock {
|
||||
kvCache.unset(id)
|
||||
kvCache.set(idGetter(it), it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun create(values: List<InputValueType>): List<ObjectType> {
|
||||
val created = parentRepo.create(values)
|
||||
|
||||
kvCache.set(
|
||||
created.associateBy { idGetter(it) }
|
||||
)
|
||||
locker.withWriteLock {
|
||||
kvCache.set(
|
||||
created.associateBy { idGetter(it) }
|
||||
)
|
||||
}
|
||||
|
||||
return created
|
||||
}
|
||||
|
||||
override suspend fun invalidate() = kvCache.clear()
|
||||
override suspend fun invalidate() = locker.withWriteLock {
|
||||
kvCache.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun <ObjectType, IdType, InputType> WriteCRUDRepo<ObjectType, IdType, InputType>.caching(
|
||||
kvCache: KVCache<IdType, ObjectType>,
|
||||
scope: CoroutineScope,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
idGetter: (ObjectType) -> IdType
|
||||
) = WriteCRUDCacheRepo(this, kvCache, scope, idGetter)
|
||||
) = WriteCRUDCacheRepo(this, kvCache, scope, locker, idGetter)
|
||||
|
||||
|
||||
open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||
override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
|
||||
kvCache: KVCache<IdType, ObjectType>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
idGetter: (ObjectType) -> IdType
|
||||
) : ReadCRUDCacheRepo<ObjectType, IdType>(
|
||||
parentRepo,
|
||||
kvCache,
|
||||
locker,
|
||||
idGetter
|
||||
),
|
||||
WriteCRUDRepo<ObjectType, IdType, InputValueType> by WriteCRUDCacheRepo(
|
||||
parentRepo,
|
||||
kvCache,
|
||||
scope,
|
||||
locker,
|
||||
idGetter
|
||||
),
|
||||
CRUDRepo<ObjectType, IdType, InputValueType>
|
||||
@@ -113,5 +143,6 @@ open class CRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
|
||||
kvCache: KVCache<IdType, ObjectType>,
|
||||
scope: CoroutineScope,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
idGetter: (ObjectType) -> IdType
|
||||
) = CRUDCacheRepo(this, kvCache, scope, idGetter)
|
||||
) = CRUDCacheRepo(this, kvCache, scope, locker, idGetter)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package dev.inmo.micro_utils.repos.cache
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
||||
@@ -10,50 +13,82 @@ import kotlinx.coroutines.flow.*
|
||||
open class ReadKeyValueCacheRepo<Key,Value>(
|
||||
protected open val parentRepo: ReadKeyValueRepo<Key, Value>,
|
||||
protected open val kvCache: KVCache<Key, Value>,
|
||||
protected val locker: SmartRWLocker = SmartRWLocker(),
|
||||
) : ReadKeyValueRepo<Key,Value> by parentRepo, CommonCacheRepo {
|
||||
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)
|
||||
override suspend fun get(k: Key): Value? = locker.withReadAcquire {
|
||||
kvCache.get(k)
|
||||
} ?: parentRepo.get(k) ?.also {
|
||||
locker.withWriteLock {
|
||||
kvCache.set(k, it)
|
||||
}
|
||||
}
|
||||
override suspend fun contains(key: Key): Boolean = locker.withReadAcquire {
|
||||
kvCache.contains(key)
|
||||
} || parentRepo.contains(key)
|
||||
|
||||
override suspend fun values(pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
|
||||
return keys(pagination, reversed).let {
|
||||
it.changeResultsUnchecked(
|
||||
it.results.mapNotNull {
|
||||
get(it)
|
||||
}
|
||||
)
|
||||
return locker.withReadAcquire {
|
||||
keys(pagination, reversed).let {
|
||||
it.changeResultsUnchecked(
|
||||
it.results.mapNotNull {
|
||||
get(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAll(): Map<Key, Value> = kvCache.getAll().takeIf {
|
||||
override suspend fun getAll(): Map<Key, Value> = locker.withReadAcquire {
|
||||
kvCache.getAll()
|
||||
}.takeIf {
|
||||
it.size.toLong() == count()
|
||||
} ?: parentRepo.getAll().also {
|
||||
kvCache.set(it)
|
||||
locker.withWriteLock {
|
||||
kvCache.set(it)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun invalidate() = kvCache.clear()
|
||||
override suspend fun invalidate() = locker.withWriteLock {
|
||||
kvCache.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
|
||||
kvCache: KVCache<Key, Value>
|
||||
) = ReadKeyValueCacheRepo(this, kvCache)
|
||||
kvCache: KVCache<Key, Value>,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
) = ReadKeyValueCacheRepo(this, kvCache, locker)
|
||||
|
||||
open class KeyValueCacheRepo<Key,Value>(
|
||||
override val parentRepo: KeyValueRepo<Key, Value>,
|
||||
kvCache: KVCache<Key, Value>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
) : ReadKeyValueCacheRepo<Key,Value>(parentRepo, kvCache), KeyValueRepo<Key,Value>, WriteKeyValueRepo<Key, Value> by parentRepo, CommonCacheRepo {
|
||||
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)
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
) : ReadKeyValueCacheRepo<Key,Value>(parentRepo, kvCache, locker), KeyValueRepo<Key,Value>, WriteKeyValueRepo<Key, Value> by parentRepo, CommonCacheRepo {
|
||||
protected val onNewJob = parentRepo.onNewValue.onEach {
|
||||
locker.withWriteLock {
|
||||
kvCache.set(it.first, it.second)
|
||||
}
|
||||
}.launchIn(scope)
|
||||
protected val onRemoveJob = parentRepo.onValueRemoved.onEach {
|
||||
locker.withWriteLock {
|
||||
kvCache.unset(it)
|
||||
}
|
||||
}.launchIn(scope)
|
||||
|
||||
override suspend fun invalidate() = kvCache.clear()
|
||||
override suspend fun invalidate() = locker.withWriteLock {
|
||||
kvCache.clear()
|
||||
}
|
||||
|
||||
override suspend fun clear() {
|
||||
parentRepo.clear()
|
||||
kvCache.clear()
|
||||
locker.withWriteLock {
|
||||
kvCache.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
|
||||
kvCache: KVCache<Key, Value>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
) = KeyValueCacheRepo(this, kvCache, scope)
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
) = KeyValueCacheRepo(this, kvCache, scope, locker)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package dev.inmo.micro_utils.repos.cache
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import dev.inmo.micro_utils.pagination.utils.*
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
@@ -10,59 +13,85 @@ import kotlinx.coroutines.flow.*
|
||||
|
||||
open class ReadKeyValuesCacheRepo<Key,Value>(
|
||||
protected open val parentRepo: ReadKeyValuesRepo<Key, Value>,
|
||||
protected open val kvCache: KVCache<Key, List<Value>>
|
||||
protected open val kvCache: KVCache<Key, List<Value>>,
|
||||
protected val locker: SmartRWLocker = SmartRWLocker(),
|
||||
) : ReadKeyValuesRepo<Key,Value> by parentRepo, CommonCacheRepo {
|
||||
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
|
||||
return getAll(k, reversed).paginate(
|
||||
return locker.withReadAcquire {
|
||||
getAll(k, reversed)
|
||||
}.paginate(
|
||||
pagination
|
||||
)
|
||||
}
|
||||
override suspend fun getAll(k: Key, reversed: Boolean): List<Value> {
|
||||
return kvCache.get(k) ?.let {
|
||||
return locker.withReadAcquire {
|
||||
kvCache.get(k)
|
||||
} ?.let {
|
||||
if (reversed) it.reversed() else it
|
||||
} ?: parentRepo.getAll(k, reversed).also {
|
||||
kvCache.set(k, it)
|
||||
locker.withWriteLock {
|
||||
kvCache.set(k, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
override suspend fun contains(k: Key, v: Value): Boolean = kvCache.get(k) ?.contains(v) ?: (parentRepo.contains(k, v).also {
|
||||
override suspend fun contains(k: Key, v: Value): Boolean = locker.withReadAcquire {
|
||||
kvCache.get(k)
|
||||
} ?.contains(v) ?: (parentRepo.contains(k, v).also {
|
||||
if (it) {
|
||||
kvCache.unset(k) // clear as invalid
|
||||
locker.withWriteLock {
|
||||
kvCache.unset(k) // clear as invalid
|
||||
}
|
||||
}
|
||||
})
|
||||
override suspend fun contains(k: Key): Boolean = kvCache.contains(k) || parentRepo.contains(k)
|
||||
override suspend fun contains(k: Key): Boolean = locker.withReadAcquire {
|
||||
kvCache.contains(k)
|
||||
} || parentRepo.contains(k)
|
||||
|
||||
override suspend fun invalidate() = kvCache.clear()
|
||||
override suspend fun invalidate() = locker.withWriteLock {
|
||||
kvCache.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
|
||||
kvCache: KVCache<Key, List<Value>>
|
||||
) = ReadKeyValuesCacheRepo(this, kvCache)
|
||||
kvCache: KVCache<Key, List<Value>>,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
) = ReadKeyValuesCacheRepo(this, kvCache, locker)
|
||||
|
||||
open class KeyValuesCacheRepo<Key,Value>(
|
||||
parentRepo: KeyValuesRepo<Key, Value>,
|
||||
kvCache: KVCache<Key, List<Value>>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
) : ReadKeyValuesCacheRepo<Key,Value>(parentRepo, kvCache), KeyValuesRepo<Key,Value>, WriteKeyValuesRepo<Key,Value> by parentRepo, CommonCacheRepo {
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
) : ReadKeyValuesCacheRepo<Key,Value>(parentRepo, kvCache, locker), KeyValuesRepo<Key,Value>, WriteKeyValuesRepo<Key,Value> by parentRepo, CommonCacheRepo {
|
||||
protected val onNewJob = parentRepo.onNewValue.onEach { (k, v) ->
|
||||
kvCache.set(
|
||||
k,
|
||||
kvCache.get(k) ?.plus(v) ?: return@onEach
|
||||
)
|
||||
locker.withWriteLock {
|
||||
kvCache.set(
|
||||
k,
|
||||
kvCache.get(k) ?.plus(v) ?: return@onEach
|
||||
)
|
||||
}
|
||||
}.launchIn(scope)
|
||||
protected val onRemoveJob = parentRepo.onValueRemoved.onEach { (k, v) ->
|
||||
kvCache.set(
|
||||
k,
|
||||
kvCache.get(k) ?.minus(v) ?: return@onEach
|
||||
)
|
||||
locker.withWriteLock {
|
||||
kvCache.set(
|
||||
k,
|
||||
kvCache.get(k)?.minus(v) ?: return@onEach
|
||||
)
|
||||
}
|
||||
}.launchIn(scope)
|
||||
protected val onDataClearedJob = parentRepo.onDataCleared.onEach {
|
||||
kvCache.unset(it)
|
||||
locker.withWriteLock {
|
||||
kvCache.unset(it)
|
||||
}
|
||||
}.launchIn(scope)
|
||||
|
||||
override suspend fun invalidate() = kvCache.clear()
|
||||
override suspend fun invalidate() = locker.withWriteLock {
|
||||
kvCache.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun <Key, Value> KeyValuesRepo<Key, Value>.cached(
|
||||
kvCache: KVCache<Key, List<Value>>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
) = KeyValuesCacheRepo(this, kvCache, scope)
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
) = KeyValuesCacheRepo(this, kvCache, scope, locker)
|
||||
|
||||
@@ -3,6 +3,7 @@ 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
|
||||
*/
|
||||
@Deprecated("This type of KV repos is obsolete and will be removed soon", ReplaceWith("KeyValueRepo<K, V>", "dev.inmo.micro_utils.repos.KeyValueRepo"))
|
||||
interface FullKVCache<K, V> : KVCache<K, V> {
|
||||
companion object
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ import dev.inmo.micro_utils.repos.MapKeyValueRepo
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
open class SimpleFullKVCache<K, V>(
|
||||
@Deprecated("This type of KV repos is obsolete and will be removed soon", ReplaceWith("MapKeyValueRepo<K, V>()", "dev.inmo.micro_utils.repos.MapKeyValueRepo"))
|
||||
|
||||
class SimpleFullKVCache<K, V>(
|
||||
private val kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
|
||||
) : FullKVCache<K, V>, KeyValueRepo<K, V> by kvParent {
|
||||
protected val syncMutex = Mutex()
|
||||
@@ -29,6 +31,7 @@ open class SimpleFullKVCache<K, V>(
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("This type of KV repos is obsolete and will be removed soon", ReplaceWith("kvParent", "dev.inmo.micro_utils.repos.MapKeyValueRepo"))
|
||||
inline fun <K, V> FullKVCache(
|
||||
kvParent: KeyValueRepo<K, V> = MapKeyValueRepo<K, V>()
|
||||
) = SimpleFullKVCache<K, V>(kvParent)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package dev.inmo.micro_utils.repos.cache.fallback.crud
|
||||
|
||||
import dev.inmo.micro_utils.repos.CRUDRepo
|
||||
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.MapKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.WriteCRUDRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
@@ -10,7 +11,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||
open class AutoRecacheCRUDRepo<RegisteredObject, Id, InputObject>(
|
||||
originalRepo: CRUDRepo<RegisteredObject, Id, InputObject>,
|
||||
scope: CoroutineScope,
|
||||
kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
|
||||
kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
|
||||
recacheDelay: Long = 60.seconds.inWholeMilliseconds,
|
||||
actionWrapper: ActionWrapper = ActionWrapper.Direct,
|
||||
idGetter: (RegisteredObject) -> Id
|
||||
@@ -29,7 +30,7 @@ open class AutoRecacheCRUDRepo<RegisteredObject, Id, InputObject>(
|
||||
originalRepo: CRUDRepo<RegisteredObject, Id, InputObject>,
|
||||
scope: CoroutineScope,
|
||||
originalCallTimeoutMillis: Long,
|
||||
kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
|
||||
kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
|
||||
recacheDelay: Long = 60.seconds.inWholeMilliseconds,
|
||||
idGetter: (RegisteredObject) -> Id
|
||||
) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis), idGetter)
|
||||
|
||||
@@ -3,8 +3,9 @@ package dev.inmo.micro_utils.repos.cache.fallback.crud
|
||||
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.MapKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
|
||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
|
||||
@@ -18,7 +19,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||
open class AutoRecacheReadCRUDRepo<RegisteredObject, Id>(
|
||||
protected open val originalRepo: ReadCRUDRepo<RegisteredObject, Id>,
|
||||
protected val scope: CoroutineScope,
|
||||
protected val kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
|
||||
protected val kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
|
||||
protected val recacheDelay: Long = 60.seconds.inWholeMilliseconds,
|
||||
protected val actionWrapper: ActionWrapper = ActionWrapper.Direct,
|
||||
protected val idGetter: (RegisteredObject) -> Id
|
||||
@@ -35,7 +36,7 @@ open class AutoRecacheReadCRUDRepo<RegisteredObject, Id>(
|
||||
originalRepo: ReadCRUDRepo<RegisteredObject, Id>,
|
||||
scope: CoroutineScope,
|
||||
originalCallTimeoutMillis: Long,
|
||||
kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
|
||||
kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
|
||||
recacheDelay: Long = 60.seconds.inWholeMilliseconds,
|
||||
idGetter: (RegisteredObject) -> Id
|
||||
) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis), idGetter)
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
package dev.inmo.micro_utils.repos.cache.fallback.crud
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.plus
|
||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.repos.UpdatedValuePair
|
||||
import dev.inmo.micro_utils.repos.WriteCRUDRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
|
||||
import dev.inmo.micro_utils.repos.set
|
||||
import dev.inmo.micro_utils.repos.unset
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.merge
|
||||
|
||||
open class AutoRecacheWriteCRUDRepo<RegisteredObject, Id, InputObject>(
|
||||
protected val originalRepo: WriteCRUDRepo<RegisteredObject, Id, InputObject>,
|
||||
protected val scope: CoroutineScope,
|
||||
protected val kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
|
||||
protected val kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
|
||||
protected val idGetter: (RegisteredObject) -> Id
|
||||
) : WriteCRUDRepo<RegisteredObject, Id, InputObject>, FallbackCacheRepo {
|
||||
override val deletedObjectsIdsFlow: Flow<Id>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package dev.inmo.micro_utils.repos.cache.fallback.keyvalue
|
||||
|
||||
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.MapKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.WriteKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
@@ -10,7 +10,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||
open class AutoRecacheKeyValueRepo<Id, RegisteredObject>(
|
||||
override val originalRepo: KeyValueRepo<Id, RegisteredObject>,
|
||||
scope: CoroutineScope,
|
||||
kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
|
||||
kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
|
||||
recacheDelay: Long = 60.seconds.inWholeMilliseconds,
|
||||
actionWrapper: ActionWrapper = ActionWrapper.Direct,
|
||||
idGetter: (RegisteredObject) -> Id
|
||||
@@ -29,7 +29,7 @@ open class AutoRecacheKeyValueRepo<Id, RegisteredObject>(
|
||||
originalRepo: KeyValueRepo<Id, RegisteredObject>,
|
||||
scope: CoroutineScope,
|
||||
originalCallTimeoutMillis: Long,
|
||||
kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
|
||||
kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
|
||||
recacheDelay: Long = 60.seconds.inWholeMilliseconds,
|
||||
idGetter: (RegisteredObject) -> Id
|
||||
) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis), idGetter)
|
||||
|
||||
@@ -3,8 +3,9 @@ package dev.inmo.micro_utils.repos.cache.fallback.keyvalue
|
||||
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.MapKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
|
||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
|
||||
@@ -18,7 +19,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||
open class AutoRecacheReadKeyValueRepo<Id, RegisteredObject>(
|
||||
protected open val originalRepo: ReadKeyValueRepo<Id, RegisteredObject>,
|
||||
protected val scope: CoroutineScope,
|
||||
protected val kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
|
||||
protected val kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
|
||||
protected val recacheDelay: Long = 60.seconds.inWholeMilliseconds,
|
||||
protected val actionWrapper: ActionWrapper = ActionWrapper.Direct,
|
||||
protected val idGetter: (RegisteredObject) -> Id
|
||||
@@ -35,7 +36,7 @@ open class AutoRecacheReadKeyValueRepo<Id, RegisteredObject>(
|
||||
originalRepo: ReadKeyValueRepo<Id, RegisteredObject>,
|
||||
scope: CoroutineScope,
|
||||
originalCallTimeoutMillis: Long,
|
||||
kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache(),
|
||||
kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo(),
|
||||
recacheDelay: Long = 60.seconds.inWholeMilliseconds,
|
||||
idGetter: (RegisteredObject) -> Id
|
||||
) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis), idGetter)
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
package dev.inmo.micro_utils.repos.cache.fallback.keyvalue
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.plus
|
||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.repos.WriteKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
|
||||
import dev.inmo.micro_utils.repos.set
|
||||
import dev.inmo.micro_utils.repos.unset
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
@@ -14,7 +10,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
open class AutoRecacheWriteKeyValueRepo<Id, RegisteredObject>(
|
||||
protected val originalRepo: WriteKeyValueRepo<Id, RegisteredObject>,
|
||||
protected val scope: CoroutineScope,
|
||||
protected val kvCache: FullKVCache<Id, RegisteredObject> = FullKVCache()
|
||||
protected val kvCache: KeyValueRepo<Id, RegisteredObject> = MapKeyValueRepo()
|
||||
) : WriteKeyValueRepo<Id, RegisteredObject>, FallbackCacheRepo {
|
||||
override val onValueRemoved: Flow<Id>
|
||||
get() = (originalRepo.onValueRemoved).distinctUntilChanged()
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package dev.inmo.micro_utils.repos.cache.fallback.keyvalues
|
||||
|
||||
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.KeyValuesRepo
|
||||
import dev.inmo.micro_utils.repos.MapKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.WriteKeyValuesRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
@@ -10,7 +11,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||
open class AutoRecacheKeyValuesRepo<Id, RegisteredObject>(
|
||||
override val originalRepo: KeyValuesRepo<Id, RegisteredObject>,
|
||||
scope: CoroutineScope,
|
||||
kvCache: FullKVCache<Id, List<RegisteredObject>> = FullKVCache(),
|
||||
kvCache: KeyValueRepo<Id, List<RegisteredObject>> = MapKeyValueRepo(),
|
||||
recacheDelay: Long = 60.seconds.inWholeMilliseconds,
|
||||
actionWrapper: ActionWrapper = ActionWrapper.Direct
|
||||
) : AutoRecacheReadKeyValuesRepo<Id, RegisteredObject> (
|
||||
@@ -27,7 +28,7 @@ open class AutoRecacheKeyValuesRepo<Id, RegisteredObject>(
|
||||
originalRepo: KeyValuesRepo<Id, RegisteredObject>,
|
||||
scope: CoroutineScope,
|
||||
originalCallTimeoutMillis: Long,
|
||||
kvCache: FullKVCache<Id, List<RegisteredObject>> = FullKVCache(),
|
||||
kvCache: KeyValueRepo<Id, List<RegisteredObject>> = MapKeyValueRepo(),
|
||||
recacheDelay: Long = 60.seconds.inWholeMilliseconds
|
||||
) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis))
|
||||
|
||||
|
||||
@@ -10,8 +10,9 @@ import dev.inmo.micro_utils.pagination.firstIndex
|
||||
import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
|
||||
import dev.inmo.micro_utils.pagination.utils.optionallyReverse
|
||||
import dev.inmo.micro_utils.pagination.utils.paginate
|
||||
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.MapKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.fallback.ActionWrapper
|
||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
|
||||
@@ -25,7 +26,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||
open class AutoRecacheReadKeyValuesRepo<Id, RegisteredObject>(
|
||||
protected open val originalRepo: ReadKeyValuesRepo<Id, RegisteredObject>,
|
||||
protected val scope: CoroutineScope,
|
||||
protected val kvCache: FullKVCache<Id, List<RegisteredObject>> = FullKVCache(),
|
||||
protected val kvCache: KeyValueRepo<Id, List<RegisteredObject>> = MapKeyValueRepo(),
|
||||
protected val recacheDelay: Long = 60.seconds.inWholeMilliseconds,
|
||||
protected val actionWrapper: ActionWrapper = ActionWrapper.Direct
|
||||
) : ReadKeyValuesRepo<Id, RegisteredObject>, FallbackCacheRepo {
|
||||
@@ -41,7 +42,7 @@ open class AutoRecacheReadKeyValuesRepo<Id, RegisteredObject>(
|
||||
originalRepo: ReadKeyValuesRepo<Id, RegisteredObject>,
|
||||
scope: CoroutineScope,
|
||||
originalCallTimeoutMillis: Long,
|
||||
kvCache: FullKVCache<Id, List<RegisteredObject>> = FullKVCache(),
|
||||
kvCache: KeyValueRepo<Id, List<RegisteredObject>> = MapKeyValueRepo(),
|
||||
recacheDelay: Long = 60.seconds.inWholeMilliseconds
|
||||
) : this(originalRepo, scope, kvCache, recacheDelay, ActionWrapper.Timeouted(originalCallTimeoutMillis))
|
||||
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
package dev.inmo.micro_utils.repos.cache.fallback.keyvalues
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.plus
|
||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.pagination.FirstPagePagination
|
||||
import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
|
||||
import dev.inmo.micro_utils.repos.WriteKeyValuesRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.micro_utils.repos.cache.FallbackCacheRepo
|
||||
import dev.inmo.micro_utils.repos.pagination.maxPagePagination
|
||||
import dev.inmo.micro_utils.repos.set
|
||||
import dev.inmo.micro_utils.repos.unset
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
@@ -17,7 +12,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
open class AutoRecacheWriteKeyValuesRepo<Id, RegisteredObject>(
|
||||
protected val originalRepo: WriteKeyValuesRepo<Id, RegisteredObject>,
|
||||
protected val scope: CoroutineScope,
|
||||
protected val kvCache: FullKVCache<Id, List<RegisteredObject>> = FullKVCache()
|
||||
protected val kvCache: KeyValueRepo<Id, List<RegisteredObject>> = MapKeyValueRepo()
|
||||
) : WriteKeyValuesRepo<Id, RegisteredObject>, FallbackCacheRepo {
|
||||
override val onValueRemoved: Flow<Pair<Id, RegisteredObject>>
|
||||
get() = originalRepo.onValueRemoved
|
||||
|
||||
@@ -1,38 +1,39 @@
|
||||
package dev.inmo.micro_utils.repos.cache.full
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.micro_utils.repos.cache.*
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
open class FullReadCRUDCacheRepo<ObjectType, IdType>(
|
||||
protected open val parentRepo: ReadCRUDRepo<ObjectType, IdType>,
|
||||
protected open val kvCache: FullKVCache<IdType, ObjectType>,
|
||||
protected open val kvCache: KeyValueRepo<IdType, ObjectType>,
|
||||
protected val locker: SmartRWLocker = SmartRWLocker(),
|
||||
protected open val idGetter: (ObjectType) -> IdType
|
||||
) : ReadCRUDRepo<ObjectType, IdType>, FullCacheRepo {
|
||||
protected inline fun <T> doOrTakeAndActualize(
|
||||
action: FullKVCache<IdType, ObjectType>.() -> Optional<T>,
|
||||
protected suspend inline fun <T> doOrTakeAndActualize(
|
||||
action: KeyValueRepo<IdType, ObjectType>.() -> Optional<T>,
|
||||
actionElse: ReadCRUDRepo<ObjectType, IdType>.() -> T,
|
||||
actualize: FullKVCache<IdType, ObjectType>.(T) -> Unit
|
||||
actualize: KeyValueRepo<IdType, ObjectType>.(T) -> Unit
|
||||
): T {
|
||||
kvCache.action().onPresented {
|
||||
return it
|
||||
}.onAbsent {
|
||||
return parentRepo.actionElse().also {
|
||||
kvCache.actualize(it)
|
||||
}
|
||||
locker.withReadAcquire {
|
||||
kvCache.action().onPresented { return it }
|
||||
}
|
||||
return parentRepo.actionElse().also {
|
||||
locker.withWriteLock { kvCache.actualize(it) }
|
||||
}
|
||||
error("The result should be returned above")
|
||||
}
|
||||
|
||||
protected open suspend fun actualizeAll() {
|
||||
kvCache.actualizeAll(parentRepo)
|
||||
locker.withWriteLock { kvCache.actualizeAll(parentRepo) }
|
||||
}
|
||||
|
||||
override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = doOrTakeAndActualize(
|
||||
@@ -77,25 +78,29 @@ open class FullReadCRUDCacheRepo<ObjectType, IdType>(
|
||||
}
|
||||
|
||||
fun <ObjectType, IdType> ReadCRUDRepo<ObjectType, IdType>.cached(
|
||||
kvCache: FullKVCache<IdType, ObjectType>,
|
||||
kvCache: KeyValueRepo<IdType, ObjectType>,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
idGetter: (ObjectType) -> IdType
|
||||
) = FullReadCRUDCacheRepo(this, kvCache, idGetter)
|
||||
) = FullReadCRUDCacheRepo(this, kvCache, locker, idGetter)
|
||||
|
||||
open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||
override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>,
|
||||
kvCache: FullKVCache<IdType, ObjectType>,
|
||||
kvCache: KeyValueRepo<IdType, ObjectType>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
idGetter: (ObjectType) -> IdType
|
||||
) : FullReadCRUDCacheRepo<ObjectType, IdType>(
|
||||
parentRepo,
|
||||
kvCache,
|
||||
locker,
|
||||
idGetter
|
||||
),
|
||||
WriteCRUDRepo<ObjectType, IdType, InputValueType> by WriteCRUDCacheRepo(
|
||||
parentRepo,
|
||||
kvCache,
|
||||
scope,
|
||||
locker,
|
||||
idGetter
|
||||
),
|
||||
CRUDRepo<ObjectType, IdType, InputValueType> {
|
||||
@@ -111,16 +116,18 @@ open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>(
|
||||
}
|
||||
|
||||
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.fullyCached(
|
||||
kvCache: FullKVCache<IdType, ObjectType> = FullKVCache(),
|
||||
kvCache: KeyValueRepo<IdType, ObjectType> = MapKeyValueRepo(),
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
idGetter: (ObjectType) -> IdType
|
||||
) = FullCRUDCacheRepo(this, kvCache, scope, skipStartInvalidate, idGetter)
|
||||
) = FullCRUDCacheRepo(this, kvCache, scope, skipStartInvalidate, locker, idGetter)
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope, idGetter)", "dev.inmo.micro_utils.repos.cache.full.fullyCached"))
|
||||
fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached(
|
||||
kvCache: FullKVCache<IdType, ObjectType>,
|
||||
kvCache: KeyValueRepo<IdType, ObjectType>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
idGetter: (ObjectType) -> IdType
|
||||
) = fullyCached(kvCache, scope, skipStartInvalidate, idGetter)
|
||||
) = fullyCached(kvCache, scope, skipStartInvalidate, locker, idGetter)
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package dev.inmo.micro_utils.repos.cache.full
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
import dev.inmo.micro_utils.pagination.PaginationResult
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||
import dev.inmo.micro_utils.repos.pagination.getAll
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -14,25 +16,26 @@ import kotlinx.coroutines.flow.*
|
||||
|
||||
open class FullReadKeyValueCacheRepo<Key,Value>(
|
||||
protected open val parentRepo: ReadKeyValueRepo<Key, Value>,
|
||||
protected open val kvCache: FullKVCache<Key, Value>,
|
||||
protected open val kvCache: KeyValueRepo<Key, Value>,
|
||||
protected val locker: SmartRWLocker = SmartRWLocker()
|
||||
) : ReadKeyValueRepo<Key, Value>, FullCacheRepo {
|
||||
protected inline fun <T> doOrTakeAndActualize(
|
||||
action: FullKVCache<Key, Value>.() -> Optional<T>,
|
||||
protected suspend inline fun <T> doOrTakeAndActualize(
|
||||
action: KeyValueRepo<Key, Value>.() -> Optional<T>,
|
||||
actionElse: ReadKeyValueRepo<Key, Value>.() -> T,
|
||||
actualize: FullKVCache<Key, Value>.(T) -> Unit
|
||||
actualize: KeyValueRepo<Key, Value>.(T) -> Unit
|
||||
): T {
|
||||
kvCache.action().onPresented {
|
||||
return it
|
||||
}.onAbsent {
|
||||
return parentRepo.actionElse().also {
|
||||
kvCache.actualize(it)
|
||||
}
|
||||
locker.withReadAcquire {
|
||||
kvCache.action().onPresented { return it }
|
||||
}
|
||||
return parentRepo.actionElse().also {
|
||||
locker.withWriteLock { kvCache.actualize(it) }
|
||||
}
|
||||
error("The result should be returned above")
|
||||
}
|
||||
protected open suspend fun actualizeAll() {
|
||||
kvCache.clear()
|
||||
kvCache.set(parentRepo.getAll { keys(it) }.toMap())
|
||||
locker.withWriteLock {
|
||||
kvCache.clear()
|
||||
kvCache.set(parentRepo.getAll { keys(it) }.toMap())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun get(k: Key): Value? = doOrTakeAndActualize(
|
||||
@@ -83,37 +86,51 @@ open class FullReadKeyValueCacheRepo<Key,Value>(
|
||||
}
|
||||
|
||||
fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached(
|
||||
kvCache: FullKVCache<Key, Value>
|
||||
) = FullReadKeyValueCacheRepo(this, kvCache)
|
||||
kvCache: KeyValueRepo<Key, Value>,
|
||||
locker: SmartRWLocker = SmartRWLocker()
|
||||
) = FullReadKeyValueCacheRepo(this, kvCache, locker)
|
||||
|
||||
open class FullWriteKeyValueCacheRepo<Key,Value>(
|
||||
parentRepo: WriteKeyValueRepo<Key, Value>,
|
||||
protected open val kvCache: FullKVCache<Key, Value>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
protected open val kvCache: KeyValueRepo<Key, Value>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
protected val locker: SmartRWLocker = SmartRWLocker()
|
||||
) : WriteKeyValueRepo<Key, Value> by parentRepo, FullCacheRepo {
|
||||
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 onNewJob = parentRepo.onNewValue.onEach {
|
||||
locker.withWriteLock {
|
||||
kvCache.set(it.first, it.second)
|
||||
}
|
||||
}.launchIn(scope)
|
||||
protected val onRemoveJob = parentRepo.onValueRemoved.onEach {
|
||||
locker.withWriteLock {
|
||||
kvCache.unset(it)
|
||||
}
|
||||
}.launchIn(scope)
|
||||
|
||||
override suspend fun invalidate() {
|
||||
kvCache.clear()
|
||||
locker.withWriteLock {
|
||||
kvCache.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <Key, Value> WriteKeyValueRepo<Key, Value>.caching(
|
||||
kvCache: FullKVCache<Key, Value>,
|
||||
kvCache: KeyValueRepo<Key, Value>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
) = FullWriteKeyValueCacheRepo(this, kvCache, scope)
|
||||
|
||||
open class FullKeyValueCacheRepo<Key,Value>(
|
||||
protected open val parentRepo: KeyValueRepo<Key, Value>,
|
||||
kvCache: FullKVCache<Key, Value>,
|
||||
kvCache: KeyValueRepo<Key, Value>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker()
|
||||
) : FullWriteKeyValueCacheRepo<Key,Value>(parentRepo, kvCache, scope),
|
||||
KeyValueRepo<Key,Value>,
|
||||
ReadKeyValueRepo<Key, Value> by FullReadKeyValueCacheRepo(
|
||||
parentRepo,
|
||||
kvCache
|
||||
kvCache,
|
||||
locker
|
||||
) {
|
||||
init {
|
||||
if (!skipStartInvalidate) {
|
||||
@@ -124,7 +141,9 @@ open class FullKeyValueCacheRepo<Key,Value>(
|
||||
override suspend fun unsetWithValues(toUnset: List<Value>) = parentRepo.unsetWithValues(toUnset)
|
||||
|
||||
override suspend fun invalidate() {
|
||||
kvCache.actualizeAll(parentRepo)
|
||||
locker.withWriteLock {
|
||||
kvCache.actualizeAll(parentRepo)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun clear() {
|
||||
@@ -134,12 +153,16 @@ open class FullKeyValueCacheRepo<Key,Value>(
|
||||
}
|
||||
|
||||
fun <Key, Value> KeyValueRepo<Key, Value>.fullyCached(
|
||||
kvCache: FullKVCache<Key, Value> = FullKVCache(),
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
) = FullKeyValueCacheRepo(this, kvCache, scope)
|
||||
kvCache: KeyValueRepo<Key, Value> = MapKeyValueRepo(),
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker()
|
||||
) = FullKeyValueCacheRepo(this, kvCache, scope, skipStartInvalidate, locker)
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope)", "dev.inmo.micro_utils.repos.cache.full.fullyCached"))
|
||||
fun <Key, Value> KeyValueRepo<Key, Value>.cached(
|
||||
kvCache: FullKVCache<Key, Value>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
) = fullyCached(kvCache, scope)
|
||||
kvCache: KeyValueRepo<Key, Value>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker()
|
||||
) = fullyCached(kvCache, scope, skipStartInvalidate, locker)
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package dev.inmo.micro_utils.repos.cache.full
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
import dev.inmo.micro_utils.coroutines.withWriteLock
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import dev.inmo.micro_utils.pagination.utils.*
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -13,29 +15,32 @@ import kotlinx.coroutines.flow.*
|
||||
|
||||
open class FullReadKeyValuesCacheRepo<Key,Value>(
|
||||
protected open val parentRepo: ReadKeyValuesRepo<Key, Value>,
|
||||
protected open val kvCache: FullKVCache<Key, List<Value>>,
|
||||
protected open val kvCache: KeyValueRepo<Key, List<Value>>,
|
||||
protected val locker: SmartRWLocker = SmartRWLocker(),
|
||||
) : ReadKeyValuesRepo<Key, Value>, FullCacheRepo {
|
||||
protected inline fun <T> doOrTakeAndActualize(
|
||||
action: FullKVCache<Key, List<Value>>.() -> Optional<T>,
|
||||
protected suspend inline fun <T> doOrTakeAndActualize(
|
||||
action: KeyValueRepo<Key, List<Value>>.() -> Optional<T>,
|
||||
actionElse: ReadKeyValuesRepo<Key, Value>.() -> T,
|
||||
actualize: FullKVCache<Key, List<Value>>.(T) -> Unit
|
||||
actualize: KeyValueRepo<Key, List<Value>>.(T) -> Unit
|
||||
): T {
|
||||
kvCache.action().onPresented {
|
||||
return it
|
||||
}.onAbsent {
|
||||
return parentRepo.actionElse().also {
|
||||
kvCache.actualize(it)
|
||||
}
|
||||
locker.withReadAcquire {
|
||||
kvCache.action().onPresented { return it }
|
||||
}
|
||||
return parentRepo.actionElse().also {
|
||||
locker.withWriteLock { kvCache.actualize(it) }
|
||||
}
|
||||
error("The result should be returned above")
|
||||
}
|
||||
|
||||
protected open suspend fun actualizeKey(k: Key) {
|
||||
kvCache.set(k, parentRepo.getAll(k))
|
||||
locker.withWriteLock {
|
||||
kvCache.set(k, parentRepo.getAll(k))
|
||||
}
|
||||
}
|
||||
|
||||
protected open suspend fun actualizeAll() {
|
||||
kvCache.actualizeAll(parentRepo)
|
||||
locker.withWriteLock {
|
||||
kvCache.actualizeAll(parentRepo)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
|
||||
@@ -109,45 +114,55 @@ open class FullReadKeyValuesCacheRepo<Key,Value>(
|
||||
}
|
||||
|
||||
fun <Key, Value> ReadKeyValuesRepo<Key, Value>.cached(
|
||||
kvCache: FullKVCache<Key, List<Value>>
|
||||
) = FullReadKeyValuesCacheRepo(this, kvCache)
|
||||
kvCache: KeyValueRepo<Key, List<Value>>,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
) = FullReadKeyValuesCacheRepo(this, kvCache, locker)
|
||||
|
||||
open class FullWriteKeyValuesCacheRepo<Key,Value>(
|
||||
parentRepo: WriteKeyValuesRepo<Key, Value>,
|
||||
protected open val kvCache: FullKVCache<Key, List<Value>>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
protected open val kvCache: KeyValueRepo<Key, List<Value>>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
protected val locker: SmartRWLocker = SmartRWLocker(),
|
||||
) : WriteKeyValuesRepo<Key, Value> by parentRepo, FullCacheRepo {
|
||||
protected val onNewJob = parentRepo.onNewValue.onEach {
|
||||
kvCache.set(
|
||||
it.first,
|
||||
kvCache.get(it.first) ?.plus(it.second) ?: listOf(it.second)
|
||||
)
|
||||
locker.withWriteLock {
|
||||
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
|
||||
)
|
||||
locker.withWriteLock {
|
||||
kvCache.set(
|
||||
it.first,
|
||||
kvCache.get(it.first)?.minus(it.second) ?: return@onEach
|
||||
)
|
||||
}
|
||||
}.launchIn(scope)
|
||||
|
||||
override suspend fun invalidate() {
|
||||
kvCache.clear()
|
||||
locker.withWriteLock {
|
||||
kvCache.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <Key, Value> WriteKeyValuesRepo<Key, Value>.caching(
|
||||
kvCache: FullKVCache<Key, List<Value>>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
) = FullWriteKeyValuesCacheRepo(this, kvCache, scope)
|
||||
kvCache: KeyValueRepo<Key, List<Value>>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
) = FullWriteKeyValuesCacheRepo(this, kvCache, scope, locker)
|
||||
|
||||
open class FullKeyValuesCacheRepo<Key,Value>(
|
||||
protected open val parentRepo: KeyValuesRepo<Key, Value>,
|
||||
kvCache: FullKVCache<Key, List<Value>>,
|
||||
kvCache: KeyValueRepo<Key, List<Value>>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false
|
||||
) : FullWriteKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, scope),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
) : FullWriteKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, scope, locker),
|
||||
KeyValuesRepo<Key, Value>,
|
||||
ReadKeyValuesRepo<Key, Value> by FullReadKeyValuesCacheRepo(parentRepo, kvCache) {
|
||||
ReadKeyValuesRepo<Key, Value> by FullReadKeyValuesCacheRepo(parentRepo, kvCache, locker) {
|
||||
init {
|
||||
if (!skipStartInvalidate) {
|
||||
scope.launchSafelyWithoutExceptions { invalidate() }
|
||||
@@ -163,7 +178,9 @@ open class FullKeyValuesCacheRepo<Key,Value>(
|
||||
}
|
||||
|
||||
override suspend fun invalidate() {
|
||||
kvCache.actualizeAll(parentRepo)
|
||||
locker.withWriteLock {
|
||||
kvCache.actualizeAll(parentRepo)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun removeWithValue(v: Value) {
|
||||
@@ -172,12 +189,16 @@ open class FullKeyValuesCacheRepo<Key,Value>(
|
||||
}
|
||||
|
||||
fun <Key, Value> KeyValuesRepo<Key, Value>.fullyCached(
|
||||
kvCache: FullKVCache<Key, List<Value>> = FullKVCache(),
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
) = FullKeyValuesCacheRepo(this, kvCache, scope)
|
||||
kvCache: KeyValueRepo<Key, List<Value>> = MapKeyValueRepo(),
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
) = FullKeyValuesCacheRepo(this, kvCache, scope, skipStartInvalidate, locker)
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope)", "dev.inmo.micro_utils.repos.cache.full.fullyCached"))
|
||||
fun <Key, Value> KeyValuesRepo<Key, Value>.caching(
|
||||
kvCache: FullKVCache<Key, List<Value>>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
) = FullKeyValuesCacheRepo(this, kvCache, scope)
|
||||
kvCache: KeyValueRepo<Key, List<Value>>,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
skipStartInvalidate: Boolean = false,
|
||||
locker: SmartRWLocker = SmartRWLocker(),
|
||||
) = FullKeyValuesCacheRepo(this, kvCache, scope, skipStartInvalidate, locker)
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
package dev.inmo.micro_utils.repos.cache.util
|
||||
|
||||
import dev.inmo.micro_utils.pagination.FirstPagePagination
|
||||
import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
|
||||
import dev.inmo.micro_utils.pagination.utils.getAllByWithNextPaging
|
||||
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
||||
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.KVCache
|
||||
import dev.inmo.micro_utils.repos.pagination.getAll
|
||||
import dev.inmo.micro_utils.repos.set
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
|
||||
suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
|
||||
suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAll(
|
||||
clear: Boolean = true,
|
||||
getAll: () -> Map<K, V>
|
||||
) {
|
||||
@@ -23,7 +15,7 @@ suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
|
||||
)
|
||||
}
|
||||
|
||||
suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
|
||||
suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAll(
|
||||
repo: ReadKeyValueRepo<K, V>,
|
||||
clear: Boolean = true,
|
||||
) {
|
||||
@@ -32,7 +24,7 @@ suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
|
||||
}
|
||||
}
|
||||
|
||||
suspend inline fun <K, V> KVCache<K, List<V>>.actualizeAll(
|
||||
suspend inline fun <K, V> KeyValueRepo<K, List<V>>.actualizeAll(
|
||||
repo: ReadKeyValuesRepo<K, V>,
|
||||
clear: Boolean = true,
|
||||
) {
|
||||
@@ -41,7 +33,7 @@ suspend inline fun <K, V> KVCache<K, List<V>>.actualizeAll(
|
||||
}
|
||||
}
|
||||
|
||||
suspend inline fun <K, V> KVCache<K, V>.actualizeAll(
|
||||
suspend inline fun <K, V> KeyValueRepo<K, V>.actualizeAll(
|
||||
repo: ReadCRUDRepo<V, K>,
|
||||
clear: Boolean = true,
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user