parquet_tables_parallel Submodule

Everything that makes a parquet_table safe to use from more than one thread: the table's own lock, the counters behind the append/read contract, and the shared refusal every structural mutation routes through.

This file exists so the #ifdef _OPENMP plumbing lives in exactly one place. Every other file in the table layer calls the plain procedures below and never sees a conditional or an omp_lib import. The two exceptions are unsafe_first_touch and record_open_thread, which stayed in parquet_tables_read.f90 next to the materialization path they guard; they implement the same ownership test unsafe_shared_mutation below uses, and the three must agree.

The concurrency model, in one paragraph. Reading an already-resident column is free: no lock, no bookkeeping, unlimited threads. It is not literally atomic-free -- every value accessor makes the one atomic read of append_active that table_check_no_append below performs -- but that single relaxed read is the whole cost, and it is the property everything here exists to protect. Any change that puts a lock, or a second atomic, on the resident read path is a design change rather than an optimisation. A first touch is refused on a shared table (unsafe_first_touch), because it publishes an allocation with no ordering guarantee behind it. A structural change is refused on a shared table (unsafe_shared_mutation). %append is the one mutation that is allowed concurrently, and it is allowed because this file serialises it -- so the caller never writes !$omp critical by hand and cannot wrap the wrong statement.

What the guards can and cannot see. They key on OpenMP thread identity, so a caller threading some other way (pthreads through C interop, coarrays) gets no enforcement at all, and a read through a %col pointer the caller already holds is invisible to the library the way every pointer dereference is. Both are documented limits, not gaps to close later; the %generation() counter is what a caller checks a pointer against.


Uses