fixes #20285; prevent oid time overflow at year 2038 (#20338)

* Revert "fixes  #20285; prevent oid time overflow at year 2038"

This reverts commit dfcdb6ec2a.

* increase time to 64 bits and clean up

* add testcase

* inline consts

* add a changelog

* fixes  #20285; prevent oid time overflow at year 2038
This commit is contained in:
ringabout
2022-09-22 21:15:27 +08:00
committed by GitHub
parent ae3dd759c4
commit db8a62d480
3 changed files with 26 additions and 26 deletions

View File

@@ -65,6 +65,8 @@
- `strutils.find` now uses and defaults to `last = -1` for whole string searches,
making limiting it to just the first char (`last = 0`) valid.
- `random.rand` now works with `Ordinal`s.
- `std/oids` now uses `int64` to store time internally (before it was int32), the length of
the string form of `Oid` changes from 24 to 32.
[//]: # "Additions:"
- Added ISO 8601 week date utilities in `times`:

View File

@@ -9,8 +9,7 @@
## Nim OID support. An OID is a global ID that consists of a timestamp,
## a unique counter and a random value. This combination should suffice to
## produce a globally distributed unique ID. This implementation was extracted
## from the MongoDB interface and is thus binary compatible with a MongoDB OID.
## produce a globally distributed unique ID.
##
## This implementation calls `initRand()` for the first call of
## `genOid`.
@@ -20,7 +19,7 @@ from std/private/decode_helpers import handleHexChar
type
Oid* = object ## An OID.
time: int32
time: int64
fuzz: int32
count: int32
@@ -44,37 +43,27 @@ proc parseOid*(str: cstring): Oid =
## Parses an OID.
var bytes = cast[cstring](addr(result.time))
var i = 0
while i < 12:
while i < 16:
bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1]))
inc(i)
template toStringImpl[T: string | cstring](result: var T, oid: Oid) =
## Stringifies `oid`.
proc `$`*(oid: Oid): string =
## Converts an OID to a string.
const hex = "0123456789abcdef"
const N = 24
when T is string:
result.setLen N
result.setLen 32
var o = oid
var bytes = cast[cstring](addr(o))
var i = 0
while i < 12:
while i < 16:
let b = bytes[i].ord
result[2 * i] = hex[(b and 0xF0) shr 4]
result[2 * i + 1] = hex[b and 0xF]
inc(i)
when T is cstring:
result[N] = '\0'
proc `$`*(oid: Oid): string =
## Converts an OID to a string.
toStringImpl(result, oid)
let
t = getTime().toUnix.int32
t = getTime().toUnix
var
seed = initRand(t)
@@ -84,24 +73,24 @@ let fuzz = cast[int32](seed.rand(high(int)))
template genOid(result: var Oid, incr: var int, fuzz: int32) =
var time = getTime().toUnix.int32
var time = getTime().toUnix
var i = cast[int32](atomicInc(incr))
bigEndian32(addr result.time, addr(time))
bigEndian64(addr result.time, addr(time))
result.fuzz = fuzz
bigEndian32(addr result.count, addr(i))
proc genOid*(): Oid =
## Generates a new OID.
runnableExamples:
doAssert ($genOid()).len == 24
doAssert ($genOid()).len == 32
runnableExamples("-r:off"):
echo $genOid() # for example, "5fc7f546ddbbc84800006aaf"
echo $genOid() # for example, "00000000632c452db08c3d19ee9073e5"
genOid(result, incr, fuzz)
proc generatedTime*(oid: Oid): Time =
## Returns the generated timestamp of the OID.
var tmp: int32
var tmp: int64
var dummy = oid.time
bigEndian32(addr(tmp), addr(dummy))
bigEndian64(addr(tmp), addr(dummy))
result = fromUnix(tmp)

View File

@@ -1,6 +1,15 @@
discard """
matrix: "--mm:refc; --mm:orc"
"""
import std/oids
block: # genOid
let x = genOid()
doAssert ($x).len == 24
doAssert ($x).len == 32
block:
let x = genOid()
let y = parseOid(cstring($x))
doAssert x == y