Database schema¶
This page documents the PostgreSQL tables, indexes, triggers, and JSONB conventions used by zodb-pgjsonb. The schema version is 2.
Tables¶
transaction_log¶
Stores transaction metadata. Present in both history-free and history-preserving modes.
Column |
Type |
Default |
Constraints |
Description |
|---|---|---|---|---|
|
|
– |
|
Transaction ID (ZODB TID as 64-bit integer). |
|
|
|
– |
User who committed the transaction. |
|
|
|
– |
Transaction description text. |
|
|
|
– |
Serialized transaction extension metadata. |
object_state¶
Stores the current state of each object as JSONB. Present in both history-free and history-preserving modes.
Column |
Type |
Default |
Constraints |
Description |
|---|---|---|---|---|
|
|
– |
|
Object ID (ZODB OID as 64-bit integer). |
|
|
– |
|
Transaction ID of the current revision. |
|
|
– |
|
Python module path of the object class. |
|
|
– |
|
Python class name of the object. |
|
|
– |
– |
Object state as JSONB (see JSONB state structure). |
|
|
– |
|
Size of the original pickle in bytes. |
|
|
|
|
Array of OIDs this object references (used by the packer). |
State processors may add extra columns to this table via ALTER TABLE.
blob_state¶
Stores blob data with tiered PG/S3 support.
Present in both history-free and history-preserving modes.
The primary key (zoid, tid) retains all blob versions across transactions.
Column |
Type |
Default |
Constraints |
Description |
|---|---|---|---|---|
|
|
– |
|
Object ID. |
|
|
– |
|
Transaction ID. |
|
|
– |
|
Blob size in bytes. |
|
|
– |
– |
Blob data (populated for PG-stored blobs). |
|
|
– |
– |
S3 object key (populated for S3-stored blobs). |
A blob row has either data populated (PG-stored) or s3_key populated
(S3-stored), but not both.
object_history (history-preserving mode)¶
Stores previous revisions of objects.
Created only when history_preserving=True.
Column |
Type |
Default |
Constraints |
Description |
|---|---|---|---|---|
|
|
– |
|
Object ID. |
|
|
– |
|
Transaction ID of this revision. |
|
|
– |
|
Python module path of the object class. |
|
|
– |
|
Python class name. |
|
|
– |
– |
Object state as JSONB. |
|
|
– |
|
Size of the original pickle in bytes. |
|
|
|
|
Referenced OIDs. |
The storage uses a copy-before-overwrite model: the previous version of an
object is copied to object_history before object_state is updated.
The current version lives only in object_state.
pack_state (history-preserving mode)¶
Tracks pack state for history-preserving databases.
Created only when history_preserving=True.
Column |
Type |
Default |
Constraints |
Description |
|---|---|---|---|---|
|
|
– |
|
Object ID. |
|
|
– |
|
Transaction ID. |
Indexes¶
Core indexes (always present)¶
Index name |
Table |
Type |
Expression |
Purpose |
|---|---|---|---|---|
|
|
B-tree |
|
Class-based queries. |
|
|
GIN |
|
Reference graph traversal (pack). |
|
|
B-tree |
|
|
History indexes (history-preserving mode)¶
Index name |
Table |
Type |
Expression |
Purpose |
|---|---|---|---|---|
|
|
B-tree |
|
Transaction-based lookups. |
|
|
B-tree |
|
|
LISTEN/NOTIFY trigger¶
A trigger on transaction_log fires a PostgreSQL NOTIFY on every committed
transaction, sending the TID as the payload on the zodb_invalidations channel.
CREATE OR REPLACE FUNCTION notify_commit() RETURNS trigger AS $$
BEGIN
PERFORM pg_notify('zodb_invalidations', NEW.tid::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_notify_commit
AFTER INSERT ON transaction_log
FOR EACH ROW EXECUTE FUNCTION notify_commit();
JSONB state structure¶
Object state is stored as a JSONB document in the state column of object_state (and object_history).
The JSONB is produced by zodb-json-codec’s decode_zodb_record_for_pg_json() function, which converts ZODB pickle data to JSON.
The class information (class_mod, class_name) is stored in separate columns, not inside the JSONB.
The JSONB contains only the object’s instance state.
For the full list of JSON marker keys (@ref, @t, @b, @pkl, @dt, and others), see the zodb-json-codec JSON format reference.
The only marker specific to zodb-pgjsonb is @ns (null-byte sanitization).
PostgreSQL JSONB cannot store \u0000 characters, so strings containing null bytes are base64-encoded and wrapped in an @ns marker.
The storage sanitizes on write and unsanitizes on read automatically.
Schema installation¶
The install_schema() function in schema.py applies DDL idempotently.
It skips DDL when core tables already exist to avoid ACCESS EXCLUSIVE
locks that would block concurrent instances holding REPEATABLE READ
snapshots.
The installation sequence:
Check whether
transaction_logexists.If absent, execute the full history-free schema DDL (tables, indexes, trigger).
If present, ensure indexes added in later schema versions exist (lightweight
CREATE INDEX IF NOT EXISTS).If
history_preserving=Trueandobject_historydoes not exist, execute the history-preserving additions.Commit.
State processor DDL (from get_schema_sql()) is applied separately via
register_state_processor(), using a dedicated autocommit connection
with a 2-second lock_timeout.
If the lock cannot be acquired at startup,
the DDL is deferred to the first tpc_begin().