-
Notifications
You must be signed in to change notification settings - Fork 14
Signature Database
This document was generated from 'src/documentation/wiki-signature-database.ts' on 2026-07-15, 09:42:41 UTC presenting an overview of flowR's bundled signature database that resolves library() calls (v2.12.0, using R v4.6.0). Please do not edit this file/wiki page directly.
flowR ships a database of the complete history of all exports in every version of all CRAN packages so it can resolve calls into the packages you load.
After library(ggplot2), a call to ggplot() resolves to ggplot2::ggplot. The same database
qualifies bare names and backs various components like the dependencies and call-context queries
as well as the undefined symbol rule.
The exports come from versions:sigdb, which reads bundled databases. It is enabled by
default (see configuring flowR).
Which version's exports get resolved is decided by the version-reading plugins that pin the packages a project uses.
function usePackageDatabase(parser: KnownParser) {
const sigdb = new FlowrAnalyzerPackageVersionsSigDbPlugin('/path/to/sigs.manifest.json.br');
return new FlowrAnalyzerBuilder().setParser(parser).registerPlugins(sigdb).build();
}Defined at src/documentation/wiki-signature-database.ts#L20
File sources load lazily on the first package load, so a script with no library() or use() calls
never pays to parse them. Set solver.sigdb.eagerlyLoad to mount the database up front instead, or
solver.sigdb.enabled to false to switch it off entirely. For a compressed (.br) or manifest source,
preload it before analysis to mount it.
The base-R packages (base, stats, graphics, ...) resolve against an assumed R version, which
defaults to 4.5.3 (solver.sigdb.assumedRVersion, or "auto" to detect the local R).
So library(stats) attaches that release's exports, and a bare sd() qualifies to stats::sd even
without attaching the base namespaces to the graph. Set solver.sigdb.linkBaseR to also link them as
dataflow edges.
No signature shards are committed: the base.* floor (self-contained base-R signatures, a few hundred KB), the
current.* scope (every package's latest version) and history.* (every older version) all live as assets on the
free solver.sigdb.downloadRepo GitHub release. The only committed file is a tiny link file,
src/data/sigdb/sigdb.remote.json, which records the release tag and each shard's sha256 and size, so
:signature download builds the direct release-CDN URL (no API rate limit), verifies every shard by content hash,
and skips any already cached. Because the link file is versioned, a git pull that updates it re-syncs only the
shards whose hash changed — and with solver.sigdb.autoSync that check runs on startup and re-downloads in the
background; npm run build bakes the shards in as well. The richest downloaded scope is used (order full >
current > base), so once fetched library(stats) resolves. Any path in solver.sigdb.additionalPaths (or
$FLOWR_SIGDB_DIR) is searched alongside the default, so a downloaded bundle stays mounted on every start.
The default bundle is not a single file but a set of shards that a manifest routes between (see
SigDatabaseSet). Nothing is read when the manifest opens. The first lookup of a package
decompresses only the one shard that holds it, plus the shared dictionary once. The following ship with this
build; the load column is the decompression time measured at generation time.
| Shard | Contents | Versions kept | Packages | Versions | Size (.br) |
Load (first touch) |
|---|---|---|---|---|---|---|
base-current |
base-R packages (base, stats, graphics, ...) |
latest only | 23 | 23 | 95 KB | ≈ 2 ms |
base-full |
base-R packages (base, stats, graphics, ...) |
full history | 23 | 1,626 | 418 KB | ≈ 6 ms |
current-top |
the 1,000 most-downloaded CRAN packages | latest only | 1,000 | 1,000 | 1.9 MB | ≈ 31 ms |
current-rest |
the remaining CRAN packages | latest only | 22,742 | 22,742 | 14.0 MB | ≈ 520 ms |
history-rest |
the remaining CRAN packages | full history | 18,466 | 140,128 | 27.6 MB | ≈ 1000 ms |
current.dict |
1,394,438 shared strings | - | - | - | 6.2 MB | ≈ 180 ms |
base.dict |
10,866 shared strings | - | - | - | 48 KB | ≈ 1 ms |
history.dict |
1,402,879 shared strings | - | - | - | 6.5 MB | ≈ 190 ms |
Which shard answers a lookup follows from the package and the version asked for. A base-R package comes from
base-current, one of the 1,000 most-downloaded CRAN packages from current-top, and anything else from
current-rest. The *-full and history-* shards hold every historical version and are only touched when
an older, pinned version is requested, so a normal analysis never decompresses them. Each scope carries its own
shared dictionary that its shards depend on, so it is decompressed the first time any of its packages is looked up and then reused.
The flowR Docker images ship this dictionary already decompressed, so a container reads it in place and skips
that step (the load column above is the cost a plain npm install pays).
Every shard, dictionary, and manifest is published in both brotli (.br) and zstd (.zst, faster to decompress) compression, and flowR uses whichever the runtime supports: .zst when the Node version exposes zstd (Node ≥ 22.15), otherwise .br. :signature download fetches only that one variant per file, and :version reports the format each loaded database resolved to.
The on-disk format is flowr-sigdb (schema 4). Beyond each version's exports it records, per
version, every function's signature (parameters, whether each is forced or optional, and its default) and
call graph, together with that version's declared dependencies (Depends, Imports, ... with their
version qualifiers). The layout is NDJSON: a header, then a shared string dictionary, then one
self-contained blob per package, next to a sidecar .idx. A reader (SigDatabase) therefore
loads the dictionary once and then seeks straight to the packages it needs, never reading the rest.
The bundle is written by SigDbBuilder and can be split into several small shards (current-only
versus full history, top-N versus the rest) that a flowr-sigdb-manifest routes transparently
(SigDatabaseSet), and which information gets stored is selectable (SigDbFeatures).
crawlr produces the bundle from its analysis of CRAN.
The dictionary is read once, the reader then seeks straight to each requested package, and consumers cache
what they derive (the base-package list is precomputed when flowR is bundled, so it costs nothing at
analysis time). After the one-time load a per-package lookup is O(1), so each library() or :: a script uses is a single cached lookup.
Currently maintained by Florian Sihler and Oliver Gerstl at Ulm University
Email | GitHub | Penguins | Portfolio
- 🧑💻 Developer Onboarding
- 💻 Setup
- 👓 Overview
- 🪟 Interfacing with flowR
- 🌋 Core
- 🧹 Testing & Linting (Benchmark Page)
⁉️ FAQ- ℹ️ Extra Information