The list cache in ::hot::store.

Layout: one metadata store (named by sanctions.store, default "sanctions") with a meta:<source> record per list, and one data store per list version, <store>:<source>:<version hash>, holding the index from ::sanctions::index/build: e:<id> records and b:<hh> buckets. A refresh writes the new version's store completely, then switches meta:<source> to it, then destroys the previous version's store, so readers never see a half-written list.

Refreshing: refresh-lists is meant to run from a schedule (daily). Each list is checked cheaply first (OFAC's SHA-256 file listing, the UK ETag, the EU Last-Modified, the UN body hash) and only re-indexed when it changed.

Sizes: about 19,500 OFAC SDN records, 6,400 UK, 6,300 EU, 1,000 UN and a few hundred OFAC Consolidated, roughly 1 KB each, plus 256 buckets per list. Screening never downloads anything.

Values

LIST_NAMES

LIST_NAMES: Map {
  ofac-sdn: "OFAC SDN List",
  ofac-cons: "OFAC Consolidated (non-SDN) List",
  uk: "UK Sanctions List",
  eu: "EU Consolidated Financial Sanctions List",
  un: "UN Security Council Consolidated List"
}

SOURCES

SOURCES: Vec [
  "ofac-sdn",
  "ofac-cons",
  "uk",
  "eu",
  "un"
]

WRITE_BATCH

WRITE_BATCH: Int 500

Functions

check-sources

fn (sources: Any): Vec<Str>

The requested sources (all when null or empty), or an Err naming an unknown one.

data-store-name

fn (store: Str, source: Str, version: Str): Str

The data store name for one version of a list: <store>:<source>:<first 12 hex digits of SHA-256(version)>.

fetch-source

fn (source: Str, known-version: Str?): Map

Download and parse one list: {source, version, entries, unchanged} (see each source namespace's fetch).

is-source

fn (source: Any): Bool

True for a known source key.

meta-of

fn (source: Str): Map?
fn (source: Str, opts: Map): Map?

The cached metadata for one list ({source, list, version, store, entries, keys, fetched-at, fetched-at-ms, checked-at}), or null when it was never refreshed.

meta-store

fn (cfg: Map): Map

now-ms

fn (): Int

open-lists

fn (ms: Map, cfg: Map, wanted: Vec, opts: Map): Map

open-sources

fn (opts: Map): Map

The cached lists to screen: {lists, sources, warnings} where each list is {source, store}. An Err when a requested list was never refreshed (screening it would silently find nothing), unless opts.allow-missing is true.

refresh-lists

fn (): Vec<Map>
fn (opts: Map): Vec<Map>

Refresh every list (or opts.sources), one after another. A list that fails does not stop the others: its row has status: "error" and an error message, and its previous version stays cached. opts.force: true re-indexes even unchanged lists. A failure that halts the run (a store write error, for example) still stops it; the schedule's retry policy covers those.

Meant for a daily schedule; see the README. The EU list needs http.max-response-bytes of at least 32 MiB.

Example

::sanctions::cache/refresh-lists()
::sanctions::cache/refresh-lists({sources: ["ofac-sdn", "un"]})

refresh-source

fn (source: Str): Map
fn (source: Str, opts: Map): Map

Refresh one list: check whether it changed, and if so download, parse, index and store the new version, then drop the old one. Returns {source, status, version, entries, ms} where status is "updated" or "unchanged". Errors (a download failure, an EU file over http.max-response-bytes) are returned as an Err and leave the cached version in place.

refresh-with

fn (source: Str, opts: Map, cfg: Map): Map

stale-warning

fn (m: Map, max-age-days: Int): Str?

status

fn (): Vec<Map>
fn (opts: Map): Vec<Map>

The cache status of every list: a Vec of metadata records, with {source, list, cached: false} for a list never refreshed.

Example

::sanctions::cache/status()

summarize

fn (source: Str, r: Result): Map

write-pairs

fn (store: Map, pairs: Vec): Int