Skip to content

FORM: make the read path thread-safe for multi-product form_source #1008

Open

Description

@coderabbitai

Summary

One form_source creates a provider per configured product. All providers share the same form_reader → persistence_reader → storage_reader. Each provider is concurrency::serial, which only serializes a provider against itself. Providers for different products can call the same storage_reader concurrently.

ROOT container reads are already guarded by root_tbranch_read_mutex and root_rfield_read_mutex. Those locks do not protect storage_reader's own state: files_, read_containers_, and index_maps_ can be looked up and inserted from several threads at once. This causes undefined behavior and can corrupt a map or crash the read.

This race predates #1007 and is independent of the cell-index lookup fix in #992. The old get_index() mutated index_maps_ through operator[] on every call. The new implementation reduces mutation to initial index-map construction but does not make the read path thread-safe.

Required changes

  • Audit shared mutable state across form_reader, persistence_reader, and storage_reader.
  • Protect lookup, initialization, and mutation of shared read-side state with a consistent synchronization strategy.
  • Cover all externally callable storage-reader operations that access shared state, including get_index, list_indices, prime, and read_container.
  • Ensure internal calls do not lock the same non-recursive mutex twice.
  • Preserve the existing ROOT read locks and check lock ordering to avoid deadlocks.

Affected areas

  • form/form_source.cpp: provider construction and shared-reader ownership.
  • form/persistence/persistence_reader.cpp and form/persistence/persistence_reader.hpp: shared persistence-reader state.
  • form/storage/storage_reader.cpp and form/storage/storage_reader.hpp: shared file, container, and index caches.
  • test/form: multi-product parallel read-back regression coverage.

Acceptance criteria

  • A regression test reads multiple products through one form_source with -j greater than 1.
  • The test checks each product's value against its expected cell and exercises initial cache construction as well as subsequent reads.
  • Shared read-side state remains protected when different product providers execute concurrently.
  • Existing cell-index lookup and read-back behavior remains correct.
  • Run the regression under a race detector where supported, and record the results.

References

Requested by @wwuoneway.

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

Metadata

Metadata

Assignees

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