Ankusa.Storage.Layout (ankusa v0.7.0)

Copy Markdown View Source

Where archive objects live in the object store.

A segment written by this release is

<storage.key_prefix>archive/v1/dt=<yyyy-mm-dd>/<node>/seg-<first_seq>-<last_seq>.seg
<storage.key_prefix>archive/v1/dt=<yyyy-mm-dd>/<node>/seg-<first_seq>-<last_seq>.idx
<storage.key_prefix>archive/v1/dt=<yyyy-mm-dd>/<node>/_manifest.json

dt is the UTC day of the segment's oldest hook (the hook id is a UUIDv7, so its time is in the id; a segment of ids that carry no time goes under the day it was written), <node> is intake.node_id or, without one, the host name, and the seqs are zero-padded to 20 digits. The day comes before the node so a node that has lost its catalogue can list one day's prefix and find every node's segments for it (Queue.Archive.reconcile/2, the Ankusa.Storage.fetch/2 fallback) instead of needing the catalogue to say where to look.

_manifest.json is a constant-size summary of one node's day: how many segments, their seq and id range and total bytes. It is rewritten after each segment and lets a reader skip a node whose ids cannot hold the one it wants.

Segments an earlier release wrote, seg/<first>-<last>.seg (and .idx) under the prefix, are still found by the catalogue and by reconcile.

Summary

Functions

The manifest with one more segment (a catalogue row) counted in.

The UTC day (yyyy-mm-dd) of an event id's time; today when the id carries none.

The prefix of one day's objects, every node's.

The days a fetch looks in for an id: its own and the day before; :error for an id with no time.

Decode a manifest object; {:error, :bad_manifest} for anything that is not one.

The full key of the manifest beside the dated segment seg_key.

Object name (no prefix) of the day manifest of node on dt.

An empty manifest for node on dt.

The name this node writes under: intake.node_id, else the host name, as a safe path part.

Parse a listed key: a dated segment, a legacy one, or nil for anything else.

The prefix every dated object is under (before storage.key_prefix).

Object name (no prefix, no extension) of the segment first..last of node on dt.

Types

parsed()

@type parsed() :: %{
  kind: :dated | :legacy,
  key: String.t(),
  idx_key: String.t(),
  first: pos_integer(),
  last: pos_integer(),
  dt: String.t() | nil,
  node: String.t() | nil
}

Functions

add_segment(manifest, row)

@spec add_segment(map(), map()) :: map()

The manifest with one more segment (a catalogue row) counted in.

day(id, now_ms \\ System.system_time(:millisecond))

@spec day(String.t(), integer()) :: String.t()

The UTC day (yyyy-mm-dd) of an event id's time; today when the id carries none.

day_prefix(dt)

@spec day_prefix(String.t()) :: String.t()

The prefix of one day's objects, every node's.

days_for(id)

@spec days_for(String.t()) :: [String.t()] | :error

The days a fetch looks in for an id: its own and the day before; :error for an id with no time.

decode_manifest(bin)

@spec decode_manifest(binary()) :: {:ok, map()} | {:error, :bad_manifest}

Decode a manifest object; {:error, :bad_manifest} for anything that is not one.

manifest_key(seg_key)

@spec manifest_key(String.t()) :: String.t()

The full key of the manifest beside the dated segment seg_key.

manifest_name(dt, node)

@spec manifest_name(String.t(), String.t()) :: String.t()

Object name (no prefix) of the day manifest of node on dt.

new_manifest(dt, node)

@spec new_manifest(String.t(), String.t()) :: map()

An empty manifest for node on dt.

node_name(config)

@spec node_name(Ankusa.Config.t()) :: String.t()

The name this node writes under: intake.node_id, else the host name, as a safe path part.

parse(key)

@spec parse(String.t()) :: parsed() | nil

Parse a listed key: a dated segment, a legacy one, or nil for anything else.

root()

@spec root() :: String.t()

The prefix every dated object is under (before storage.key_prefix).

segment_name(dt, node, first, last)

@spec segment_name(String.t(), String.t(), pos_integer(), pos_integer()) :: String.t()

Object name (no prefix, no extension) of the segment first..last of node on dt.