From 6bc01f6552c6bf523b9af668bbe8406e4255a82f Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Thu, 20 Apr 2023 22:02:14 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20ID=E7=94=9F=E6=88=90=E5=99=A8=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hideout/service/IdGenerateService.kt | 5 ++ .../service/SnowflakeIdGenerateService.kt | 47 +++++++++++++++++++ .../TwitterSnowflakeIdGenerateService.kt | 4 ++ .../TwitterSnowflakeIdGenerateServiceTest.kt | 35 ++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 src/main/kotlin/dev/usbharu/hideout/service/IdGenerateService.kt create mode 100644 src/main/kotlin/dev/usbharu/hideout/service/SnowflakeIdGenerateService.kt create mode 100644 src/main/kotlin/dev/usbharu/hideout/service/TwitterSnowflakeIdGenerateService.kt create mode 100644 src/test/kotlin/dev/usbharu/hideout/service/TwitterSnowflakeIdGenerateServiceTest.kt diff --git a/src/main/kotlin/dev/usbharu/hideout/service/IdGenerateService.kt b/src/main/kotlin/dev/usbharu/hideout/service/IdGenerateService.kt new file mode 100644 index 00000000..8a74d9e4 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/service/IdGenerateService.kt @@ -0,0 +1,5 @@ +package dev.usbharu.hideout.service + +interface IdGenerateService { + suspend fun generateId():Long +} diff --git a/src/main/kotlin/dev/usbharu/hideout/service/SnowflakeIdGenerateService.kt b/src/main/kotlin/dev/usbharu/hideout/service/SnowflakeIdGenerateService.kt new file mode 100644 index 00000000..69cda875 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/service/SnowflakeIdGenerateService.kt @@ -0,0 +1,47 @@ +package dev.usbharu.hideout.service + +import kotlinx.coroutines.delay +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import java.time.Instant + +open class SnowflakeIdGenerateService(private val baseTime:Long) : IdGenerateService { + var lastTimeStamp: Long = -1 + var sequenceId: Int = 0 + val mutex = Mutex() + + @Throws(IllegalStateException::class) + override suspend fun generateId(): Long { + return mutex.withLock { + + var timestamp = getTime() + if (timestamp < lastTimeStamp) { + while (timestamp <= lastTimeStamp) { + delay(1L) + timestamp = getTime() + } + // throw IllegalStateException(" $lastTimeStamp $timestamp ${lastTimeStamp-timestamp} ") + } + if (timestamp == lastTimeStamp) { + sequenceId++ + if (sequenceId >= 4096) { + while (timestamp <= lastTimeStamp) { + delay(1L) + timestamp = getTime() + } + sequenceId = 0 + } + } else { + sequenceId = 0 + } + lastTimeStamp = timestamp + return@withLock (timestamp - baseTime).shl(22).or(1L.shl(12)).or(sequenceId.toLong()) + } + + + } + + private fun getTime(): Long { + return Instant.now().toEpochMilli() + } +} diff --git a/src/main/kotlin/dev/usbharu/hideout/service/TwitterSnowflakeIdGenerateService.kt b/src/main/kotlin/dev/usbharu/hideout/service/TwitterSnowflakeIdGenerateService.kt new file mode 100644 index 00000000..7eb6b391 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/service/TwitterSnowflakeIdGenerateService.kt @@ -0,0 +1,4 @@ +package dev.usbharu.hideout.service + +// 2010-11-04T01:42:54.657 +object TwitterSnowflakeIdGenerateService : SnowflakeIdGenerateService(1288834974657L) diff --git a/src/test/kotlin/dev/usbharu/hideout/service/TwitterSnowflakeIdGenerateServiceTest.kt b/src/test/kotlin/dev/usbharu/hideout/service/TwitterSnowflakeIdGenerateServiceTest.kt new file mode 100644 index 00000000..d1d5ff60 --- /dev/null +++ b/src/test/kotlin/dev/usbharu/hideout/service/TwitterSnowflakeIdGenerateServiceTest.kt @@ -0,0 +1,35 @@ +package dev.usbharu.hideout.service + +//import kotlinx.coroutines.NonCancellable.message +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class TwitterSnowflakeIdGenerateServiceTest { + @Test + fun noDuplicateTest() = runBlocking { + val mutex = Mutex() + val mutableListOf = mutableListOf() + coroutineScope { + + repeat(500000) { + + launch(Dispatchers.IO) { + val id = TwitterSnowflakeIdGenerateService.generateId() + mutex.withLock { + mutableListOf.add(id) + + } + } + + } + } + + assertEquals(0, mutableListOf.size - mutableListOf.toSet().size) + } +}