class_docstr: Open dataset in readonly mode.
  
  `DistributeDataset` is used to read datasets in a distributed manner.
  Data in this dataset will be distributed evenly in blocks to each worker in the `distributed communicator`.
  
  **Note** When all data has been read, reading dataset again will revert back to the first data.
  
  Args:
      path (str): Path to dataset.
      rank (int): Rank in distributed communicator. See: bmtrain.rank()
      world_size (int): Total workers in distributed communicator. See: bmtrain.world_size()
      block_size (int): Size of each block in bytes. All files in the same dataset should have the same block size. Default: 16MB
  
  Example:
      >>> dataset = DistributedDataset("/path/to/dataset")
      >>> for i in range(10):
      >>>     dataset.read()
class_docstr_tok: ["Open","dataset","in","readonly","mode",".","`","DistributeDataset","`","is","used","to","read","datasets","in","a","distributed","manner",".","Data","in","this","dataset","will","be","distributed","evenly","in","blocks","to","each","worker","in","the","`","distributed","communicator","`",".","*","*","Note","*","*","When","all","data","has","been","read",",","reading","dataset","again","will","revert","back","to","the","first","data",".","Args",":","path","(","str",")",":","Path","to","dataset",".","rank","(","int",")",":","Rank","in","distributed","communicator",".","See",":","bmtrain.rank","(",")","world_size","(","int",")",":","Total","workers","in","distributed","communicator",".","See",":","bmtrain.world_size","(",")","block_size","(","int",")",":","Size","of","each","block","in","bytes",".","All","files","in","the","same","dataset","should","have","the","same","block","size",".","Default",":","16MB","Example",":",">",">",">","dataset","=","DistributedDataset","(","``","\/path\/to\/dataset","''",")",">",">",">","for","i","in","range","(","10",")",":",">",">",">","dataset.read","(",")"]
code: def _update_states(self, fast_skip: bool = True):
      meta_path = os.path.join(self._path, "meta.bin")
  
      while True:
          try:
              mod_time = os.stat(meta_path).st_mtime
              break
          except Exception as e:
              print(
                  "Error: reading info list in DistributedDataset._update_states, "
                  "meta_path={path}, err={err}!".format(
                      path=meta_path, err=str(e)
                  )
              )
              time.sleep(10)
  
      if self._last_mod_time < mod_time:
          # file changed
          pass
      else:
          if fast_skip:
              return
  
      info: List[FileInfo] = []
      if os.path.exists(meta_path):
          info = _read_info_list(meta_path)
  
      old_len = len(self._file_info)
      if old_len > len(info):
          raise RuntimeError("Dataset meta file: changed unexpectly")
  
      mask_changed = False
      for i in range(old_len):
          if self._file_info[i].file_name != info[i].file_name:
              raise RuntimeError(
                  "Dataset meta file: changed unexpectly"
              )
          if self._file_info[i].block_begin != info[i].block_begin:
              raise RuntimeError(
                  "Dataset meta file: changed unexpectly"
              )
          if self._file_info[i].block_end != info[i].block_end:
              raise RuntimeError(
                  "Dataset meta file: changed unexpectly"
              )
          if self._file_info[i].mask != info[i].mask:
              mask_changed = True
  
      if info[0].block_begin != 0:
          raise RuntimeError("Dataset meta file: block error (0)")
      for i in range(len(info) - 1):
          if info[i].block_end != info[i + 1].block_begin:
              raise RuntimeError(
                  "Dataset meta file: block error (%d)" % (i + 1)
              )
  
      if (old_len == len(info) and not mask_changed) and fast_skip:
          # fast skip
          return
  
      if len(info) > 0:
          total_blocks = info[-1].block_end
          self._nbytes = 0
          self._nlines = 0
          for v in info:
              self._nbytes += v.nbytes
              self._nlines += v.nlines
      else:
          total_blocks = 0
          self._nbytes = 0
          self._nlines = 0
  
      if total_blocks > 0:
          unused_block_set = set(self._unused_block)
          nw_unused_block: List[int] = []
          for i in range(len(info)):
              v = info[i]
              if not v.mask:
                  if i < old_len:
                      nw_unused_block.extend(
                          _filtered_range(
                              v.block_begin,
                              v.block_end,
                              self._rank,
                              self._world_size,
                              unused_block_set,
                          )
                      )
                  else:
                      nw_unused_block.extend(
                          _filtered_range(
                              v.block_begin,
                              v.block_end,
                              self._rank,
                              self._world_size,
                          )
                      )
  
          # re-shuffle unused blocks
          if self._shuffle:
              random.shuffle(nw_unused_block)
          self._unused_block = nw_unused_block
  
          self._file_ends = []
          for v in info:
              self._file_ends.append(v.block_end)
      else:
          self._unused_block = []
          self._file_ends = []
      self._total_blocks = total_blocks
      self._file_info = info
  
      assert len(self._file_ends) == len(self._file_info)
  
imports: import io
  import os
  import struct
  from typing import List, Optional, Set
  import torch
  import bisect
  import bmtrain
  import json
  from .serializer import Serializer, PickleSerializer
  import random
  import string
  import time
label_desc: Use image node_id 2 for calling the DistributedDataset obj's underlying member method code with example usage: obj._update_states(fast_skip) without return types