private void writeGlobalState(
      String reason, MetaData metaData, @Nullable MetaData previousMetaData) throws Exception {
    logger.trace("[_global] writing state, reason [{}]", reason);
    // create metadata to write with just the global state
    MetaData globalMetaData = MetaData.builder().metaData(metaData).removeAllIndices().build();

    XContentBuilder builder = XContentFactory.contentBuilder(format);
    builder.startObject();
    MetaData.Builder.toXContent(globalMetaData, builder, formatParams);
    builder.endObject();
    builder.flush();

    String globalFileName = "global-" + globalMetaData.version();
    Exception lastFailure = null;
    boolean wroteAtLeastOnce = false;
    for (File dataLocation : nodeEnv.nodeDataLocations()) {
      File stateLocation = new File(dataLocation, "_state");
      FileSystemUtils.mkdirs(stateLocation);
      File stateFile = new File(stateLocation, globalFileName);

      FileOutputStream fos = null;
      try {
        fos = new FileOutputStream(stateFile);
        BytesReference bytes = builder.bytes();
        fos.write(bytes.array(), bytes.arrayOffset(), bytes.length());
        fos.getChannel().force(true);
        fos.close();
        wroteAtLeastOnce = true;
      } catch (Exception e) {
        lastFailure = e;
      } finally {
        IOUtils.closeWhileHandlingException(fos);
      }
    }

    if (!wroteAtLeastOnce) {
      logger.warn("[_global]: failed to write global state", lastFailure);
      throw new IOException("failed to write global state", lastFailure);
    }

    // delete the old files
    for (File dataLocation : nodeEnv.nodeDataLocations()) {
      File[] files = new File(dataLocation, "_state").listFiles();
      if (files == null) {
        continue;
      }
      for (File file : files) {
        if (!file.getName().startsWith("global-")) {
          continue;
        }
        if (file.getName().equals(globalFileName)) {
          continue;
        }
        file.delete();
      }
    }
  }
    public static void toXContent(
        MetaData metaData, XContentBuilder builder, ToXContent.Params params) throws IOException {
      XContentContext context = XContentContext.valueOf(params.param(CONTEXT_MODE_PARAM, "API"));

      builder.startObject("meta-data");

      builder.field("version", metaData.version());
      builder.field("cluster_uuid", metaData.clusterUUID);

      if (!metaData.persistentSettings().getAsMap().isEmpty()) {
        builder.startObject("settings");
        for (Map.Entry<String, String> entry :
            metaData.persistentSettings().getAsMap().entrySet()) {
          builder.field(entry.getKey(), entry.getValue());
        }
        builder.endObject();
      }

      if (context == XContentContext.API && !metaData.transientSettings().getAsMap().isEmpty()) {
        builder.startObject("transient_settings");
        for (Map.Entry<String, String> entry : metaData.transientSettings().getAsMap().entrySet()) {
          builder.field(entry.getKey(), entry.getValue());
        }
        builder.endObject();
      }

      builder.startObject("templates");
      for (ObjectCursor<IndexTemplateMetaData> cursor : metaData.templates().values()) {
        IndexTemplateMetaData.Builder.toXContent(cursor.value, builder, params);
      }
      builder.endObject();

      if (context == XContentContext.API && !metaData.indices().isEmpty()) {
        builder.startObject("indices");
        for (IndexMetaData indexMetaData : metaData) {
          IndexMetaData.Builder.toXContent(indexMetaData, builder, params);
        }
        builder.endObject();
      }

      for (ObjectObjectCursor<String, Custom> cursor : metaData.customs()) {
        Custom proto = lookupPrototypeSafe(cursor.key);
        if (proto.context().contains(context)) {
          builder.startObject(cursor.key);
          cursor.value.toXContent(builder, params);
          builder.endObject();
        }
      }
      builder.endObject();
    }
  /**
   * As of 2.0 we require units for time and byte-sized settings. This methods adds default units to
   * any cluster settings that don't specify a unit.
   */
  public static MetaData addDefaultUnitsIfNeeded(ESLogger logger, MetaData metaData) {
    Settings.Builder newPersistentSettings = null;
    for (Map.Entry<String, String> ent : metaData.persistentSettings().getAsMap().entrySet()) {
      String settingName = ent.getKey();
      String settingValue = ent.getValue();
      if (CLUSTER_BYTES_SIZE_SETTINGS.contains(settingName)) {
        try {
          Long.parseLong(settingValue);
        } catch (NumberFormatException nfe) {
          continue;
        }
        // It's a naked number that previously would be interpreted as default unit (bytes); now we
        // add it:
        logger.warn(
            "byte-sized cluster setting [{}] with value [{}] is missing units; assuming default units (b) but in future versions this will be a hard error",
            settingName,
            settingValue);
        if (newPersistentSettings == null) {
          newPersistentSettings = Settings.builder();
          newPersistentSettings.put(metaData.persistentSettings());
        }
        newPersistentSettings.put(settingName, settingValue + "b");
      }
      if (CLUSTER_TIME_SETTINGS.contains(settingName)) {
        try {
          Long.parseLong(settingValue);
        } catch (NumberFormatException nfe) {
          continue;
        }
        // It's a naked number that previously would be interpreted as default unit (ms); now we add
        // it:
        logger.warn(
            "time cluster setting [{}] with value [{}] is missing units; assuming default units (ms) but in future versions this will be a hard error",
            settingName,
            settingValue);
        if (newPersistentSettings == null) {
          newPersistentSettings = Settings.builder();
          newPersistentSettings.put(metaData.persistentSettings());
        }
        newPersistentSettings.put(settingName, settingValue + "ms");
      }
    }

    if (newPersistentSettings != null) {
      return new MetaData(
          metaData.clusterUUID(),
          metaData.version(),
          metaData.transientSettings(),
          newPersistentSettings.build(),
          metaData.getIndices(),
          metaData.getTemplates(),
          metaData.getCustoms(),
          metaData.concreteAllIndices(),
          metaData.concreteAllOpenIndices(),
          metaData.concreteAllClosedIndices(),
          metaData.getAliasAndIndexLookup());
    } else {
      // No changes:
      return metaData;
    }
  }