Repository navigation
Commit 0e30566
Fix stale TID errors in VLE path materialization (#2551)
Four problems with the TID-based VLE cache and its version counters, all from
798917c ("VLE cache + performance improvements").
1. A path bound by MATCH could not be projected once the same statement deleted
its endpoints (#2549):
MATCH p = (n0)<-[:R*..2]-(n1) DETACH DELETE n0, n1 RETURN p
ERROR: get_vertex_entry_properties: stale TID - ...
That commit replaced the properties Datum in vertex_entry and edge_entry
with a TID fetched lazily at projection. cypher_delete() advances
es_snapshot->curcid past every delete, so a path's own endpoints fail the
visibility test by the time they are read; before, properties were captured
at cache build and a later delete could not affect them.
Such a tuple is still physically present, the deleting transaction having
not committed, so it is read anyway and the path reports the properties it
was matched with. The relaxation is narrow: only a tuple deleted by our own
transaction qualifies, and only while the row still carries the cached
entity, so a recycled line pointer cannot be substituted. Any other
unreachable TID still raises the error, keeping a real invalidation bug
visible. Properties are detoasted under the buffer pin, and the buffer is
now released on the failing path too, since heap_fetch is called with
keep_buf, which leaves it pinned when only visibility fails.
2. VACUUM FULL and CLUSTER rewrite the heap, moving every cached TID, and
announce themselves through no trigger and no version counter. A cached
context then resolved stale TIDs against the new file, giving the stale TID
error or "could not read block", which never reaches AGE's guard.
Both are now intercepted in ag_ProcessUtility_hook as TRUNCATE already was,
and the database-wide forms invalidate every tracked graph. Plain VACUUM and
ANALYZE do not move tuples and are ignored.
3. NULL properties were reported as a stale TID. Label tables are created with
properties NOT NULL, so a NULL means the table was altered out from under
AGE; that is now said plainly rather than blamed on the cache.
4. Version counter slots were never released, making the table a tally of every
graph ever mutated rather than of those that exist. A server cycling graphs
filled it, then warned on every mutation and fell back to snapshot
invalidation. drop_graph() now releases its slot and a freed slot is reused;
a new occupant seeds its version above every value the table has issued, so
a context cached for the previous occupant cannot compare equal. The cap
moves 128 -> 256, about 4 KB of shared memory at 16 bytes per entry; lookups
scan only the entries in use, so unused slots cost nothing.
Both accessors now share one helper, and hardcoded column numbers give way to
the Anum_ag_label_* constants.
cypher_vle gains 14 cases: the reported query, a fan-out that fails
if the result depends on which row is projected first, partial and edge-only
deletes, the edge-list projection, an edge property constraint reaching the
accessor during traversal, zero-length bounds, self-loops, labelled vertices, a
multi-hop chain, a delete from an earlier statement that must not be
resurrected, savepoint and transaction rollback, and out-of-line TOAST asserted
set-identical to a live read.
age_global_graph covers CLUSTER and all three VACUUM FULL spellings (named,
parenthesised, database-wide), plus plain VACUUM, ANALYZE and FULL false which
must not invalidate; NULL properties on a vertex and an edge; 260
create/drop cycles that must stay silent; a rolled-back drop; and a graph
recreated under a dropped name.
Verified on PostgreSQL 18.4 and 18.6: clean build, no warnings; installcheck
43/43 on 18.4 before and after, run twice; and 43/43 on 18.6 with
--enable-cassert, reporting no assertion failure or resource leak.
Fixes #2549
modified: regress/expected/age_global_graph.out
modified: regress/expected/cypher_vle.out
modified: regress/sql/age_global_graph.sql
modified: regress/sql/cypher_vle.sql
modified: src/backend/catalog/ag_catalog.c
modified: src/backend/commands/graph_commands.c
modified: src/backend/utils/adt/age_global_graph.c
modified: src/include/utils/age_global_graph.h
Co-authored-by: GitHub Copilot (Claude Opus 5) <noreply@github.com>1 parent 4d9b250 commit 0e30566
8 files changed
Lines changed: 1877 additions & 64 deletions
File tree
- regress
- expected
- sql
- src
- backend
- catalog
- commands
- utils/adt
- include/utils
Large diffs are not rendered by default.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
354 | 354 | | |
355 | 355 | | |
356 | 356 | | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
357 | 588 | | |
358 | 589 | | |
359 | 590 | | |
| |||
0 commit comments