Skip to content

RUM index insertion can spin at 100% CPU and ignore pending termination #184

Description

@brauliobo

Summary

Several PostgreSQL backends performing concurrent UPDATEs became stuck at 100% CPU while inserting into a RUM tsvector index. The backends did not respond to pg_terminate_backend(): it returned true, and debugger inspection showed both InterruptPending = 1 and ProcDiePending = 1, but the processes continued spinning.

Rebuilding the affected RUM indexes resolved the problem. The same write and indexed-search paths now complete in milliseconds under the original workload.

Environment

  • PostgreSQL 17.7
  • RUM package 1.3.15; extension version reports 1.3
  • Linux on ARM64
  • RUM operator class: rum_tsvector_ops

Generic schema/workload description

The affected table contains a tsvector maintained by a BEFORE INSERT OR UPDATE trigger. The trigger combines several ordinary text fields using the simple text-search configuration.

There were two RUM indexes on the same tsvector:

  1. A full-table RUM index.
  2. A partial RUM index restricted by two ordinary scalar-column predicates.

The workload performs concurrent updates to rows in this table. Even metadata-only updates cause the trigger to recompute the tsvector.

Observed behavior

  • Multiple concurrent UPDATE backends consumed approximately one CPU core each indefinitely.
  • Additional updates became blocked on the spinning transactions.
  • pg_stat_activity showed the spinning backends as active, with no wait event.
  • pg_terminate_backend(pid) returned true, but the backends did not exit.
  • Debugger inspection confirmed the termination signal was pending.
  • A concurrent REINDEX could not start its build because it was waiting for the spinning writer transactions.

The relevant portion of a representative stack was:

ResourceOwnerEnlarge
StartReadBuffer
ReadBufferExtended
<frames in rum.so>
ExecInsertIndexTuples

This indicates the loop was in the RUM insertion path rather than an index scan.

Recovery and validation

After the stuck transactions were cleared, both RUM indexes were rebuilt with REINDEX INDEX CONCURRENTLY.

The full index decreased from approximately 1.65 GiB to 1.06 GiB. Afterward:

  • Metadata-only updates completed normally.
  • Updates that changed indexed text completed normally.
  • A search using @@ and ordered using <=> selected the rebuilt full RUM index and completed in under 1 ms.
  • The equivalent query with the partial-index predicates selected the rebuilt partial RUM index and also completed in under 1 ms.
  • The original concurrent write workload has continued without stuck backends or lock chains.

Expected behavior

RUM insertion should complete or return an error. At minimum, a backend with ProcDiePending should reach an interrupt check and exit rather than spinning indefinitely.

Questions

  1. Is there a known write-side posting-tree/page-split corruption or infinite-loop issue in RUM 1.3.15 that matches this stack?
  2. Are there integrity checks that can detect this state before an update enters the loop?
  3. Would adding CHECK_FOR_INTERRUPTS() to the relevant insertion/page-tree loops be appropriate as a defensive measure?

We do not yet have a standalone reproducer. We can collect additional sanitized debugger stacks or index metadata if maintainers suggest specific commands.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions