-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathfrugal-uuid-clock.lisp
70 lines (59 loc) · 2.61 KB
/
frugal-uuid-clock.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
;;;; frugal-uuid-clock.lisp
(in-package #:frugal-uuid)
(defconstant +millis-per-second+ 1000)
(defconstant +nanos-per-second+ 1000000000)
(defconstant +nanos-per-milli+ 1000000)
(defconstant +100nanos-per-second+ (/ +nanos-per-second+ 100))
(defconstant +unix-time-uuid-epoch-offset-seconds+ 12219292800)
(defconstant +universal-time-unix-epoch-offset+
(encode-universal-time 0 0 0 1 1 1970 0))
(defun get-unix-time ()
(values (- (get-universal-time)
+universal-time-unix-epoch-offset+)
nil))
(defvar *unix-timestamp-function* #'get-unix-time
"Function should return the number of seconds since the unix epoch and
the number of additional nanoseconds as a second value or NIL if
unknown.")
(defun random-clock-seq ()
;; Only use 13 bits for initial clock-seq to
;; minimize rollover:
(random-integer #b1111111111111))
(defun get-current-timestamp (uuid-epoch make-fraction-function)
(multiple-value-bind (seconds nanos) (funcall *unix-timestamp-function*)
(let* ((seconds (if uuid-epoch
(+ seconds +unix-time-uuid-epoch-offset-seconds+)
seconds))
(fraction (if (and nanos make-fraction-function)
(funcall make-fraction-function nanos)
nanos)))
(values seconds fraction))))
(defun make-timestamp-generator
(&key (uuid-epoch t) (make-fraction-function nil) (repetitions-increment 1))
(let ((previous-base nil)
(previous-fraction nil)
(repetitions 0))
(lambda ()
(multiple-value-bind (base fraction)
(get-current-timestamp uuid-epoch make-fraction-function)
(labels ((return-results (n)
(setf previous-base base
previous-fraction fraction)
(values base fraction n)))
(cond
;; No previous timestamp means no repetitions
((null previous-base) (return-results repetitions))
;; Timestamp is the same as the previous one
((and (eql base previous-base)
(eql fraction previous-fraction))
(return-results (incf repetitions repetitions-increment)))
;; Time went backwards, unknown number of repetitions
((or (< base previous-base)
(and (eql base previous-base)
fraction
(< fraction previous-fraction)))
(setf repetitions 0)
(return-results nil))
;; We have a new timestamp, reset number of repetitions
(t (setf repetitions 0)
(return-results repetitions))))))))