1# Chapter 3: postjevsql/src, the judge 2 3Two files, and one of them is long. `lib.rs` is about two thousand lines, 4but it reads well from top to bottom once you know that it has exactly one 5job: it is the `Judge` the scan (chapter 7) calls. The scan hands it one 6row's calls at a time and gets back one answer per call. Everything between 7those two moments is here. 8 9Follow one call, `jev_prob(t, 'Urgent?')` on one row: 10 11```mermaid 12flowchart TD 13 C["a call, with the row as canonical JSON"] --> K["its cache key: the hash of the exact bytes it would send"] 14 K --> S{"an equal call already asked in this statement?"} 15 S -->|yes| W["wait on that one's answer (dedupe_hits)"] 16 S -->|no| L{"in jev_cache?"} 17 L -->|yes| H["the kept answer, for nothing"] 18 L -->|no| B{"within jev.max_rows and jev.max_cost?"} 19 B -->|no| R["refuse: 54000"] 20 B -->|yes| Q["one request: the row as the state, each distinct question about it once"] 21 Q --> J["jev-client: send, retry, classify"] 22 J --> A["the answer, checked against the pinned model"] 23 A --> St["settle: stored in jev_cache, on the backend"] 24``` 25 26The last box is the subtle one. A judgment runs as a future on the 27backend's executor (chapter 6), polled from inside the executor's wait in 28the middle of the scan's own work, and the `Judge` contract says plainly 29that such a future must not call Postgres. So answers pile up as *receipts*, and the scan 30calls `settle` between waits, on the backend proper, which writes them to 31`jev_cache` with ordinary SQL. 32 33> **Aside.** The same trick, run backwards, is how a label-tree search works. 34> It takes several rounds, and each round's Choices should be looked up in 35> the cache before anything is sent. But the cache is SQL, and the search is 36> a future. So the future hands a closure to the backend 37> (`scan::on_backend`), the scan runs it between waits, and the future 38> resumes with the result. A future asking a database for a favour, and 39> waiting politely for it. 40 41## lib.rs, in the order it is written 42 431. **The settings.** `_PG_init` registers every `jev.*` GUC, with who may 44 set it and why, then registers the scan (`scan::register::<JevScan>()`). 45 `PinnedModel` refuses an alias when `jev.model` is set. 462. **The SQL around the functions.** Three `extension_sql!` blocks: the 47 `jev_cache` table, the five result types (`jev_noul_result`, 48 `jev_score_result`, `jev_choice_result`, `jev_tree_result`, 49 `jev_shortlist_result`), and the `REVOKE … FROM PUBLIC` of every function. 503. **The functions.** One `#[pg_extern]` each, all `volatile`, 51 `parallel_restricted` and planned with `jev_support`, all with a body that 52 refuses (chapter 2 says why). Then `jev_support`, the planner support 53 function that prices them, and `jev_stats`. 544. **`JevScan`**, the `Judge`. `begin` reads the settings once per statement 55 (a prepared plan outlives a `SET`) and builds the client; `afford` refuses 56 a statement whose estimate is over budget; `explain` is what EXPLAIN 57 shows; `window` is `jev.concurrency` clamped to the server's stream limit; 58 `judge` answers one row; `settle` stores what was answered. 595. **Sharing.** `Asking` and `Shared` are the statement's registry of 60 judgments in flight, so an equal call waits instead of sending. `Owed` 61 unregisters a key whose request was dropped, so its waiters ask again 62 themselves. `Budget` and `Committed` hold each request's worst case 63 against the spend guards until its real `usage` replaces it. 646. **The searches.** `TreeCall` drives `postjevsql-core`'s label-tree search 65 for `jev_choice_tree`, and `ShortlistCall` its chunk-and-shortlist search 66 for `jev_choice_shortlist`, a round at a time, each round looked up through 67 `on_backend`. `tree_out` turns a search's outcome into the SQL result. 687. **Asking.** `Lookup` finds calls in the cache; `Judged` is a judgment's 69 answer and how each function reads it; `Sender` sends the misses within 70 the budget, serves their waiters and queues their receipts. 718. **Odds and ends.** `api_key` (exactly one source, never both), 72 `learned_ratio` (characters per token, learned from `jev_cache` for the 73 pinned model), and `setting`. 74 75> **Try it.** `cargo test -p postjevsql-core` exercises the planner, key and 76> searches this file drives. The judge itself needs a running Postgres, so its 77> tests are the integration tests: `nix develop -c buck2 test //tests:cache` 78> runs the cache's. 79 80## For the people who maintain it 81 82| Path | What | 83| --- | --- | 84| [lib.rs](lib.rs) | Settings, the SQL objects, the functions, and `JevScan`: begin, afford, explain, judge, settle; sharing, budgets, the searches, the sender. | 85| [failure.rs](failure.rs) | `Failure`: every way a call fails, the one place each becomes an ERROR with its SQLSTATE and DETAIL, and `is_failed_judgment`, which decides what `jev.on_error = unsure` may turn into NULL. | 86| [bin/](bin/) | The schema binary cargo-pgrx runs. Chapter 4. | 87 88← Previous: [Chapter 2, postjevsql/](../) · Up: [postjevsql](../) · Next: [Chapter 4, src/bin/](bin/) →