private void close(boolean unmap) throws IOException {
    boolean actuallyClosed = false;
    try {
      synchronized (pagesLock) {
        if (channel.isOpen()) {
          channel.close();
          for (Page page : pages) {
            if (page != null) {
              unregisterMappedPage(pageSize);
            }
          }
          actuallyClosed = true;
        }

        if (unmap) {
          try {
            for (Page page : pages) {
              if (page != null) {
                page.unmap();
              }
            }
          }
          finally {
            //Tradeoff: we can _always_ clean the .pages array, regardless of unmap or not -- then .close(unmap:false)
            // benefits from faster page unmapping by GC (it is quite often storage itself is still strongly-reachable
            // after the .close() => without nulling the .pages pageBuffers also remain strongly-reachable => not
            // unmapped)
            // But this way we lose the ability to ask storage explicitly unmap pages _after_ the .close() -- because
            // .pages is already cleared, nothing to unmap.
            // This close-then-unmap is really frequent scenario: it is quite often storage is .close()-ed during
            // some regular resource-deallocation-procedure, but in the very end we want to _delete_ the storage
            // file, hence we need to explicitly unmap it beforehand -- which we can't do if page refs were already
            // cleared during regular .close()
            // So I chose to lean the other side, and do NOT clear page refs on close(unmap:false), so later
            // .close(unmap:true) if called -- could still unmap them. But this means that without explicit
            // .close(unmap:true) mapped buffers will remain mapped for longer, even after storage was already
            // .close()-ed.
            Arrays.fill(pages, null);
          }
        }
      }
    }
    finally {
      synchronized (openedStorages) {
        MMappedFileStorage removed = openedStorages.get(storagePath);
        if (removed == this) {
          //noinspection resource
          openedStorages.remove(storagePath);
          //noinspection AssignmentToStaticFieldFromInstanceMethod
          openedStoragesCount--;
        }
      }
    }

    if (actuallyClosed && WARN_OF_DELETED_STORAGES_USE) {
      Path parent = storagePath.getParent();
      if (!Files.exists(parent)) {
        LOG.warn("Storage parent dir[" + parent.toAbsolutePath() + "] is not exist: storage files were removed while wasn't yet closed!");
      }
      else {
        if (!Files.exists(storagePath)) {
          LOG.warn("Storage[" + storagePath.toAbsolutePath() + "] is not exist: storage file was removed while wasn't yet closed!");
        }
      }
    }
  }
private void close(boolean unmap)