MPI ingest and export ===================== Build with ``--features mpi`` against one MPI implementation (``MPICC=mpicc.mpich`` or ``mpicc.openmpi``). The library never calls ``MPI_Init`` and only uses the communicator you pass. .. _mpi-ingest: Ingest ------ .. code:: rust let counts = readcon_db::mpi_ingest::append_trajectory_paths(&world, "corpus", &files, 4096)?; let counts = readcon_db::mpi_ingest::append_trajectory_paths_sharded(&world, "root", 64, &files, 4096)?; The frames of all files, in order, are split into contiguous blocks. Each rank parses, hashes and derives index keys for its block. Ranks exchange only the 16-byte hashes first, so a repeated frame sends no blob. Records go to the env owner with ``MPI_Alltoallv`` (rank 0 for one corpus, rank ``shard % P`` for shards), which inserts them in global frame order. From C, C++ or Fortran use ``rkrdb_mpi_ingest_paths`` (an ``MPI_Comm``) or ``rkrdb_mpi_ingest_paths_f`` (an ``MPI_Fint``) from ``readcon-db-mpi.h``. .. _mpi-read-export: Read and export --------------- ``mpi_read::scatter_packed_frames`` sends each rank its block of a selection as one RCSO batch. ``mpi_read::export_extxyz_collective`` writes extended XYZ from every rank with ``MPI_File_write_at_all``, or through rank 0 with ``WriteMode::Gather``. LMDB map size ------------- Each writer rank grows its LMDB map to three times the CON bytes routed to it before the first batch, so large ingests do not stop with ``MDB_MAP_FULL``. A serial write that hits ``MDB_MAP_FULL`` aborts that transaction, grows the map to the larger of twice its size and the bytes already used plus the input, and retries. Serial callers can set ``READCON_DB_MAP_SIZE`` (for example ``8G``) or call ``ConCorpus::open_with_map_size`` and ``ConCorpus::reserve_map``. The default is 2 GiB, and reopening an existing corpus always maps at least twice its ``data.mdb``. The map is address space, so a large value costs no disk until pages are written. .. _mpi-determinism: Determinism ----------- LMDB page layout can differ between equal corpora, so the check is ``ConCorpus::canonical_dump`` (every table in key order). Its sha256 after an MPI ingest equals the serial ingest of the same files in the same order, for every rank count. Exported XYZ bytes equal the serial export. .. _mpi-benchmark: Benchmark --------- ``bench/mpi_bench.sh FRAMES ATOMS "1 2 4 8"`` writes a synthetic trajectory with ``bench/gen_con.py`` and prints the ingest wall time and the sha256 match for every rank count and mode.