mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2026-04-08 02:22:42 +00:00
Compare commits
3 Commits
5447bf9691
...
04f82a03bf
| Author | SHA1 | Date | |
|---|---|---|---|
| 04f82a03bf | |||
| aac545074b | |||
| 87a3a925ee |
@@ -4,6 +4,10 @@
|
||||
|
||||
* `Coroutines`:
|
||||
* Add extensions `SmartRWLocker.alsoWithUnlockingOnSuccessAsync` and `SmartRWLocker.alsoWithUnlockingOnSuccess`
|
||||
* Fix of `SmartRWLocker.lockWrite` issue when it could lock write mutex without unlocking
|
||||
* Add tool `SmartKeyRWLocker`
|
||||
* `SmartSemaphore` got new property `maxPermits`
|
||||
* New extension `SmartSemaphore.waitReleaseAll()`
|
||||
* `Transactions`:
|
||||
* Add `TransactionsDSL`
|
||||
|
||||
|
||||
@@ -7,6 +7,22 @@ import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
/**
|
||||
* Combining [globalRWLocker] and internal map of [SmartRWLocker] associated by [T] to provide next logic:
|
||||
*
|
||||
* * Locker by key, for reading: waiting for [globalRWLocker] unlock write by acquiring read permit in it and then
|
||||
* taking or creating locker for key [T] and lock its reading too
|
||||
* * Locker by key, for writing: waiting for [globalRWLocker] unlock write by acquiring read permit in it and then
|
||||
* taking or creating locker for key [T] and lock its writing
|
||||
* * [globalRWLocker], for reading: using [SmartRWLocker.acquireRead], will be suspended until its
|
||||
* [SmartRWLocker.lockWrite] will not be unlocked
|
||||
* * [globalRWLocker], for writing: using [SmartRWLocker.lockWrite], will be paused by other reading and writing
|
||||
* operations and will pause other operations until the end of operation (calling of [unlockWrite])
|
||||
*
|
||||
* You may see, that lockers by key still will use global locker permits - it is required to prevent [globalRWLocker]
|
||||
* write locking during all other operations are not done. In fact, all the keys works like a simple [SmartRWLocker] as
|
||||
* well, as [globalRWLocker], but they are linked with [globalRWLocker] [SmartRWLocker.acquireRead] permissions
|
||||
*/
|
||||
class SmartKeyRWLocker<T>(
|
||||
globalLockerReadPermits: Int = Int.MAX_VALUE,
|
||||
globalLockerWriteIsLocked: Boolean = false,
|
||||
@@ -152,6 +168,27 @@ suspend inline fun <T, R> SmartKeyRWLocker<T>.withReadAcquire(key: T, action: ()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
suspend inline fun <T, R> SmartKeyRWLocker<T>.withReadAcquires(keys: Iterable<T>, action: () -> R): R {
|
||||
contract {
|
||||
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
|
||||
val acquired = mutableSetOf<T>()
|
||||
try {
|
||||
keys.forEach {
|
||||
acquireRead(it)
|
||||
acquired.add(it)
|
||||
}
|
||||
return action()
|
||||
} finally {
|
||||
acquired.forEach {
|
||||
releaseRead(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
suspend inline fun <T, R> SmartKeyRWLocker<T>.withReadAcquires(vararg keys: T, action: () -> R): R = withReadAcquires(keys.asIterable(), action)
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
suspend inline fun <T, R> SmartKeyRWLocker<T>.withWriteLock(key: T, action: () -> R): R {
|
||||
contract {
|
||||
@@ -164,4 +201,24 @@ suspend inline fun <T, R> SmartKeyRWLocker<T>.withWriteLock(key: T, action: () -
|
||||
} finally {
|
||||
unlockWrite(key)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
suspend inline fun <T, R> SmartKeyRWLocker<T>.withWriteLocks(keys: Iterable<T>, action: () -> R): R {
|
||||
contract {
|
||||
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
|
||||
val locked = mutableSetOf<T>()
|
||||
try {
|
||||
keys.forEach {
|
||||
lockWrite(it)
|
||||
locked.add(it)
|
||||
}
|
||||
return action()
|
||||
} finally {
|
||||
locked.forEach {
|
||||
unlockWrite(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,10 @@ import kotlin.contracts.contract
|
||||
/**
|
||||
* Composite mutex which works with next rules:
|
||||
*
|
||||
* * [acquireRead] require to [writeMutex] be free. Then it will take one lock from [readSemaphore]
|
||||
* * [acquireRead] require to [writeMutex] to be free. Then it will take one lock from [readSemaphore]
|
||||
* * [releaseRead] will just free up one permit in [readSemaphore]
|
||||
* * [lockWrite] will lock [writeMutex] and then await while all [readSemaphore] will be freed
|
||||
* * [lockWrite] will lock [writeMutex] and then await while all [readSemaphore] will be freed. If coroutine will be
|
||||
* cancelled during read semaphore freeing, locking will be cancelled too with [SmartMutex.Mutable.unlock]ing of [writeMutex]
|
||||
* * [unlockWrite] will just unlock [writeMutex]
|
||||
*/
|
||||
class SmartRWLocker(private val readPermits: Int = Int.MAX_VALUE, writeIsLocked: Boolean = false) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.micro_utils.repos.annotations.OverrideRequireManualInvalidation
|
||||
import dev.inmo.micro_utils.repos.cache.util.ActualizeAllClearMode
|
||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||
import dev.inmo.micro_utils.repos.pagination.maxPagePagination
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
@@ -8,9 +8,6 @@ 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.annotations.OverrideRequireManualInvalidation
|
||||
import dev.inmo.micro_utils.repos.cache.full.FullKeyValueCacheRepo
|
||||
import dev.inmo.micro_utils.repos.cache.full.FullReadKeyValueCacheRepo
|
||||
import dev.inmo.micro_utils.repos.cache.full.FullWriteKeyValueCacheRepo
|
||||
import dev.inmo.micro_utils.repos.cache.util.actualizeAll
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package dev.inmo.micro_utils.repos.cache.full.direct
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.coroutines.SmartRWLocker
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import dev.inmo.micro_utils.coroutines.withReadAcquire
|
||||
|
||||
Reference in New Issue
Block a user