From 3ef6b7ed8ff1dafd613854ec23becf6700b97ee1 Mon Sep 17 00:00:00 2001 From: Looly Date: Wed, 25 Oct 2023 11:24:50 +0800 Subject: [PATCH] =?UTF-8?q?Snowflake=E5=A2=9E=E5=8A=A0=E6=96=B9=E6=B3=95?= =?UTF-8?q?=EF=BC=9A=E6=A0=B9=E6=8D=AE=E4=BC=A0=E5=85=A5=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E6=88=B3=EF=BC=8C=E8=AE=A1=E7=AE=97ID=E8=B5=B7=E7=BB=88?= =?UTF-8?q?=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hutool/core/data/id/Snowflake.java | 37 ++++++++++++++++++- .../hutool/core/io/file/PathCopier.java | 6 ++- .../hutool/core/lang/SnowflakeTest.java | 27 +++++++++++++- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/data/id/Snowflake.java b/hutool-core/src/main/java/org/dromara/hutool/core/data/id/Snowflake.java index 026fca697..229674b20 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/data/id/Snowflake.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/data/id/Snowflake.java @@ -14,8 +14,9 @@ package org.dromara.hutool.core.data.id; import org.dromara.hutool.core.date.SystemClock; import org.dromara.hutool.core.lang.Assert; -import org.dromara.hutool.core.util.RandomUtil; +import org.dromara.hutool.core.lang.tuple.Pair; import org.dromara.hutool.core.text.StrUtil; +import org.dromara.hutool.core.util.RandomUtil; import java.io.Serializable; import java.util.Date; @@ -259,6 +260,40 @@ public class Snowflake implements Serializable { return Long.toString(nextId()); } + /** + * 根据传入时间戳-计算ID起终点 + * + * @param timestampStart 开始时间戳 + * @param timestampEnd 结束时间戳 + * @return key-ID起点,Value-ID终点 + * @since 5.8.23 + */ + public Pair getIdScopeByTimestamp(final long timestampStart, final long timestampEnd) { + return getIdScopeByTimestamp(timestampStart, timestampEnd, true); + } + + /** + * 根据传入时间戳-计算ID起终点 Gitee/issues/I60M14 + * + * @param timestampStart 开始时间戳 + * @param timestampEnd 结束时间戳 + * @param ignoreCenterAndWorker 是否忽略数据中心和机器节点的占位,忽略后可获得分布式环境全局可信赖的起终点。 + * @return key-ID起点,Value-ID终点 + * @since 5.8.23 + */ + public Pair getIdScopeByTimestamp(final long timestampStart, final long timestampEnd, final boolean ignoreCenterAndWorker) { + final long startTimeMinId = (timestampStart - twepoch) << TIMESTAMP_LEFT_SHIFT; + final long endTimeMinId = (timestampEnd - twepoch) << TIMESTAMP_LEFT_SHIFT; + if (ignoreCenterAndWorker) { + final long endId = endTimeMinId | ~(-1 << TIMESTAMP_LEFT_SHIFT); + return Pair.of(startTimeMinId, endId); + } else { + final long startId = startTimeMinId | (dataCenterId << DATA_CENTER_ID_SHIFT) | (workerId << WORKER_ID_SHIFT); + final long endId = endTimeMinId | (dataCenterId << DATA_CENTER_ID_SHIFT) | (workerId << WORKER_ID_SHIFT) | SEQUENCE_MASK; + return Pair.of(startId, endId); + } + } + // ------------------------------------------------------------------------------------------------------------------------------------ Private method start /** diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/io/file/PathCopier.java b/hutool-core/src/main/java/org/dromara/hutool/core/io/file/PathCopier.java index a98f60309..bc145e27f 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/io/file/PathCopier.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/io/file/PathCopier.java @@ -128,6 +128,7 @@ public class PathCopier extends SrcToDestCopier { return copyFile(src, target, options); } + // region private methods /** * 拷贝目录下的所有文件或目录到目标目录中,此方法不支持文件对文件的拷贝。 *
    @@ -161,8 +162,8 @@ public class PathCopier extends SrcToDestCopier { * @throws IORuntimeException IO异常 */ private static Path copyFile(final Path src, final Path target, final CopyOption... options) throws IORuntimeException { - Assert.notNull(src, "Source File is null !"); - Assert.notNull(target, "Destination File or directory is null !"); + Assert.notNull(src, "Source file is null !"); + Assert.notNull(target, "Target file or directory is null !"); final Path targetPath = PathUtil.isDirectory(target) ? target.resolve(src.getFileName()) : target; // 创建级联父目录 @@ -173,4 +174,5 @@ public class PathCopier extends SrcToDestCopier { throw new IORuntimeException(e); } } + // endregion } diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/SnowflakeTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/SnowflakeTest.java index 1cc2558b6..23f0c99b6 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/lang/SnowflakeTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/SnowflakeTest.java @@ -13,11 +13,13 @@ package org.dromara.hutool.core.lang; import org.dromara.hutool.core.collection.ConcurrentHashSet; -import org.dromara.hutool.core.exception.HutoolException; import org.dromara.hutool.core.data.id.IdUtil; import org.dromara.hutool.core.data.id.Snowflake; +import org.dromara.hutool.core.exception.HutoolException; +import org.dromara.hutool.core.lang.tuple.Pair; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.thread.ThreadUtil; +import org.dromara.hutool.core.util.RandomUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -116,4 +118,27 @@ public class SnowflakeTest { } }); } + + /** + * 测试-根据传入时间戳-计算ID起终点 + */ + @Test + public void snowflakeTestGetIdScope() { + final long workerId = RandomUtil.randomLong(31); + final long dataCenterId = RandomUtil.randomLong(31); + final Snowflake idWorker = new Snowflake(workerId, dataCenterId); + final long generatedId = idWorker.nextId(); + // 随机忽略数据中心和工作机器的占位 + final boolean ignore = RandomUtil.randomBoolean(); + final long createTimestamp = idWorker.getGenerateDateTime(generatedId); + final Pair idScope = idWorker.getIdScopeByTimestamp(createTimestamp, createTimestamp, ignore); + final long startId = idScope.getLeft(); + final long endId = idScope.getRight(); + + // 起点终点相差比较 + final long trueOffSet = endId - startId; + // 忽略数据中心和工作机器时差值为22个1,否则为12个1 + final long expectedOffSet = ignore ? ~(-1 << 22) : ~(-1 << 12); + Assertions.assertEquals(trueOffSet, expectedOffSet); + } }