@Override
  public synchronized void close() {
    if (!closed) {
      LOG.info("VFS closing");
      Exception stackTraceEx = new Exception("FSRecordsImpl close stacktrace");

      if (flushingTask != null) {
        //Stop flushing _before_ assigning .close=true: otherwise there could be 'already closed' exceptions
        //  in Flusher -- mostly harmless, but annoying.
        try {
          flushingTask.close();
        }
        catch (Exception stoppingEx) {
          LOG.warn("Can't close VFS flushing task", stoppingEx);
          stackTraceEx.addSuppressed(stoppingEx);
        }
      }

      closed = true;


      try {
        //ensure async scanning is finished -- until that records file is still in use,
        // which could cause e.g. problems with its deletion
        InvertedNameIndex invertedNameIndex = invertedNameIndexLazy.get();
        //Clear index is not required, but help GC by releasing huge table faster
        invertedNameIndex.clear();
      }
      catch (Throwable t) {
        LOG.warn("VFS: invertedNameIndex building is not terminated properly", t);
        stackTraceEx.addSuppressed(t);
      }

      for (AutoCloseable toClose : closeables) {
        try {
          toClose.close();
        }
        catch (Exception e) {
          LOG.warn("Can't close " + toClose, e);
          stackTraceEx.addSuppressed(e);
        }
      }

      try {
        PersistentFSConnector.disconnect(connection);
      }
      catch (IOException e) {
        //handleError(e);
        stackTraceEx.addSuppressed(e);
      }

      //Assign at the end so all .addSuppressed() are visible.
      // Downside: it could be .closed=true but .closedStackTrace=null because not assigned yet.
      closedStackTrace = stackTraceEx;
    }
  }
@Override
  public synchronized void close()