1# Chapter 5: postjevsql-pg, where the unsafe lives 2 3Postgres is an old, careful C program with house rules, and an extension 4lives in its house. Some of the rules are unusual if you come from web 5servers: 6 7- **One process per connection, one thread per process.** Your session has a 8 backend process all to itself, and every Postgres function assumes it is 9 being called from that process's one thread. Call one from anywhere else 10 and you corrupt the backend. 11- **Errors do not return; they jump.** `ereport(ERROR)` `longjmp`s straight 12 back to the top of the query, past every stack frame in between. Rust 13 frames that own something with a `Drop` would never run it. 14- **Cancel is a flag and a latch.** Ctrl-C does not kill anything: a signal 15 handler sets a latch, and the backend notices at its next 16 `CHECK_FOR_INTERRUPTS()`. Code that sleeps somewhere Postgres cannot see 17 never notices, and the query cannot be cancelled. 18- **Memory belongs to contexts**, which are freed wholesale when a query 19 ends, so nothing in them is ever dropped one by one. 20 21This crate is where all of that is met. It is the one crate allowed `unsafe`, 22and its job is to export safe types so that no other crate needs any: an 23executor whose only way to wait is Postgres's own, an HTTP/2 client that 24runs on it, and the plan node that judges rows (chapter 7). 25 26```mermaid 27flowchart TD 28 ext["postjevsql (safe code only)"] --> scan["scan/: the plan node, behind the Judge trait"] 29 ext --> https["https.rs: HttpsTransport, Backend"] 30 scan --> exec["executor.rs: one thread, waits on a WaitEventSet"] 31 https --> net["net.rs: non-blocking TCP, hyper's I/O"] 32 https --> dns["dns.rs: hickory on the executor"] 33 https --> rl["ratelimit.rs: the cluster's limit, in shared memory"] 34 net --> exec 35 dns --> exec 36 rl --> exec 37``` 38 39> **Aside: why not tokio?** Everyone's first idea, and wrong twice here. 40> Tokio's usual runtime runs futures on worker threads, where a Postgres call 41> corrupts the backend. Its single-threaded runtime is safer, but it sleeps in 42> its own `epoll`, which never sees Postgres's latch, so a cancel would wait 43> for the request to finish. Running tokio in 10 ms slices with interrupt 44> checks between them is polling, and burns CPU to add latency. So the 45> executor here waits on exactly what Postgres waits on, and a cancel lands 46> in the same wait as the network does. 47 48> **Try it.** In `psql`, start a statement that judges many rows and press 49> Ctrl-C. It stops at once, mid-request, and the HTTP/2 streams it had open 50> are reset at the server. `tests/cancel.rs` proves that at the mock, through 51> both `pg_cancel_backend` and a client-side cancel. 52 53## For the people who maintain it 54 55| Path | What | 56| --- | --- | 57| [src/](src/) | The executor, the network stack, the rate limiter, the row's JSON, and the scan. Chapter 6. | 58| [BUCK](BUCK) | The library, built with `pg_major = True`: `ffi.rs` and `plan.rs` differ between PG17 and PG18 by the `pgNN` feature. | 59| [Cargo.toml](Cargo.toml) | Generated by `tools/cargo-gen` (chapter 20). | 60 61The traps each of these closes, and the evidence for each choice, are the 62root `CLAUDE.md`'s *Implementation* §1 and §2. 63 64← Previous: [Chapter 4, src/bin/](../postjevsql/src/bin/) · Up: [crates](../) · Next: [Chapter 6, postjevsql-pg/src/](src/) →