docs: @Override
      public void save() throws IOException {
          if (BulkChange.contains(this)) {
              return;
          }
          final File nodesDir = getNodesDir();
          final Set<String> existing = new HashSet<>();
          for (Node n : nodes.values()) {
              if (n instanceof EphemeralNode) {
                  continue;
              }
              existing.add(n.getNodeName());
              XmlFile xmlFile = new XmlFile(Jenkins.XSTREAM, new File(new File(nodesDir, n.getNodeName()), "config.xml"));
              xmlFile.write(n);
              SaveableListener.fireOnChange(this, xmlFile);
          }
          for (File forDeletion : nodesDir.listFiles(new FileFilter() {
              @Override
              public boolean accept(File pathname) {
                  return pathname.isDirectory() && !existing.contains(pathname.getName());
              }
          })) {
              Util.deleteRecursive(forDeletion);
          }
      }