You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

uSnowWorkerM1.pas 10 kB

2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. unit uSnowWorkerM1;
  2. interface
  3. uses
  4. uISnowWorker, uIdGeneratorOptions, System.SyncObjs, uTOverCostActionArg, System.DateUtils, System.SysUtils;
  5. /// <summary>
  6. /// ѩƯ㷨
  7. /// </summary>
  8. type
  9. TSnowWorkerM1 = class(TInterfacedObject, ISnowWorker)
  10. private
  11. // private static long _StartTimeTick = 0;
  12. // private static long _BaseTimeTick = 0;
  13. protected
  14. SyncLock: TCriticalSection;
  15. protected
  16. // FBaseTime: TDateTime;
  17. FBaseTime: Int64;
  18. FWorkerId: Word;
  19. FWorkerIdBitLength: Byte;
  20. FSeqBitLength: Byte;
  21. FMaxSeqNumber: Integer;
  22. FMinSeqNumber: Word;
  23. FTopOverCostCount: Integer;
  24. //
  25. FTimestampShift: Byte;
  26. FCurrentSeqNumber: Word;
  27. FLastTimeTick: Int64;
  28. FTurnBackTimeTick: Int64;
  29. FTurnBackIndex: Byte;
  30. FIsOverCost: Boolean;
  31. FOverCostCountInOneTerm: Integer;
  32. //
  33. FGenCountInOneTerm: Integer;
  34. FTermIndex: Integer;
  35. protected
  36. /// <summary>
  37. /// ʱ
  38. /// </summary>
  39. // property BaseTime: TDateTime read FBaseTime write FBaseTime;
  40. property BaseTime: Int64 read FBaseTime;
  41. /// <summary>
  42. ///
  43. /// </summary>
  44. property WorkerId: Word read FWorkerId default 0;
  45. /// <summary>
  46. /// λ
  47. /// </summary>
  48. property WorkerIdBitLength: Byte read FWorkerIdBitLength default 0;
  49. /// <summary>
  50. /// λ
  51. /// </summary>
  52. property SeqBitLength: Byte read FSeqBitLength default 0;
  53. /// <summary>
  54. ///
  55. /// </summary>
  56. property MaxSeqNumber: Integer read FMaxSeqNumber default 0;
  57. /// <summary>
  58. /// С
  59. /// </summary>
  60. property MinSeqNumber: Word read FMinSeqNumber default 0;
  61. /// <summary>
  62. /// Ưƴ
  63. /// </summary>
  64. property TopOverCostCount: Integer read FTopOverCostCount write FTopOverCostCount default 0;
  65. //
  66. property TimestampShift: Byte read FTimestampShift write FTimestampShift default 0;
  67. //
  68. property CurrentSeqNumber: Word read FCurrentSeqNumber write FCurrentSeqNumber;
  69. property LastTimeTick: Int64 read FLastTimeTick write FLastTimeTick default 0; // -1L
  70. property TurnBackTimeTick: Int64 read FTurnBackTimeTick write FTurnBackTimeTick default 0; // -1L;
  71. property TurnBackIndex: Byte read FTurnBackIndex write FTurnBackIndex default 0;
  72. property IsOverCost: Boolean read FIsOverCost write FIsOverCost default False;
  73. property OverCostCountInOneTerm: Integer read FOverCostCountInOneTerm write FOverCostCountInOneTerm default 0;
  74. {$IFDEF DEBUG}
  75. property GenCountInOneTerm: Integer read FGenCountInOneTerm write FGenCountInOneTerm default 0;
  76. property TermIndex: Integer read FTermIndex write FTermIndex default 0;
  77. {$ENDIF}
  78. protected
  79. {$IFDEF DEBUG}
  80. procedure DoGenIdAction(arg: TOverCostActionArg);
  81. procedure BeginOverCostAction(UseTimeTick: Int64);
  82. procedure EndOverCostAction(UseTimeTick: Int64);
  83. procedure BeginTurnBackAction(UseTimeTick: Int64);
  84. procedure EndTurnBackAction(UseTimeTick: Int64);
  85. {$ENDIF}
  86. //
  87. function GetSecondTimeStamp(): Int64;
  88. function GetMillisecondTimeStamp(): Int64;
  89. //
  90. function CalcId(UseTimeTick: Int64): Int64; virtual;
  91. function CalcTurnBackId(UseTimeTick: Int64): Int64; virtual;
  92. function NextOverCostId(): Int64;
  93. function GetCurrentTimeTick(): Int64; virtual;
  94. function GetNextTimeTick(): Int64;
  95. public
  96. // Action<OverCostActionArg> GenAction { get; set; }
  97. function NextId(): Int64;
  98. function NextNormalId(): Int64;
  99. constructor Create(options: TIdGeneratorOptions); overload;
  100. destructor Destroy(); override;
  101. end;
  102. implementation
  103. { TSnowWorkerM1 }
  104. function TSnowWorkerM1.GetSecondTimeStamp(): Int64;
  105. var
  106. ST: TDateTime;
  107. begin
  108. ST := EncodeDateTime(1970, 1, 1, 0, 0, 0, 0);
  109. Result := MilliSecondsBetween(Now(), ST) - 28800; // 8*60*60;
  110. end;
  111. function TSnowWorkerM1.GetMillisecondTimeStamp(): Int64;
  112. var
  113. ST: TDateTime;
  114. begin
  115. ST := EncodeDateTime(1970, 1, 1, 0, 0, 0, 0);
  116. Result := MilliSecondsBetween(Now(), ST) - 28800000; // 8*60*60*1000;
  117. end;
  118. constructor TSnowWorkerM1.Create(options: TIdGeneratorOptions);
  119. begin
  120. SyncLock := TCriticalSection.Create;
  121. // 1.BaseTime
  122. if (options.BaseTime <> 0) then
  123. FBaseTime := options.BaseTime;
  124. // 2.WorkerIdBitLength
  125. if (options.WorkerIdBitLength <> 0) then
  126. begin
  127. FWorkerIdBitLength := 6;
  128. end
  129. else
  130. begin
  131. FWorkerIdBitLength := options.WorkerIdBitLength;
  132. end;
  133. // 3.WorkerId
  134. FWorkerId := options.WorkerId;
  135. // 4.SeqBitLength
  136. if (options.SeqBitLength = 0) then
  137. begin
  138. FSeqBitLength := 6;
  139. end
  140. else
  141. begin
  142. FSeqBitLength := options.SeqBitLength;
  143. end;
  144. // 5.MaxSeqNumber
  145. if (options.MaxSeqNumber <= 0) then
  146. begin
  147. FMaxSeqNumber := (1 shl SeqBitLength) - 1;
  148. end
  149. else
  150. begin
  151. FMaxSeqNumber := options.MaxSeqNumber;
  152. end;
  153. // 6.MinSeqNumber
  154. FMinSeqNumber := options.MinSeqNumber;
  155. // 7.Others
  156. FTopOverCostCount := options.TopOverCostCount;
  157. // if (TopOverCostCount = 0) then
  158. // begin
  159. // FTopOverCostCount := 2000;
  160. // end;
  161. FTimestampShift := Byte(WorkerIdBitLength + SeqBitLength);
  162. FCurrentSeqNumber := options.MinSeqNumber;
  163. // FBaseTimeTick = BaseTime.Ticks;
  164. // FStartTimeTick = (long)(DateTime.UtcNow.Subtract(BaseTime).TotalMilliseconds) - Environment.TickCount;
  165. end;
  166. destructor TSnowWorkerM1.Destroy();
  167. begin
  168. SyncLock.Free;
  169. inherited;
  170. end;
  171. {$IFDEF DEBUG}
  172. procedure TSnowWorkerM1.DoGenIdAction(arg: TOverCostActionArg);
  173. begin
  174. // //return;
  175. // Task.Run(() =>
  176. // {
  177. // GenAction(arg);
  178. // });
  179. end;
  180. procedure TSnowWorkerM1.BeginOverCostAction(UseTimeTick: Int64);
  181. begin
  182. end;
  183. procedure TSnowWorkerM1.EndOverCostAction(UseTimeTick: Int64);
  184. begin
  185. end;
  186. procedure TSnowWorkerM1.BeginTurnBackAction(UseTimeTick: Int64);
  187. begin
  188. end;
  189. procedure TSnowWorkerM1.EndTurnBackAction(UseTimeTick: Int64);
  190. begin
  191. end;
  192. {$ENDIF}
  193. function TSnowWorkerM1.NextOverCostId(): Int64;
  194. var
  195. CurrentTimeTick: Int64;
  196. begin
  197. CurrentTimeTick := GetCurrentTimeTick();
  198. if (CurrentTimeTick > FLastTimeTick) then
  199. begin
  200. {$IFDEF DEBUG}
  201. EndOverCostAction(CurrentTimeTick);
  202. FGenCountInOneTerm := 0;
  203. {$ENDIF}
  204. FLastTimeTick := CurrentTimeTick;
  205. FCurrentSeqNumber := FMinSeqNumber;
  206. FIsOverCost := False;
  207. FOverCostCountInOneTerm := 0;
  208. Result := CalcId(FLastTimeTick);
  209. Exit;
  210. end;
  211. if (FOverCostCountInOneTerm >= FTopOverCostCount) then
  212. begin
  213. {$IFDEF DEBUG}
  214. EndOverCostAction(CurrentTimeTick);
  215. FGenCountInOneTerm := 0;
  216. {$ENDIF}
  217. // TODO: Ưֹȴʱʱʱزϳ˴ܵȴϳʱ䡣
  218. // ŻΪƯֹʱʱزӦ߼ʵͣݲ
  219. FLastTimeTick := GetNextTimeTick();
  220. FCurrentSeqNumber := FMinSeqNumber;
  221. FIsOverCost := False;
  222. FOverCostCountInOneTerm := 0;
  223. Result := CalcId(FLastTimeTick);
  224. Exit;
  225. end;
  226. if (FCurrentSeqNumber > FMaxSeqNumber) then
  227. begin
  228. {$IFDEF DEBUG}
  229. Inc(FGenCountInOneTerm);
  230. {$ENDIF}
  231. Inc(FLastTimeTick);
  232. FCurrentSeqNumber := FMinSeqNumber;
  233. FIsOverCost := True;
  234. Inc(FOverCostCountInOneTerm);
  235. Result := CalcId(FLastTimeTick);
  236. Exit;
  237. end;
  238. {$IFDEF DEBUG}
  239. Inc(FGenCountInOneTerm);
  240. {$ENDIF}
  241. Result := CalcId(FLastTimeTick);
  242. end;
  243. function TSnowWorkerM1.NextNormalId: Int64;
  244. var
  245. CurrentTimeTick: Int64;
  246. begin
  247. CurrentTimeTick := GetCurrentTimeTick();
  248. if (CurrentTimeTick < FLastTimeTick) then
  249. begin
  250. if (FTurnBackTimeTick < 1) then
  251. begin
  252. FTurnBackTimeTick := FLastTimeTick - 1;
  253. Inc(FTurnBackIndex);
  254. // ÿǰ5λԤλ0ֵֹ1-4ʱز
  255. // ֧4λز򣨱زصIDظ޴λزѭʹã
  256. if (FTurnBackIndex > 4) then
  257. begin
  258. FTurnBackIndex := 1;
  259. end;
  260. {$IFDEF DEBUG}
  261. BeginTurnBackAction(FTurnBackTimeTick);
  262. {$ENDIF}
  263. end;
  264. // Sleep(1);
  265. Result := CalcTurnBackId(FTurnBackTimeTick);
  266. Exit;
  267. end;
  268. // ʱ׷ƽʱ_TurnBackTimeTick
  269. if (FTurnBackTimeTick > 0) then
  270. begin
  271. {$IFDEF DEBUG}
  272. EndTurnBackAction(FTurnBackTimeTick);
  273. {$ENDIF}
  274. FTurnBackTimeTick := 0;
  275. end;
  276. if (CurrentTimeTick > FLastTimeTick) then
  277. begin
  278. FLastTimeTick := CurrentTimeTick;
  279. FCurrentSeqNumber := FMinSeqNumber;
  280. Result := CalcId(FLastTimeTick);
  281. Exit;
  282. end;
  283. if (FCurrentSeqNumber > FMaxSeqNumber) then
  284. begin
  285. {$IFDEF DEBUG}
  286. BeginOverCostAction(CurrentTimeTick);
  287. Inc(FTermIndex);
  288. FGenCountInOneTerm := 1;
  289. {$ENDIF}
  290. FOverCostCountInOneTerm := 1;
  291. Inc(FLastTimeTick);
  292. FCurrentSeqNumber := FMinSeqNumber;
  293. FIsOverCost := True;
  294. Result := CalcId(FLastTimeTick);
  295. Exit;
  296. end;
  297. Result := CalcId(FLastTimeTick);
  298. end;
  299. function TSnowWorkerM1.CalcId(UseTimeTick: Int64): Int64;
  300. begin
  301. Result := ((UseTimeTick shl FTimestampShift) + (Int64(FWorkerId) shl FSeqBitLength) + Cardinal(FCurrentSeqNumber));
  302. Inc(FCurrentSeqNumber);
  303. end;
  304. function TSnowWorkerM1.CalcTurnBackId(UseTimeTick: Int64): Int64;
  305. begin
  306. Result := ((UseTimeTick shl FTimestampShift) + (Int64(FWorkerId) shl FSeqBitLength) + FTurnBackIndex);
  307. Dec(FTurnBackTimeTick);
  308. end;
  309. function TSnowWorkerM1.GetCurrentTimeTick(): Int64;
  310. var
  311. Millis: Int64;
  312. begin
  313. // Millis := DateTimeToUnix(Now(), False);
  314. Millis := GetMillisecondTimeStamp();
  315. Result := Millis - FBaseTime;
  316. end;
  317. function TSnowWorkerM1.GetNextTimeTick(): Int64;
  318. var
  319. TempTimeTicker: Int64;
  320. begin
  321. TempTimeTicker := GetCurrentTimeTick();
  322. while (TempTimeTicker <= FLastTimeTick) do
  323. begin
  324. // Sleep(1);
  325. TSpinWait.SpinUntil(
  326. function(): Boolean
  327. begin
  328. Result := False;
  329. end, 1);
  330. TempTimeTicker := GetCurrentTimeTick();
  331. end;
  332. Result := TempTimeTicker;
  333. end;
  334. function TSnowWorkerM1.NextId(): Int64;
  335. begin
  336. SyncLock.Enter;
  337. try
  338. if FIsOverCost then
  339. Result := NextOverCostId()
  340. else
  341. Result := NextNormalId();
  342. finally
  343. SyncLock.Leave;
  344. end;
  345. end;
  346. end.