Get and Disk Cache - dathere/qsv GitHub Wiki
Tier: Intermediate
Commands covered: get
Note
Per-command flag reference lives in /docs/help/get.md. This page is the workflow layer β when to reach for get, how the cache works, and how dc: lets every other command read cached data.
get fetches tabular data once from a local path, an HTTP(S) URL, a CKAN portal, or cloud object storage, and stores it in a managed, queryable disk cache. Once cached, the resource can be read by any qsv command via the dc: prefix β no re-download, no re-parse.
Think of it as the acquisition layer that sits in front of the rest of qsv: get owns "how do I get this file and keep it fresh?", and every other command just reads dc:<name>.
For each source, get:
- Stores the blob compressed (zstd by default) and content-addressed by BLAKE3 β identical content is stored once.
- Sniffs the delimiter of CSV/TSV ingests so the cached copy parses correctly even when the source uses a non-comma delimiter.
- Auto-builds a qsv index for the cached file, so downstream commands get instant random access and exact record counts.
-
Records rich metadata β
ETag,Last-Modified, compressed/uncompressed sizes, record count, and TTL. -
Revalidates instead of re-downloading. Re-fetches send a conditional request (
If-None-Match/If-Modified-Since); an unchanged resource returns304 Not Modifiedand the cached copy is kept. -
Streams large remote objects in parallel byte-ranges β tune with
QSV_GET_PART_SIZE(default 8 MiB) andQSV_GET_CONCURRENCY(default 4, clamped 1β64).
Note
get is behind the get feature flag (β¨). Of the prebuilt binaries, only qsvdp has it (Linux only): the prebuilt qsv, qsvpy*, qsvmcp and qsvlite are built without it, so qsv get and dc: inputs aren't available there (check with qsv --list). To use get in the full qsv, build from source with -F get (or -F distrib_features/-F all_features, which include it). Cloud sources (s3://, gs://, az://) additionally require the get_cloud sub-feature. See Binary Variants.
| If you want to⦠| Use |
|---|---|
| Cache a local file (compressed + indexed) for reuse | qsv get path/to/file.csv |
| Cache every matching file in one go | qsv get '/data/*.csv' |
| Peek at a remote file without caching it | qsv get https://β¦ --sample 10 |
| Fetch a URL once and reuse it across commands | qsv get https://β¦ --name data.csv |
| Pull a CKAN resource by id | qsv get "ckan://<resource-id>" --name ref.csv |
| Pull a CKAN resource by name (resource_search) | qsv get "ckan://<name>?" --name ref.csv |
Fetch from S3 / GCS / Azure (needs get_cloud) |
qsv get s3://bucket/key.csv --name data.csv |
| Read cached data from any command | qsv stats dc:data.csv |
| List / inspect / verify what's cached | qsv get cache-list [--verify] |
| Drop old entries | qsv get cache-prune --older-than=30d |
| Retune one entry's freshness |
qsv get cache-set-ttl / cache-set-policy
|
| Source | Example | Notes |
|---|---|---|
| Local file | qsv get data/sales.csv |
Compressed + indexed copy in the cache |
| Glob / directory | qsv get '/data/*.csv' |
Fetches every matching tabular file (.csv/.tsv/.tab/.ssv); each cached separately; --name is ignored |
| HTTP / HTTPS | qsv get https://example.com/data.csv |
Conditional revalidation, ranged parallel download |
| datHere lookup repo | qsv get dathere://us-states.csv |
The datHere qsv-lookup-tables repo |
| CKAN by id | qsv get "ckan://abc123β¦" |
Resource id on the configured CKAN portal |
| CKAN by name | qsv get "ckan://covid-vaccinations?" |
Trailing ? triggers resource_search
|
AWS S3 (get_cloud) |
qsv get s3://bucket/key.csv |
S3 / S3-compatible endpoints |
Google Cloud Storage (get_cloud) |
qsv get gs://bucket/key.csv |
|
Azure Blob Storage (get_cloud) |
qsv get az://container/key.csv |
sftp://is planned for a later release.
Cloud credentials are read from the standard AWS_* / AZURE_* / GOOGLE_* environment variables (and IAM roles). Use --cloud-opt key=value (repeatable) for one-off overrides such as region=us-east-1, a custom endpoint=β¦, or skip_signature=true for public buckets.
# Fetch a CSV into the cache, then read it with another command
qsv get https://example.com/data.csv --name data.csv
qsv stats dc:data.csv
# Seed a CKAN reference table by name
qsv get "ckan://covid-vaccinations?" --name vax.csv
# Cloud object storage (requires the get_cloud feature)
qsv get s3://my-bucket/data.csv --name data.csv
qsv get gs://my-bucket/data.csv --cloud-opt skip_signature=trueOnce a resource is cached under a logical name, any qsv command reads it by prefixing that name with dc::
qsv get https://example.com/big.csv --name big.csv
qsv stats dc:big.csv
qsv frequency dc:big.csv
qsv sqlp dc:big.csv "SELECT * FROM big WHERE amount > 100"- The logical name is set with
--name. If omitted, it defaults to the source's terminal path segment (e.g.big.csvfromβ¦/big.csv).--nameis ignored when multiple sources are given. - Reading a
dc:handle transparently decompresses the blob to a temp CSV with a sibling.idx. -
New in 24.0.0: a
frequency --frequency-jsonl dc:<name>cache is saved into the durable disk cache beside the stats cache and restored when the temp CSV is recreated, so the nextfrequency/vizrun on the samedc:dataset hits it instead of recomputing (#4641).get cache-prune/cache-clearreclaim it. Re-materializing adc:dataset also now streams the blob to disk rather than decoding it in memory first. -
Stale
dc:entries are auto-refreshed according to the entry's refresh policy (see below) β adc:read can trigger a conditional revalidation before handing the data to the command.
--sample N is a cheap peek at a single source β it streams just the first N data records (re-attaching the sniffed header row) to stdout or --output and caches nothing. No dc: entry is created. Because it stops reading early, a huge remote file is barely touched.
Note
This is not a statistical sample. For a random, representative subset use qsv sample instead.
| Option | Meaning |
|---|---|
--sample <n> |
Stream the first N records of a single source (no caching) |
--offset <mb> |
Skip ~<mb> megabytes (via an HTTP Range request) before sampling, realigning to the next record boundary. Implies --sample; needs a Range-capable source |
--random |
Reservoir-sample instead of reading the head. Streams and parses the full source from the start (so quoted multi-line records stay intact) β slower, but uniform |
# Peek at the first 10 rows of a remote CSV without caching it
qsv get https://example.com/big.csv --sample 10
# Skip ~500 MB, then peek 10 rows
qsv get https://example.com/big.csv --offset 500 --sample 10
# Uniform random preview of 20 rows
qsv get https://example.com/big.csv --sample 20 --randomA glob (e.g. data/*.csv) or directory source fetches every matching tabular file (.csv/.tsv/.tab/.ssv) in one call β each cached separately under its own dc: handle. Supported for local paths and, with the get_cloud feature, cloud buckets/prefixes. --name is ignored when a source expands to multiple files.
# Cache every CSV in a local directory
qsv get '/data/*.csv'
qsv get /data/
# Cache every matching object under an S3 prefix (requires get_cloud)
qsv get 's3://my-bucket/exports/*.csv'Each cache entry carries a TTL and a refresh policy that together decide what a dc: read does when the entry ages out:
| Option | Values | Default | Meaning |
|---|---|---|---|
--ttl <secs> |
seconds, or -1 to never expire |
2419200 (28 days) |
How long an entry is considered fresh |
--refresh <policy> |
on-stale, always, never
|
on-stale |
on-stale revalidates only past TTL; always revalidates every read; never serves the cached copy without checking |
--force |
β | off | Re-fetch immediately, even if a fresh copy exists |
--compress <algo> |
zstd, none
|
zstd |
Transparent blob compression |
As of 23.0.1, cache-list reports each entry's age and whether it is stale, so you can judge a cached response before reusing it rather than after.
"Stale" here means exactly one thing β will this entry re-fetch on its next dc: use? β and cache-list reads it from the same predicate the refresh path gates on, so the two can never disagree. An entry is due for refresh when its refresh policy is not never, its TTL is non-negative, and its age has reached that TTL. Note this is TTL-driven, not policy-driven: --refresh always does not make an entry due sooner, it only makes the eventual fetch unconditional.
Age is clamped at zero, because downloaded_at can legitimately sit in the future β a backward clock step from an NTP correction or a resumed VM, or metadata written by another machine when QSV_CACHE_DIR points at a shared mount. A future timestamp reads as "just fetched" rather than as a negative age.
Note
A failed refresh of a stale entry no longer falls back to the stale copy silently (23.0.1). Previously, if the network fetch that was meant to refresh a stale entry failed, qsv quietly served the old copy β so a pipeline could run for weeks on data it believed was fresh. The refresh path now warns when it falls back. For ckan:// entries there is an extra hint: the CKAN API URL is persisted on the entry but the token never is (it's read from QSV_CKAN_TOKEN at refresh time), so a private resource silently stops refreshing in any shell without that variable set.
Warning
The qsvmcp binary no longer ships get at all, no longer accepts dc: prefixed inputs, and no longer reads cloud (s3://, gs://, az://) sources.
qsvdp and source builds with the get/get_cloud features keep the full get command and cloud support. The prebuilt qsv has never included get (Binary Variants). Within qsvmcp, the http(s)://, dathere:// and ckan:// schemes are unaffected, and auto-decompression of compressed sources still works.
If you drive qsv through the MCP server and relied on dc: or an s3:// source, fetch the object with your own tooling (or a full qsv binary) and hand the MCP server a local path.
| Command | Purpose |
|---|---|
qsv get cache-list [--verify] |
List cached entries β including each entry's age and whether it is stale (new in 23.0.1). Add --verify to recompute each blob's BLAKE3 and report OK/FAIL β exits non-zero on any failure |
qsv get cache-info |
Summarize the cache (size, entry count) |
qsv get cache-clear |
Remove all cache entries |
qsv get cache-prune --older-than=<val> |
Remove entries older than an age β <val> is seconds or a value with an s/m/h/d/w suffix (e.g. 3600, 90m, 30d, 2w) |
qsv get cache-set-ttl <name> --ttl=<secs> |
Change one entry's TTL |
qsv get cache-set-policy <name> --refresh=<policy> |
Change one entry's refresh policy |
cache-list / cache-info accept --json for machine-readable output.
# Inspect, verify integrity, then prune
qsv get cache-list
qsv get cache-list --verify
qsv get cache-prune --older-than=30d
# Retune a single entry
qsv get cache-set-ttl data.csv --ttl=86400
qsv get cache-set-policy data.csv --refresh=never| Option | Default | Env override |
|---|---|---|
--ckan-api <url> |
https://data.dathere.com/api/3/action |
QSV_CKAN_API |
--ckan-token <token> |
β (only for private resources) | QSV_CKAN_TOKEN |
-
--sample <n>/--offset <mb>/--randomβ preview a single source without caching (see Sampling preview above). -
--timeout <secs>β request timeout (default60;0= no timeout). For cache downloads it's an inactivity timeout; for preview mode (--sample/--offset/--random) a total-request timeout. -
--cache-dir <dir>β cache directory (default~/.qsv-cache; overridesQSV_CACHE_DIR). -
-o, --output <file>β for a single source, also write the fetched (decompressed) data to<file>(use-for stdout). -
-q, --quietβ suppress progress/summary output on stderr.
| Variable | Effect | Default |
|---|---|---|
QSV_CACHE_DIR |
Cache directory | ~/.qsv-cache |
QSV_GET_PART_SIZE |
Byte-range part size for parallel downloads | 8 MiB |
QSV_GET_CONCURRENCY |
Parallel range-download workers (clamped 1β64) | 4 |
QSV_CKAN_API |
CKAN action API endpoint for ckan://
|
datHere portal |
QSV_CKAN_TOKEN |
CKAN access token (private resources) | β |
See Environment Variables for the full list.
These solve different problems:
-
getfetches one resource (a whole file) into a managed cache, so any command can read it viadc:. Acquisition + caching of datasets. -
fetch/fetchpostmake one HTTP call per row to enrich a CSV from an API, caching individual responses. Per-row enrichment.
Reach for get to pull a dataset once and reuse it; reach for fetch to hit an API for every row.
- Command Reference (index)
-
docs/help/get.mdβ canonical flag reference - HTTP & Web β fetch / fetchpost β per-row HTTP enrichment
- Stats Cache & Caching β the wider qsv caching story
- Recipe: CKAN Integration
- Environment Variables