Search code examples
file-iooperating-systemfilesystemsmpihpc

How to replace an existing file in MPI with MPI_File_open


I am reading "Using MPI-2" and try to execute the code myself. I specified MPI_MODE_CREATE for MPI_File_open, but it actually does not create a new file, instead, it overwrites the previous file with the same name. I happen to find this out when first running with more processes, and then with fewer processes. My MPI version is openmpi 1.8.1.

Here is the code

#include <stdio.h>
#include <mpi.h>
#define BUFSIZE 4
int main(int argc, char **argv)
{
    int map[BUFSIZE], i, rank , size;
    char buf[BUFSIZE];
    MPI_File fh;
    MPI_Datatype filetype;
    MPI_Status status;
    MPI_Offset disp=0;

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    for(i=0;i<BUFSIZE;i++)
    {
//      buf[i]=size*i+rank+'0';
        buf[i]=size*i+rank+'A';
        map[i]=size*i+rank;
    }
    MPI_File_open(MPI_COMM_WORLD, "datafile4", MPI_MODE_CREATE|MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
    MPI_Type_create_indexed_block(BUFSIZE, 1, map, MPI_CHAR, &filetype);
    MPI_Type_commit(&filetype);
    MPI_File_set_view(fh, disp, MPI_CHAR, filetype, "native", MPI_INFO_NULL);
    MPI_File_write_all(fh, buf, BUFSIZE, MPI_CHAR, &status);
    MPI_File_close(&fh);
    MPI_Type_free(&filetype);
    MPI_Finalize();
    return 0;
}

Here is the file content when I run with 6 processes

ABCDEFGHIJKLMNOPQRSTUVWX

Then I modified it a little bit. Substitute

buf[i]=size*i+rank+'A';

with

buf[i]=size*i+rank+'0';

and run with 2 processes, the file is as follows

01234567IJKLMNOPQRSTUVWX

Solution

  • This is correct behaviour - MPI_MODE_CREATE "creates the file if it does not exist", and has no effect if it does; as the documentation says, exactly like the corresponding POSIX O_CREAT.

    For whatever reason, there isn't an MPI_MODE_* equivalent to O_TRUNC which would clobber the file if it already exists; for that you'd have to open with MPI_MODE_CREATE|MPI_MODE_EXCL, check to see if the open fails, and if so, delete the file and repeat (or maybe open it with MPI_MODE_DELETE_ON_CLOSE, close it, and then re-open it)

    Coding it up both ways:

    #include <stdio.h>
    #include <mpi.h>
    #define BUFSIZE 4
    int main(int argc, char **argv)
    {
        int map[BUFSIZE], i, rank , size;
        char buf[BUFSIZE];
        MPI_File fh;
        MPI_Datatype filetype;
        MPI_Status status;
        MPI_Offset disp=0;
    
        if (argc != 3) {
            fprintf(stderr,"Usage: %s letters|numbers test|delete|none\n", argv[0]);
            exit(-1);
        }
    
        int letters=0;
        if (!strcasecmp(argv[1],"letters"))
            letters = 1;
    
        int test=0;
        if (!strcasecmp(argv[2],"test"))
            test = 1;
        int delete = 0;
        if (!strcasecmp(argv[2],"delete"))
            delete = 1;
    
        MPI_Init(&argc, &argv);
        MPI_Comm_size(MPI_COMM_WORLD, &size);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        for(i=0;i<BUFSIZE;i++)
        {
            if (letters)
                buf[i]=size*i+rank+'A';
            else
                buf[i]=size*i+rank+'0';
    
            map[i]=size*i+rank;
        }
    
        if (test) {
            int err = MPI_File_open(MPI_COMM_WORLD, "datafile4", MPI_MODE_CREATE|MPI_MODE_EXCL|MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
            if (err != MPI_SUCCESS)  {
                if (rank == 0)
                    MPI_File_delete("datafile4",MPI_INFO_NULL);
                MPI_File_open(MPI_COMM_WORLD, "datafile4", MPI_MODE_CREATE|MPI_MODE_EXCL|MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
            }
        } else if (delete) {
            MPI_File_open(MPI_COMM_WORLD, "datafile4", MPI_MODE_CREATE|MPI_MODE_DELETE_ON_CLOSE|MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
            MPI_File_close(&fh);
            MPI_File_open(MPI_COMM_WORLD, "datafile4", MPI_MODE_CREATE|MPI_MODE_EXCL|MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
        } else {
            MPI_File_open(MPI_COMM_WORLD, "datafile4", MPI_MODE_CREATE|MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
        }
    
        MPI_Type_create_indexed_block(BUFSIZE, 1, map, MPI_CHAR, &filetype);
        MPI_Type_commit(&filetype);
        MPI_File_set_view(fh, disp, MPI_CHAR, filetype, "native", MPI_INFO_NULL);
        MPI_File_write_all(fh, buf, BUFSIZE, MPI_CHAR, &status);
        MPI_File_close(&fh);
        MPI_Type_free(&filetype);
        MPI_Finalize();
        return 0;
    }
    

    and running gives:

    # just open CREATE|WRONLY, reproduce result above
    $ mpirun -np 6 ./clobber letters none
    $ cat datafile4
    ABCDEFGHIJKLMNOPQRSTUVWX$
    $ mpirun -np 2 ./clobber numbers none
    $ cat datafile4
    01234567IJKLMNOPQRSTUVWX$ 
    
    # test for failed EXCL open, and if so, remove file:
    $ mpirun -np 6 ./clobber letters test
    $ cat datafile4
    ABCDEFGHIJKLMNOPQRSTUVWX$
    $ mpirun -np 2 ./clobber numbers test
    $ cat datafile4
    01234567$
    
    # or always open delete-on-close, close, then re-open              
    $ mpirun -np 6 ./clobber letters delete
    $ cat datafile4
    ABCDEFGHIJKLMNOPQRSTUVWX$
    $ mpirun -np 2 ./clobber numbers delete
    $ cat datafile4
    01234567$