State and storage¶
Each config has one storage path, data/<name> unless [storage].path says otherwise. It holds
the records and everything databrew needs to continue the crawl.
| Path | Holds |
|---|---|
items/, itemstore.json |
The versions |
observations/ |
The observations, as a store of their own |
.state.db |
The queue, the traversals, the failures, the last watched values, and each item's last fetch and HTTP validators |
.last_run.json |
The last run's report |
_failed_urls.json |
A readable export of the URLs with a failure on record, written when a run closes; absent when there are none |
.itemstore.db |
itemstore's catalog and journal |
The record files follow itemstore's
format. Databrew never reads
_failed_urls.json back; it exists for people and diffs.
Records and state belong together¶
The records say what was stored, and .state.db says what is left to do. Neither can be rebuilt
from the other, so back them up, restore them, and move them as one.
A run writes a version to the record store first and to .state.db second, and counts the versions
it has stored in .state.db with each one. That order decides what happens if a process dies
between the two writes:
- The records hold more versions than
.state.dbcounted. The nextrunorreactivateindexes the stored items again, then continues. This is also what happens after a checkout that adds record parts from another machine. Only the item index is rebuilt; the queue, the traversals, and the failures stay as they were. - The records hold fewer versions than
.state.dbcounted. Records are missing, so databrew refuses to open the crawl. Restore the records and.state.dbfrom the same snapshot.
Databrew never deletes, repairs, or migrates .state.db. A run, check, status, or
reactivate refuses a storage path whose .state.db is missing beside earlier records, is not a
readable database, or has a schema of another databrew version. The error says which.
Upgrading databrew
A release that changes the state schema cannot open storage paths written before it, and there is no migration; the changelog marks such releases as breaking. Keep an existing crawl on the version that wrote it, or start the new version at a new storage path.
One writer at a time¶
A storage path allows one writer. A second process that tries to run the same config fails that
config at once, with a line naming the path, and leaves the running crawl alone. To crawl two sites
at once, give each its own storage path; databrew run a.toml b.toml --parallel 2 runs them in one
process.
Reading while a crawl runs¶
Readers can open the part files at any time, because parts are only ever added. The newest records
may still sit in the journal in .itemstore.db until the run flushes them, at the latest when it
closes, so a reader sees them after the run ends. A crawl never compacts its stores. If you compact
them with itemstore's compact, do it while no reader and no crawl is using them, since compaction
rewrites parts in place.
Changing a config¶
A config's records stay tied to its storage path, so some edits start over and some rewrite history:
- Renaming the file changes the default
name, and with it the default storage path, so the next run begins a new crawl. Setname, or[storage].path, to keep the old one. - Adding, removing, or reshaping a field changes the extracted content of every item, so each item's next fetch stores a new version, whether or not the site changed.
- Changing the key splits each record's history: later observations and versions carry the new item key, and the earlier ones keep the old.
- Changing the start URLs while a traversal is paused fails until it completes or a
--rescanbegins a new one, as traversals describes.