diff --git a/C/source/.gitignore b/C/source/.gitignore index 69294d6..67cc059 100644 --- a/C/source/.gitignore +++ b/C/source/.gitignore @@ -1,7 +1,7 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. -./build/* +build/* # User-specific files *.suo diff --git a/D/.gitignore b/D/.gitignore index dc69746..10b9ca8 100644 --- a/D/.gitignore +++ b/D/.gitignore @@ -1,9 +1,9 @@ .DS_Store -./test/test -./libyitterd.a -./dub.*.json -./.dub/* -./test/.dub/* -./test/dub.*.json +test/test +libyitterd.a +dub.*.json +.dub/* +test/.dub/* +test/dub.*.json diff --git a/D/source/yitter/contract/IdGeneratorOptions.d b/D/source/yitter/contract/IdGeneratorOptions.d index 088b9e0..328842b 100644 --- a/D/source/yitter/contract/IdGeneratorOptions.d +++ b/D/source/yitter/contract/IdGeneratorOptions.d @@ -22,8 +22,7 @@ class IdGeneratorOptions { * 基础时间(ms单位) * 不能超过当前系统时间 */ - // long BaseTime = 1582136402000L; - SysTime BaseTime; + long BaseTime = 1582136402000L; /** * 机器码 @@ -62,11 +61,9 @@ class IdGeneratorOptions { short TopOverCostCount = 2000; this() { - BaseTime = SysTime(DateTime(2020, 2, 20, 2, 20, 2)); } this(short workerId) { WorkerId = workerId; - BaseTime = SysTime(DateTime(2020, 2, 20, 2, 20, 2)); } } diff --git a/D/source/yitter/core/DateTimeHelper.d b/D/source/yitter/core/DateTimeHelper.d new file mode 100644 index 0000000..8a676cb --- /dev/null +++ b/D/source/yitter/core/DateTimeHelper.d @@ -0,0 +1,173 @@ +module yitter.core.DateTimeHelper; + +import core.stdc.time; +import std.datetime : convert; +import std.string; + +enum TimeUnit : string { + Year = "years", + Month = "months", + Week = "weeks", + Day = "days", + Hour = "hours", + Second = "seconds", + Millisecond = "msecs", + Microsecond = "usecs", + HectoNanosecond = "hnsecs", + Nanosecond = "nsecs" +} + + +/** + * + */ +class DateTimeHelper { + /** + * Returns the current time in milliseconds. Note that + * while the unit of time of the return value is a millisecond, + * the granularity of the value depends on the underlying + * operating system and may be larger. For example, many + * operating systems measure time in units of tens of + * milliseconds. + * + *

See the description of the class {@code Date} for + * a discussion of slight discrepancies that may arise between + * "computer time" and coordinated universal time (UTC). + * + * @return the difference, measured in milliseconds, between + * the current time and midnight, January 1, 1970 UTC. + */ + static long currentTimeMillis() @trusted @property { + return currentTime!(TimeUnit.Millisecond)(); + } + + static long currentTimeNsecs() @trusted @property { + return currentTime!(TimeUnit.Nanosecond)(); + } + + static long currentUnixTime() @trusted @property { + return currentTime!(TimeUnit.Second)(); + } + + alias currentTimeSecond = currentUnixTime; + + /** + * + */ + static long currentTime(TimeUnit targetUnit)() @trusted @property { + version (Windows) { + import core.sys.windows.winbase; + import core.sys.windows.winnt; + + /** + http://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ + https://stackoverflow.com/questions/10849717/what-is-the-significance-of-january-1-1601 + https://stackoverflow.com/questions/1090869/why-is-1-1-1970-the-epoch-time + https://www.unixtimestamp.com/ + */ + FILETIME fileTime; + GetSystemTimeAsFileTime(&fileTime); + ULARGE_INTEGER date, adjust; + date.HighPart = fileTime.dwHighDateTime; + date.LowPart = fileTime.dwLowDateTime; + + // 100-nanoseconds = milliseconds * 10000 + adjust.QuadPart = 11644473600000 * 10000; + + // removes the diff between 1970 and 1601 + date.QuadPart -= adjust.QuadPart; + + // converts back from 100-nanoseconds to milliseconds + return convert!(TimeUnit.HectoNanosecond, targetUnit)(date.QuadPart); + + } else version (Posix) { + import core.sys.posix.signal : timespec; + version (OSX) { + import core.sys.posix.sys.time : gettimeofday, timeval; + + timeval tv = void; + // Posix gettimeofday called with a valid timeval address + // and a null second parameter doesn't fail. + gettimeofday(&tv, null); + return convert!(TimeUnit.Second, targetUnit)(tv.tv_sec) + + convert!(TimeUnit.Microsecond, targetUnit)(tv.tv_usec); + + } else version (linux) { + import core.sys.linux.time : CLOCK_REALTIME_COARSE; + import core.sys.posix.time : clock_gettime, CLOCK_REALTIME; + + timespec ts = void; + immutable error = clock_gettime(CLOCK_REALTIME, &ts); + // Posix clock_gettime called with a valid address and valid clock_id is only + // permitted to fail if the number of seconds does not fit in time_t. If tv_sec + // is long or larger overflow won't happen before 292 billion years A.D. + static if (ts.tv_sec.max < long.max) { + if (error) + throw new TimeException("Call to clock_gettime() failed"); + } + return convert!(TimeUnit.Second, targetUnit)(ts.tv_sec) + + convert!(TimeUnit.Nanosecond, targetUnit)(ts.tv_nsec); + + } else version (FreeBSD) { + import core.sys.freebsd.time : clock_gettime, CLOCK_REALTIME; + + timespec ts = void; + immutable error = clock_gettime(CLOCK_REALTIME, &ts); + // Posix clock_gettime called with a valid address and valid clock_id is only + // permitted to fail if the number of seconds does not fit in time_t. If tv_sec + // is long or larger overflow won't happen before 292 billion years A.D. + static if (ts.tv_sec.max < long.max) { + if (error) + throw new TimeException("Call to clock_gettime() failed"); + } + return convert!(TimeUnit.Second, targetUnit)(ts.tv_sec) + + convert!(TimeUnit.Nanosecond, targetUnit)(ts.tv_nsec); + } else version (NetBSD) { + import core.sys.netbsd.time : clock_gettime, CLOCK_REALTIME; + + timespec ts = void; + immutable error = clock_gettime(CLOCK_REALTIME, &ts); + // Posix clock_gettime called with a valid address and valid clock_id is only + // permitted to fail if the number of seconds does not fit in time_t. If tv_sec + // is long or larger overflow won't happen before 292 billion years A.D. + static if (ts.tv_sec.max < long.max) { + if (error) + throw new TimeException("Call to clock_gettime() failed"); + } + return convert!(TimeUnit.Second, targetUnit)(ts.tv_sec) + + convert!(TimeUnit.Nanosecond, targetUnit)(ts.tv_nsec); + } else version (DragonFlyBSD) { + import core.sys.dragonflybsd.time : clock_gettime, CLOCK_REALTIME; + + timespec ts = void; + immutable error = clock_gettime(CLOCK_REALTIME, &ts); + // Posix clock_gettime called with a valid address and valid clock_id is only + // permitted to fail if the number of seconds does not fit in time_t. If tv_sec + // is long or larger overflow won't happen before 292 billion years A.D. + static if (ts.tv_sec.max < long.max) { + if (error) + throw new TimeException("Call to clock_gettime() failed"); + } + return convert!(TimeUnit.Second, targetUnit)(ts.tv_sec) + + convert!(TimeUnit.Nanosecond, targetUnit)(ts.tv_nsec); + } else version (Solaris) { + import core.sys.solaris.time : clock_gettime, CLOCK_REALTIME; + + timespec ts = void; + immutable error = clock_gettime(CLOCK_REALTIME, &ts); + // Posix clock_gettime called with a valid address and valid clock_id is only + // permitted to fail if the number of seconds does not fit in time_t. If tv_sec + // is long or larger overflow won't happen before 292 billion years A.D. + static if (ts.tv_sec.max < long.max) { + if (error) + throw new TimeException("Call to clock_gettime() failed"); + } + return convert!(TimeUnit.Second, targetUnit)(ts.tv_sec) + + convert!(TimeUnit.Nanosecond, targetUnit)(ts.tv_nsec); + } else + static assert(0, "Unsupported OS"); + } else + static assert(0, "Unsupported OS"); + } + +} \ No newline at end of file diff --git a/D/source/yitter/core/SnowWorkerM1.d b/D/source/yitter/core/SnowWorkerM1.d index 935243b..f5e456a 100644 --- a/D/source/yitter/core/SnowWorkerM1.d +++ b/D/source/yitter/core/SnowWorkerM1.d @@ -4,6 +4,7 @@ */ module yitter.core.SnowWorkerM1; +import yitter.core.DateTimeHelper; import yitter.contract.ISnowWorker; import yitter.contract.IdGeneratorOptions; import yitter.contract.OverCostActionArg; @@ -11,12 +12,13 @@ import yitter.contract.IdGeneratorException; import std.datetime; + class SnowWorkerM1 : ISnowWorker { /** * 基础时间 */ - protected SysTime BaseTime; + protected long BaseTime; /** * 机器码 @@ -49,7 +51,6 @@ class SnowWorkerM1 : ISnowWorker { protected int TopOverCostCount; protected byte _TimestampShift; - // protected __gshared Object _SyncLock; // = new byte[0]; protected short _CurrentSeqNumber; protected long _LastTimeTick = 0; @@ -61,12 +62,8 @@ class SnowWorkerM1 : ISnowWorker { protected int _GenCountInOneTerm = 0; protected int _TermIndex = 0; - // shared static this() { - // _SyncLock = new Object(); - // } - this(IdGeneratorOptions options) { - BaseTime = options.BaseTime != SysTime.min ? options.BaseTime : SysTime(DateTime(2020, 2, 20, 2, 20, 2)); + BaseTime = options.BaseTime != 0 ? options.BaseTime : 1582136402000L; WorkerIdBitLength = options.WorkerIdBitLength == 0 ? 6 : options.WorkerIdBitLength; WorkerId = options.WorkerId; SeqBitLength = options.SeqBitLength == 0 ? 6 : options.SeqBitLength; @@ -212,14 +209,11 @@ class SnowWorkerM1 : ISnowWorker { } protected long GetCurrentTimeTick() { - SysTime now = Clock.currTime; - Duration dur = Clock.currTime - BaseTime; - return dur.total!("msecs"); + return DateTimeHelper.currentTimeMillis - BaseTime; } protected long GetNextTimeTick() { long tempTimeTicker = GetCurrentTimeTick(); - while (tempTimeTicker <= _LastTimeTick) { tempTimeTicker = GetCurrentTimeTick(); } @@ -227,8 +221,7 @@ class SnowWorkerM1 : ISnowWorker { return tempTimeTicker; } - override - long nextId() { + override long nextId() { synchronized { return _IsOverCost ? NextOverCostId() : NextNormalId(); } diff --git a/D/source/yitter/core/SnowWorkerM2.d b/D/source/yitter/core/SnowWorkerM2.d index 474f8cc..da01d08 100644 --- a/D/source/yitter/core/SnowWorkerM2.d +++ b/D/source/yitter/core/SnowWorkerM2.d @@ -21,8 +21,7 @@ class SnowWorkerM2 : SnowWorkerM1 { super(options); } - override - long nextId() { + override long nextId() { synchronized { long currentTimeTick = GetCurrentTimeTick(); diff --git a/D/source/yitter/idgen/DefaultIdGenerator.d b/D/source/yitter/idgen/DefaultIdGenerator.d index fe33134..47b43b7 100644 --- a/D/source/yitter/idgen/DefaultIdGenerator.d +++ b/D/source/yitter/idgen/DefaultIdGenerator.d @@ -8,6 +8,8 @@ import yitter.contract.IIdGenerator; import yitter.contract.ISnowWorker; import yitter.contract.IdGeneratorException; import yitter.contract.IdGeneratorOptions; + +import yitter.core.DateTimeHelper; import yitter.core.SnowWorkerM1; import yitter.core.SnowWorkerM2; @@ -31,8 +33,7 @@ class DefaultIdGenerator : IIdGenerator { } // 1.BaseTime - SysTime MinBaseTime = SysTime(DateTime(2020, 2, 20, 2, 20, 2)).add!"years"(-50); - if (options.BaseTime < MinBaseTime || options.BaseTime > Clock.currTime) { + if (options.BaseTime < 315504000000L || options.BaseTime > DateTimeHelper.currentTimeMillis) { throw new IdGeneratorException("BaseTime error."); } diff --git a/D/source/yitter/package.d b/D/source/yitter/package.d index 2f044e6..1f630f7 100644 --- a/D/source/yitter/package.d +++ b/D/source/yitter/package.d @@ -1,6 +1,7 @@ module yitter; public import yitter.contract; +public import yitter.core.DateTimeHelper; public import yitter.idgen.DefaultIdGenerator; public import yitter.idgen.YitIdHelper; diff --git a/D/test/source/GenTest.d b/D/test/source/GenTest.d index f60d39f..a1b789d 100644 --- a/D/test/source/GenTest.d +++ b/D/test/source/GenTest.d @@ -32,7 +32,7 @@ class GenTest { // writeln(id); writeln("++++++++++++++++++++++++++++++++++++++++WorkerId: " - ~ WorkerId.to!string() ~ ", total: " ~ dur.total!("msecs").to!string() ~ " ms"); + ~ WorkerId.to!string() ~ ", total: " ~ dur.total!("usecs").to!string() ~ " us"); } } diff --git a/D/test/source/app.d b/D/test/source/app.d index c2c9349..0c11f9f 100644 --- a/D/test/source/app.d +++ b/D/test/source/app.d @@ -27,7 +27,7 @@ void main() IdGeneratorOptions options = new IdGeneratorOptions(); options.Method = method; - options.BaseTime = SysTime(DateTime(2020, 2, 20, 21, 51, 33)); + options.BaseTime = 1582206693000L; options.WorkerId = 1; IIdGenerator idGen = new DefaultIdGenerator(options); @@ -37,13 +37,13 @@ void main() YitIdHelper.setIdGenerator(options); long newId = YitIdHelper.nextId(); writeln("====================================="); - writeln("这是用方法 " ~ method.to!string() ~ " 生成的 Id:" ~ newId.to!string()); + writeln("Method " ~ method.to!string() ~ " used, the result Id:" ~ newId.to!string()); // 然后循环测试一下,看看并发请求时的耗时情况 try { while (true) { genTest.GenStart(); - // Thread.sleep(200.msecs); // 每隔1秒执行一次GenStart + Thread.sleep(1000.msecs); // writeln("Hello World! D"); } } catch (Exception e) {