gnomon (gnomon v1.0.0)

View Source

HTTP 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

clear()

-spec clear() -> ok.

Erases the persistent term.

date()

-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.

format(UnixSeconds)

-spec format(integer()) -> binary().

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.

pack(UnixSeconds)

-spec pack(integer()) -> non_neg_integer().

Packs the given Unix time into the small integer this library stores in its persistent term.

update()

-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.