Which Index Access Methods Are Supported by pgrust? B‑tree, Hash, GiST, and GIN
pgrust implements all four core PostgreSQL index access methods—B‑tree, Hash, GiST, and GIN—providing complete Rust-based equivalents to PostgreSQL's nbtree, hash, gist, and gin access methods.
The pgrust project reimplements PostgreSQL's storage engine in safe Rust, including full support for the standard index access methods defined by PostgreSQL's Access Method (AM) API. These implementations reside in dedicated crates under crates/backend/access/, offering memory-safe alternatives to PostgreSQL's C-based index handlers while maintaining compatibility with the IndexAmRoutine callback structure.
B‑tree Index Implementation
The B‑tree access method in pgrust lives in crates/backend/access/nbtree/nbtree_core/src/. This crate contains the complete B‑tree logic including page layout management, tree traversal, and node splitting.
Key source files include:
search.rs– Implements tree traversal and key lookup algorithmsinsert.rs– Handles tuple insertion and page split operations
The module exposes standard PostgreSQL B‑tree callbacks through IndexAmRoutine, allowing the planner to create indexes via CREATE INDEX and execute scans using nbtree_core::insert::btree_insert.
Hash Index Support
Hash indexes are implemented in crates/backend/access/hashfunc/src/lib.rs with validation routines in crates/backend/access/hashvalidate/src/lib.rs. This implementation provides bucket-based hash indexing with collision handling and consistency verification.
The hash function library computes bucket locations for heap TIDs, while hashvalidate ensures index consistency during operations. When executing CREATE INDEX ... USING HASH, pgrust routes calls through hashfunc::hash_insert to store entries in hash bucket pages.
GiST (Generalized Search Tree) Access Method
pgrust implements GiST functionality in crates/backend/access/spgist/spgist_core/src/. This crate provides the generic index infrastructure required for extensible data types, including scan operations and handler routines.
Important files include:
spgscan.rs– GiST scan implementationspgproc.rs– Procedural handlers for GiST operations
The GiST module supports extensible operator classes such as ltree_gist_ops (demonstrated in crates/contrib/ltree/src/lib.rs), enabling spatial and custom data type indexing through the generic tree structure.
GIN (Generalized Inverted Index) Implementation
The GIN access method resides in crates/backend/access/gin/ginutil/src/lib.rs, providing utility routines for inverted index operations. GIN supports complex data types like arrays and full-text search documents through postings lists.
Concrete operator class implementations demonstrate GIN integration:
crates/contrib/pg_trgm/src/lib.rs– Trigram matching with GIN opclass wiringcrates/contrib/hstore/src/lib.rs– Key-value GIN indexing
The generic GIN dispatcher routes opclass requests through ginutil, calling specific functions like gin_consistent and gin_extract_value during index maintenance and scanning.
Practical Usage Examples
When creating indexes in pgrust, the planner selects the appropriate access method OID and routes to the corresponding Rust implementation.
Creating a B‑tree Index
CREATE INDEX ON my_table (col1);
// The planner resolves `col1`’s OID, chooses the B‑tree AM (OID = BTREE_AM_OID),
// and builds an IndexInfo that is later passed to pgrust’s B‑tree inserter.
// Internally the B‑tree code in `nbtree_core` creates the root page and
// calls `nbtree_core::insert::btree_insert` for each tuple.
Creating a GIN Index on tsvector
CREATE INDEX ON docs USING GIN (content);
// The planner selects the GIN access method (OID = GIN_AM_OID).
// pgrust routes the opclass `gin_tsvector_ops` through the generic GIN
// dispatcher (`crate::gin::extproc`) which ends up in `ginutil` and then
// calls the opclass’s `gin_consistent` / `gin_extract_value` functions.
Creating a GiST Index on ltree
CREATE INDEX ON paths USING GiST (path);
// The GiST AM handler lives in `spgist_core`. The planner builds a
// GiST `IndexInfo`, and the execution engine invokes `spgist_core::spg_insert`
// for each entry, using the ltree-specific GiST opclass (`ltree_gist_ops`).
Creating a Hash Index
CREATE INDEX ON users USING HASH (email);
// The Hash AM is implemented in `hashfunc`. During index creation the
// planner calls `hashfunc::hash_insert` for each row, which computes the
// hash and stores the heap TID in a hash bucket page.
Key Source Files and Architecture
| Access Method | Primary Crate | Key Files |
|---|---|---|
| B‑tree | nbtree_core |
crates/backend/access/nbtree/nbtree_core/src/lib.rs (entry point), search.rs, insert.rs |
| Hash | hashfunc |
crates/backend/access/hashfunc/src/lib.rs, crates/backend/access/hashvalidate/src/lib.rs |
| GiST | spgist_core |
crates/backend/access/spgist/spgist_core/src/lib.rs, spgscan.rs, spgproc.rs |
| GIN | ginutil |
crates/backend/access/gin/ginutil/src/lib.rs |
| Catalog | syscache_seams |
crates/backend/utils/cache/syscache_seams/src/lib.rs (AM OID lookups) |
| Opclass Examples | pg_trgm, hstore, ltree |
crates/contrib/pg_trgm/src/lib.rs, crates/contrib/hstore/src/lib.rs, crates/contrib/ltree/src/lib.rs |
Summary
- pgrust provides Rust implementations for all four standard PostgreSQL index access methods: B‑tree, Hash, GiST, and GIN.
- Each method resides in a dedicated crate under
crates/backend/access/, exposingIndexAmRoutinecallbacks compatible with PostgreSQL's planner and executor. - B‑tree logic handles page splits and searches in
nbtree_core/src/search.rsandinsert.rs. - Hash indexes use bucket-based storage via
hashfuncandhashvalidatecrates. - GiST generic tree structures are implemented in
spgist_corewith support for custom operator classes. - GIN inverted indexes utilize
ginutilwith concrete examples inpg_trgmandhstorecontrib modules.
Frequently Asked Questions
Does pgrust support all standard PostgreSQL index types?
Yes, pgrust implements the four core index access methods defined by PostgreSQL: B‑tree, Hash, GiST, and GIN. These implementations provide the same IndexAmRoutine callbacks that PostgreSQL's planner expects, enabling transparent use with standard SQL CREATE INDEX commands.
How does pgrust handle B‑tree page splits?
The B‑tree implementation in crates/backend/access/nbtree/nbtree_core/src/insert.rs manages page splits during tuple insertion. When a page exceeds capacity, the code allocates new pages and redistributes entries according to B‑tree balancing algorithms, maintaining the tree structure through the btree_insert function.
What is the difference between GiST and GIN in pgrust's implementation?
GiST (Generalized Search Tree) in spgist_core provides a balanced tree structure framework suitable for geometric and custom data types with arbitrary splitting strategies. GIN (Generalized Inverted Index) in ginutil implements inverted indexes optimized for composite values containing multiple keys, such as arrays or full-text documents, with separate posting lists for each key.
Where are the catalog lookups for index access methods handled?
Index access method metadata and OID lookups are managed by the system cache layer in crates/backend/utils/cache/syscache_seams/src/lib.rs. This module translates PostgreSQL catalog entries for amopmethod into the Rust structures used by pgrust's planner to select the appropriate index handler.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →