Skip to content

Commit

Permalink
Rename classes (#66)
Browse files Browse the repository at this point in the history
* rename classes to Mutex

* remove old naming from other places

* bump to v1.2.0
  • Loading branch information
himadieievsv authored Jan 22, 2024
1 parent 8b2e864 commit 6aac897
Show file tree
Hide file tree
Showing 17 changed files with 240 additions and 240 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ It is minimalistic, lightweight, and easy to use library written in Kotlin and c

## Features

- **[RedLock](./redpulsar-core/src/main/kotlin/me/himadieiev/redpulsar/core/locks/RedLock.kt)**: Distributed lock mechanism on a resource, that uses consensus of the majority of data storage nodes to determine if check obtained successfully.
- **[Semaphore](./redpulsar-core/src/main/kotlin/me/himadieiev/redpulsar/core/locks/Semaphore.kt)**: Distributed semaphore implementation allowing multiple number of lock on a resource. It also uses consensus of the majority of data storage nodes to determine if check obtained successfully.
- **[SimpleLock](./redpulsar-core/src/main/kotlin/me/himadieiev/redpulsar/core/locks/SimpleLock.kt)**: Simplified distributed lock mechanism on a resource. Unlike [RedLock](./redpulsar-core/src/main/kotlin/me/himadieiev/redpulsar/core/locks/RedLock.kt) it uses single data storage node.
- **[ListeningCountDownLatch](./redpulsar-core/src/main/kotlin/me/himadieiev/redpulsar/core/locks/ListeningCountDownLatch.kt)**: Implementation of distributed Count Down Latch, it uses that uses consensus of the majority of data storage instances ensuring count down consistency.
[ListeningCountDownLatch](./redpulsar-core/src/main/kotlin/me/himadieiev/redpulsar/core/locks/ListeningCountDownLatch.kt) utilized [Redis Pub/Sub](https://redis.io/topics/pubsub) mechanism to notify waiting workloads about count reaching zero.
- **[Mutex](./redpulsar-core/src/main/kotlin/com/himadieiev/redpulsar/core/locks/Mutex.kt)**: Distributed lock mechanism on a resource, that uses consensus of the majority of data storage nodes to determine if check obtained successfully.
- **[Semaphore](./redpulsar-core/src/main/kotlin/com/himadieiev/redpulsar/core/locks/Semaphore.kt)**: Distributed semaphore implementation allowing multiple number of lock on a resource. It also uses consensus of the majority of data storage nodes to determine if check obtained successfully.
- **[SimplifiedMutex](./redpulsar-core/src/main/kotlin/com/himadieiev/redpulsar/core/locks/SimplifiedMutex.kt)**: Simplified distributed lock mechanism on a resource. Unlike [Mutex](./redpulsar-core/src/main/kotlin/com/himadieiev/redpulsar/core/locks/Mutex.kt) it uses single data storage node.
- **[ListeningCountDownLatch](./redpulsar-core/src/main/kotlin/com/himadieiev/redpulsar/core/locks/ListeningCountDownLatch.kt)**: Implementation of distributed Count Down Latch, it uses that uses consensus of the majority of data storage instances ensuring count down consistency.
[ListeningCountDownLatch](./redpulsar-core/src/main/kotlin/com/himadieiev/redpulsar/core/locks/ListeningCountDownLatch.kt) utilized [Redis Pub/Sub](https://redis.io/topics/pubsub) mechanism to notify waiting workloads about count reaching zero.

## Supporting data storages
Currently, RedPulsar supports Redis as a data storage. It can be used with both Jedis or Lettuce clients.
Expand Down Expand Up @@ -72,7 +72,7 @@ docker-compose up -d

### Extending RedPulsar to use other data stores
Currently, all features are implemented with Redis. However, it is possible to extend RedPulsar to use other distributed data stores like AWS DynamoDB / Casandra / ScyllaDB etc. Even it could be implemented with RDBMS like MySQL or PostgreSQL.
RedPulsar project have an abstraction level for data storage called [Backend](./redpulsar-core/src/main/kotlin/me/himadieiev/redpulsar/core/locks/abstracts/Backend.kt). See package [com.himadieiev.redpulsar.core.locks.abstracts.backends](./redpulsar-core/src/main/kotlin/me/himadieiev/redpulsar/core/locks/abstracts/backends) for details what particular operation should be implemented.
RedPulsar project have an abstraction level for data storage called [Backend](./redpulsar-core/src/main/kotlin/com/himadieiev/redpulsar/core/locks/abstracts/Backend.kt). See package [com.himadieiev.redpulsar.core.locks.abstracts.backends](./redpulsar-core/src/main/kotlin/com/himadieiev/redpulsar/core/locks/abstracts/backends) for details what particular operation should be implemented.
New data storage should use a new module and implement same abstractions as current Redis implementations.

### Contributing
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ plugins {

allprojects {
group = "com.himadieiev"
version = "1.1.5"
version = "1.2.0"

repositories {
mavenCentral()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import java.time.Duration
* @param retryCount [Int] the number of retries to acquire lock.
* @param retryDelay [Duration] the delay between retries.
*/
class RedLock(
class Mutex(
backends: List<LocksBackend>,
retryCount: Int = 3,
retryDelay: Duration = Duration.ofMillis(100),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import java.time.Duration
* @param retryDelay [Duration] the delay between retries.
* @param retryCount [Int] the number of retries to acquire lock.
*/
class SimpleLock(
class SimplifiedMutex(
private val backend: LocksBackend,
private val retryDelay: Duration = Duration.ofMillis(100),
private val retryCount: Int = 3,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import org.junit.jupiter.params.provider.ValueSource
import java.time.Duration

@Tag(TestTags.UNIT)
class RedLockTest {
class MutexTest {
@Nested
inner class SingleRedisInstance {
private lateinit var backend: LocksBackend
Expand All @@ -35,8 +35,8 @@ class RedLockTest {
fun `lock acquired`(ttl: Long) {
every { backend.setLock(eq("test"), any(), eq(Duration.ofSeconds(ttl))) } returns "OK"

val redLock = RedLock(listOf(backend))
val permit = redLock.lock("test", Duration.ofSeconds(ttl))
val mutex = Mutex(listOf(backend))
val permit = mutex.lock("test", Duration.ofSeconds(ttl))

assertTrue(permit)
verify(exactly = 1) { backend.setLock(any(), any(), any()) }
Expand All @@ -48,8 +48,8 @@ class RedLockTest {
every { backend.setLock(eq("test"), any(), eq(Duration.ofSeconds(10))) } returns null
every { backend.removeLock(eq("test"), any()) } returns "OK"

val redLock = RedLock(listOf(backend), retryCount = 3, retryDelay = Duration.ofMillis(20))
val permit = redLock.lock("test")
val mutex = Mutex(listOf(backend), retryCount = 3, retryDelay = Duration.ofMillis(20))
val permit = mutex.lock("test")

assertFalse(permit)

Expand All @@ -63,9 +63,9 @@ class RedLockTest {
fun `unlock resource`() {
every { backend.removeLock(eq("test"), any()) } returns "OK"

val redLock = RedLock(listOf(backend))
val mutex = Mutex(listOf(backend))
// It cant be guarantied that the lock was actually acquired
redLock.unlock("test")
mutex.unlock("test")

verify(exactly = 1) {
backend.removeLock(eq("test"), any())
Expand All @@ -79,28 +79,28 @@ class RedLockTest {
@ValueSource(ints = [-123, -1, 0, 1, 2, 5, 7, 10])
fun `validate retry count`(retryCount: Int) {
if (retryCount > 0) {
Assertions.assertDoesNotThrow { RedLock(listOf(backend), retryCount = retryCount) }
Assertions.assertDoesNotThrow { Mutex(listOf(backend), retryCount = retryCount) }
} else {
assertThrows<IllegalArgumentException> { RedLock(listOf(backend), retryCount = retryCount) }
assertThrows<IllegalArgumentException> { Mutex(listOf(backend), retryCount = retryCount) }
}
}

@ParameterizedTest(name = "Validated with retry delay - {0}")
@ValueSource(ints = [-123, -1, 0, 1, 2, 5, 7, 10])
fun `validate retry delay`(retryDelay: Long) {
if (retryDelay > 0) {
Assertions.assertDoesNotThrow { RedLock(listOf(backend), retryDelay = Duration.ofMillis(retryDelay)) }
Assertions.assertDoesNotThrow { Mutex(listOf(backend), retryDelay = Duration.ofMillis(retryDelay)) }
} else {
assertThrows<IllegalArgumentException> {
RedLock(listOf(backend), retryDelay = Duration.ofMillis(retryDelay))
Mutex(listOf(backend), retryDelay = Duration.ofMillis(retryDelay))
}
}
}

@Test
fun `validate instance count`() {
Assertions.assertDoesNotThrow { RedLock(listOf(backend)) }
assertThrows<IllegalArgumentException> { RedLock(listOf()) }
Assertions.assertDoesNotThrow { Mutex(listOf(backend)) }
assertThrows<IllegalArgumentException> { Mutex(listOf()) }
}

@ParameterizedTest(name = "lock acquired with ttl - {0}")
Expand All @@ -110,11 +110,11 @@ class RedLockTest {
// validity can be rejected with tiny ttl
every { backend.removeLock(eq("test"), any()) } returns "OK"

val redLock = RedLock(listOf(backend))
val mutex = Mutex(listOf(backend))
if (ttl > 2) {
Assertions.assertDoesNotThrow { redLock.lock("test", Duration.ofMillis(ttl)) }
Assertions.assertDoesNotThrow { mutex.lock("test", Duration.ofMillis(ttl)) }
} else {
assertThrows<IllegalArgumentException> { redLock.lock("test", Duration.ofMillis(ttl)) }
assertThrows<IllegalArgumentException> { mutex.lock("test", Duration.ofMillis(ttl)) }
}
}
}
Expand Down Expand Up @@ -142,8 +142,8 @@ class RedLockTest {
} returns "OK"
}

val redLock = RedLock(instances)
val permit = redLock.lock("test")
val mutex = Mutex(instances)
val permit = mutex.lock("test")

assertTrue(permit)
verify(exactly = 1) {
Expand All @@ -160,8 +160,8 @@ class RedLockTest {
every { backend2.setLock(eq("test"), any(), any()) } returns null
every { backend3.setLock(eq("test"), any(), any()) } returns "OK"

val redLock = RedLock(instances)
val permit = redLock.lock("test")
val mutex = Mutex(instances)
val permit = mutex.lock("test")

assertTrue(permit)
verify(exactly = 1) {
Expand All @@ -181,8 +181,8 @@ class RedLockTest {
every { backend.removeLock(eq("test"), any()) } returns "OK"
}

val redLock = RedLock(instances, retryCount = 3, retryDelay = Duration.ofMillis(20))
val permit = redLock.lock("test")
val mutex = Mutex(instances, retryCount = 3, retryDelay = Duration.ofMillis(20))
val permit = mutex.lock("test")

assertFalse(permit)
verify(exactly = 3) {
Expand All @@ -205,8 +205,8 @@ class RedLockTest {
every { backend.removeLock(eq("test"), any()) } returns "OK"
}

val redLock = RedLock(instances, retryCount = 3, retryDelay = Duration.ofMillis(30))
val permit = redLock.lock("test", Duration.ofMillis(30))
val mutex = Mutex(instances, retryCount = 3, retryDelay = Duration.ofMillis(30))
val permit = mutex.lock("test", Duration.ofMillis(30))

assertFalse(permit)
verify(exactly = 3) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import org.junit.jupiter.params.provider.ValueSource
import java.time.Duration

@Tag(TestTags.UNIT)
class SimpleLockTest {
class SimplifiedMutexTest {
private lateinit var backend: LocksBackend

@BeforeEach
Expand All @@ -30,8 +30,8 @@ class SimpleLockTest {
fun `lock acquired`(ttl: Long) {
every { backend.setLock(eq("test"), any(), eq(Duration.ofSeconds(ttl))) } returns "OK"

val simpleLock = SimpleLock(backend)
val permit = simpleLock.lock("test", Duration.ofSeconds(ttl))
val simplifiedMutex = SimplifiedMutex(backend)
val permit = simplifiedMutex.lock("test", Duration.ofSeconds(ttl))

assertTrue(permit)
verify(exactly = 1) {
Expand All @@ -44,8 +44,8 @@ class SimpleLockTest {
// every { redis.set(eq("test"), any(), any()) } returns null
every { backend.setLock(eq("test"), any(), eq(Duration.ofSeconds(1))) } returns null

val simpleLock = SimpleLock(backend, retryDelay = Duration.ofMillis(20), retryCount = 3)
val permit = simpleLock.lock("test", Duration.ofSeconds(1))
val simplifiedMutex = SimplifiedMutex(backend, retryDelay = Duration.ofMillis(20), retryCount = 3)
val permit = simplifiedMutex.lock("test", Duration.ofSeconds(1))

assertFalse(permit)

Expand All @@ -56,8 +56,8 @@ class SimpleLockTest {
fun `unlock resource`() {
every { backend.removeLock(eq("test"), any()) } returns "OK"

val simpleLock = SimpleLock(backend)
simpleLock.unlock("test")
val simplifiedMutex = SimplifiedMutex(backend)
simplifiedMutex.unlock("test")

verify(exactly = 1) {
backend.removeLock(eq("test"), any())
Expand All @@ -71,19 +71,19 @@ class SimpleLockTest {
@ValueSource(ints = [-123, -1, 0, 1, 2, 5, 7, 10])
fun `validate retry count`(retryCount: Int) {
if (retryCount > 0) {
assertDoesNotThrow { SimpleLock(backend, retryCount = retryCount) }
assertDoesNotThrow { SimplifiedMutex(backend, retryCount = retryCount) }
} else {
assertThrows<IllegalArgumentException> { SimpleLock(backend, retryCount = retryCount) }
assertThrows<IllegalArgumentException> { SimplifiedMutex(backend, retryCount = retryCount) }
}
}

@ParameterizedTest(name = "Validated with retry delay - {0}")
@ValueSource(ints = [-123, -1, 0, 1, 2, 5, 7, 10])
fun `validate retry delay`(retryDelay: Long) {
if (retryDelay > 0) {
assertDoesNotThrow { SimpleLock(backend, retryDelay = Duration.ofMillis(retryDelay)) }
assertDoesNotThrow { SimplifiedMutex(backend, retryDelay = Duration.ofMillis(retryDelay)) }
} else {
assertThrows<IllegalArgumentException> { SimpleLock(backend, retryDelay = Duration.ofMillis(retryDelay)) }
assertThrows<IllegalArgumentException> { SimplifiedMutex(backend, retryDelay = Duration.ofMillis(retryDelay)) }
}
}

Expand All @@ -92,11 +92,11 @@ class SimpleLockTest {
fun `validate ttl`(ttl: Long) {
every { backend.setLock(eq("test"), any(), any()) } returns "OK"

val simpleLock = SimpleLock(backend)
val simplifiedMutex = SimplifiedMutex(backend)
if (ttl > 2) {
assertDoesNotThrow { simpleLock.lock("test", Duration.ofMillis(ttl)) }
assertDoesNotThrow { simplifiedMutex.lock("test", Duration.ofMillis(ttl)) }
} else {
assertThrows<IllegalArgumentException> { simpleLock.lock("test", Duration.ofMillis(ttl)) }
assertThrows<IllegalArgumentException> { simplifiedMutex.lock("test", Duration.ofMillis(ttl)) }
}
}
}
4 changes: 2 additions & 2 deletions redpulsar-jedis/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ val client = JedisPooled(poolConfig, "localhost", 6379, 100)
Creating lock:
```kotlin
// Create lock
val lock = LockFactory.createSimpleLock(client)
val lock = LockFactory.createSimplifiedMutex(client)
lock.lock("myResource", Duration.ofSeconds(1))
// do something
lock.unlock("myResource")
Expand All @@ -26,7 +26,7 @@ var client = new JedisPooled(poolConfig, "localhost", 6381, 100);
Creating lock:
```java
// Create lock
var lock = LockFactory.createSimpleLock(client, Duration.ofSeconds(1), 3);
var lock = LockFactory.createSimplifiedMutex(client, Duration.ofSeconds(1), 3);
lock.lock("myResource", Duration.ofSeconds(1));
// do something
lock.unlock("myResource");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.himadieiev.redpulsar.jedis.locks

import com.himadieiev.redpulsar.core.locks.ListeningCountDownLatch
import com.himadieiev.redpulsar.core.locks.RedLock
import com.himadieiev.redpulsar.core.locks.Mutex
import com.himadieiev.redpulsar.core.locks.Semaphore
import com.himadieiev.redpulsar.core.locks.SimpleLock
import com.himadieiev.redpulsar.core.locks.SimplifiedMutex
import com.himadieiev.redpulsar.jedis.locks.backends.JedisCountDownLatchBackend
import com.himadieiev.redpulsar.jedis.locks.backends.JedisLocksBackend
import redis.clients.jedis.UnifiedJedis
Expand All @@ -15,36 +15,36 @@ import java.time.Duration
class LockFactory {
companion object {
/**
* Create a new [SimpleLock] instance.
* Create a new [SimplifiedMutex] instance.
* @param client [UnifiedJedis] the Jedis client instance to use for lock.
* @param retryDelay [Duration] the delay between retries.
* @param retryCount [Int] the number of retries.
* @return [SimpleLock] the lock instance.
* @return [SimplifiedMutex] the lock instance.
*/
@JvmStatic
fun createSimpleLock(
fun createSimplifiedMutex(
client: UnifiedJedis,
retryDelay: Duration = Duration.ofMillis(100),
retryCount: Int = 3,
): SimpleLock {
return SimpleLock(JedisLocksBackend(client), retryDelay, retryCount)
): SimplifiedMutex {
return SimplifiedMutex(JedisLocksBackend(client), retryDelay, retryCount)
}

/**
* Create a new [RedLock] instance.
* Create a new [Mutex] instance.
* @param clients [List]<[UnifiedJedis]> the Jedis client instances to use for lock.
* @param retryDelay [Duration] the delay between retries.
* @param retryCount [Int] the number of retries.
* @return [RedLock] the lock instance.
* @return [Mutex] the lock instance.
*/
@JvmStatic
fun createRedLock(
fun createMutex(
clients: List<UnifiedJedis>,
retryDelay: Duration = Duration.ofMillis(100),
retryCount: Int = 3,
): RedLock {
): Mutex {
val backends = clients.map { JedisLocksBackend(it) }
return RedLock(backends, retryCount, retryDelay)
return Mutex(backends, retryCount, retryDelay)
}

/**
Expand Down
Loading

0 comments on commit 6aac897

Please sign in to comment.