TextMemMapDataset assumes shared storage between nodes
**Describe the bug**

There is an assumption in [TextMemMapDataset](https://github.com/NVIDIA/NeMo/blob/main/nemo/collections/nlp/data/language_modeling/text_memmap_dataset.py) that all nodes share the same storage. When this is not the case, the class fails to find index files on ancillary nodes (those on which we the node rank is not zero).

**Steps/Code to reproduce bug**

* Copy a text file F into the local filesystems of two nodes A and B.
* In a multi-node setup comprising nodes A and B, instantiate a `TextMemMapDataset` (or any subclass such as `JSONLMemMapDataset`) with `dataset_paths=[F]`).
* Assuming node B is the one `node_rank>0`, all node B processes fail with an exception is raised with a message like  `ValueError: Memory Map for F is not found, missing one or more of files: F.idx.{.npy,.info}`.

**Expected behavior**

No exception should occur.

**Environment overview (please complete the following information)**

A cluster that supports multi-node jobs and isolated (not shared) filesystems on each node.

**Environment details**

NeMo 23.02.

**Additional context**

This issue appears to stem from these lines in `TextMemMapDataset.__init__()`:

```
        if not is_distributed or (is_distributed and torch.distributed.get_rank() == 0):
            build_index_files(dataset_paths, newline_int, workers=self._worker, build_index_fn=build_index_fn)
```

The test should use the local rank. However if the input storage is indeed shared between nodes, `local_rank=0` processes might collide with one another, as they would write into the same files. In order to avoid this, one suggestion would be to factor in the node rank into the index file path, which cause separate index files to be created on each node. If this is deemed unacceptable on shared filesystems where this is not necessary, other options would include:
* adding a flag to turn on/off that behavior
* adding an extra barrier to automatically detect whether the index files have been created on first pass:

```
        if not is_distributed or (is_distributed and torch.distributed.get_rank() == 0):
            # Creates index files only on global rank 0.
            build_index_files(dataset_paths, newline_int, workers=self._worker, build_index_fn=build_index_fn)

        if is_distributed:
            # Wait for global rank 0 to create index files.
            torch.distributed.barrier()

        if is_distributed and local_rank == 0:
            # Shared file system case: this is a no-op since the index files have already been created.
            # Non-shared file system case: will only create the index files on node_rank>0 and local_rank==0.
            build_index_files(dataset_paths, newline_int, workers=self._worker, build_index_fn=build_index_fn)

        if is_distributed:
            # Wait for all local ranks 0 to create index files.
            torch.distributed.barrier()
```

