add repos.cache

This commit is contained in:
InsanusMokrassar 2021-03-24 13:01:15 +06:00
parent 8e62dd460c
commit 08c371c142
6 changed files with 137 additions and 0 deletions

View File

@ -2,6 +2,8 @@
## 0.4.31 ## 0.4.31
* Add subproject `repos.cache`
## 0.4.30 ## 0.4.30
* `Versions`: * `Versions`:

17
repos/cache/build.gradle vendored Normal file
View File

@ -0,0 +1,17 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
id "com.android.library"
}
apply from: "$mppProjectWithSerializationPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api internalProject("micro_utils.repos.common")
}
}
}
}

View File

@ -0,0 +1,42 @@
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.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
open class KeyValueCacheRepo<Key,Value>(
protected val parentRepo: KeyValueRepo<Key, Value>,
protected val cachedValuesCount: Int,
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 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)
}

View File

@ -0,0 +1,74 @@
package dev.inmo.micro_utils.repos.cache
import dev.inmo.micro_utils.pagination.Pagination
import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.pagination.utils.paginate
import dev.inmo.micro_utils.pagination.utils.reverse
import dev.inmo.micro_utils.repos.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
open class KeyValuesCacheRepo<Key,Value>(
protected val parentRepo: KeyValuesRepo<Key, Value>,
protected val cachedValuesCount: Int,
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)
}
}
override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> {
return cache[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 {
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)
}

View File

@ -0,0 +1 @@
<manifest package="dev.inmo.micro_utils.repos.cache"/>

View File

@ -11,6 +11,7 @@ String[] includes = [
":pagination:ktor:server", ":pagination:ktor:server",
":mime_types", ":mime_types",
":repos:common", ":repos:common",
":repos:cache",
":repos:exposed", ":repos:exposed",
":repos:inmemory", ":repos:inmemory",
":repos:ktor:client", ":repos:ktor:client",