gnomon (gnomon v1.0.0)
View SourceHTTP Date header values served from a persistent term.
The current date is stored as one small integer in a persistent term. On 64-bit BEAM a small integer is an immediate, so the once-per-second update and the erase on shutdown never trigger the global garbage collection pass that persistent terms normally cause. Readers unpack the integer with bsr and band and assemble the 29-byte value from seven fixed-width integer segments taken from literal tables, so a read is one persistent-term lookup and one small binary on the caller's heap.
The gnomon application runs gnomon_clock, which keeps the value fresh. When no clock is running, on a 32-bit emulator or outside the application, readers compute the date from the system clock, which is correct but slower.
The packed layout, from the least significant bit:
second 6 bits shift 0
minute 6 bits shift 6
hour 5 bits shift 12
weekday 3 bits shift 17 0 = Monday
day 5 bits shift 20 1..31
month 4 bits shift 25 1..12
year 14 bits shift 29 0..9999
Summary
Functions
Erases the persistent term.
The current IMF-fixdate as a 29-byte binary, for example <<"Sun, 06 Nov 1994 08:49:37 GMT">>. This is the hot path.
Formats the given Unix time (seconds since the epoch, UTC) as a 29-byte IMF-fixdate binary, the same shape as date/0.
Packs the given Unix time into the small integer this library stores in its persistent term.
Writes the packed value for the current system time. gnomon_clock calls this once per second. A clock run instead of the application must call clear/0 when it stops, or readers keep serving a frozen date.
Functions
-spec clear() -> ok.
Erases the persistent term.
-spec date() -> binary().
The current IMF-fixdate as a 29-byte binary, for example <<"Sun, 06 Nov 1994 08:49:37 GMT">>. This is the hot path.
A binary is valid iodata and valid chardata; an API that insists on a list can take [gnomon:date()]. The binary is built from seven fixed-width integer segments, each a field's ASCII bytes as an integer from a literal table. The compiler knows the total size, so the result lives on the caller's heap rather than off-heap with a reference count, and each segment is written as a word rather than copied from a binary. This measured faster than an improper-list iodata form, than iolist_to_binary/1 over such a list, than a variable-size construction and than fixed-size binary segments when the library was written.
Reads the packed value from the persistent term. If no gnomon_clock is running the value is computed from the system clock instead.
Formats the given Unix time (seconds since the epoch, UTC) as a 29-byte IMF-fixdate binary, the same shape as date/0.
Valid for years 0 through 9999. Years outside 2000 to 2199 take a slower path that formats the year on the fly.
-spec pack(integer()) -> non_neg_integer().
Packs the given Unix time into the small integer this library stores in its persistent term.
-spec update() -> ok.
Writes the packed value for the current system time. gnomon_clock calls this once per second. A clock run instead of the application must call clear/0 when it stops, or readers keep serving a frozen date.