@Override
  public @NotNull DurableEnumerator<V> open(@NotNull Path storagePath) throws IOException {
    String name = storagePath.getFileName().toString();
    Path hashToIdPath = storagePath.resolveSibling(name + mapFileSuffix);

    return valuesLogFactory.wrapStorageSafely(
      storagePath,
      valuesLog -> valueHashToIdFactory.wrapStorageSafely(
        hashToIdPath,
        valueHashToId -> {
          if (rebuildMapFromLogIfInconsistent) {
            //If hashToId map is durable, but its factory configured to 'create an empty map if (corrupted, inconsistent,
            // wasn't properly closed...)' -- then this branch rebuilds such a map, hence provides a recovery even for
            // durable maps
            //If hashToId is really non-durable (see DEFAULT_IN_MEMORY_MAP_FACTORY) then this branch refills the map.
            if (!valuesLog.isEmpty() && valueHashToId.isEmpty()) {

              boolean mapIsDurable = !(valueHashToId instanceof NonDurableNonParallelIntToMultiIntMap);

              //this branch is a warning for durable maps, but a regular thing for non-durable:
              if (mapIsDurable) {
                LOG.warn("[" + name + "]: .valueHashToId map is out-of-sync with .valuesLog data (records count don't match) " +
                         "-> rebuilding the map (impl: " + valueHashToId.getClass() + ")");
              }

              //MAYBE RC: valueHashToId could be build/load async -- to not delay initialization (see DurableStringEnumerator)
              DurableEnumerator.fillValueHashToIdMap(valuesLog, valueDescriptor, valueHashToId);

              if (mapIsDurable) {
                LOG.warn("[" + name + "]: .valueHashToId was rebuilt (" + valueHashToId.size() + " records)");
              }
              else {
                LOG.info("[" + name + "]: .valueHashToId (in memory) was filled (" + valueHashToId.size() + " records)");
              }
            }
            //TODO RC: what if valuesLog was recovered? -- could it be the .hashToId map is somehow wasClosedProperly,
            //         but still is inconsistent with valuesLog? It seems it could: current implementation of append-only-log
            //         _could_ sometimes lose the written-and-commited record: i.e. one of the previous values in the log
            //         wasn't committed, and even record header wasn't written -- and because of that whole region after
            //         that allocated-but-not-yet-started record is lost (see more detailed discussion in the implementation
            //         class). So there _is_ a chance that value is appended to the log, and valueId is inserted into the map,
            //         but value record is lost on crash, so the id put in the map is now invalid.
            //         So we should either modify AppendOnlyLog so that it doesn't allow that (e.g. we could not return
            //         from allocateRecord until at least header is written -- again, see discussion in the impl class) -- or
            //         we should always rebuild the map if AppendOnlyLog was recovered, _and_ the recovered region >0 -- even
            //         if the map itself wasClosedProperly=true.

            //MAYBE separate 'always rebuild map' and 'rebuild map if inconsistent'
            //      (both requires .open(path,CREATE_NEW) method)
          }


          return new DurableEnumerator<>(
            valueDescriptor,
            valuesLog,
            () -> valueHashToId
          );
        }
      )
    );
  }
@Override
  public @NotNull DurableEnumerator<V> open(@NotNull Path storagePath)