@Override
  protected GlobalQuotaSettingsImpl merge(QuotaSettings other) throws IOException {
    // Validate the quota subject
    validateQuotaTarget(other);

    // Propagate the Throttle
    QuotaProtos.Throttle.Builder throttleBuilder =
      throttleProto == null ? null : throttleProto.toBuilder();

    if (other instanceof ThrottleSettings) {
      ThrottleSettings otherThrottle = (ThrottleSettings) other;
      if (!otherThrottle.proto.hasType() || !otherThrottle.proto.hasTimedQuota()) {
        // It means it's a remove request
        // To prevent the "empty" row in QuotaTableUtil.QUOTA_TABLE_NAME

        QuotaProtos.ThrottleRequest otherProto = otherThrottle.proto;
        if (
          throttleBuilder != null && !otherThrottle.proto.hasTimedQuota()
            && otherThrottle.proto.hasType()
        ) {
          switch (otherProto.getType()) {
            case REQUEST_NUMBER:
              throttleBuilder.clearReqNum();
              break;
            case REQUEST_SIZE:
              throttleBuilder.clearReqSize();
              break;
            case WRITE_NUMBER:
              throttleBuilder.clearWriteNum();
              break;
            case WRITE_SIZE:
              throttleBuilder.clearWriteSize();
              break;
            case READ_NUMBER:
              throttleBuilder.clearReadNum();
              break;
            case READ_SIZE:
              throttleBuilder.clearReadSize();
              break;
            case REQUEST_CAPACITY_UNIT:
              throttleBuilder.clearReqCapacityUnit();
              break;
            case READ_CAPACITY_UNIT:
              throttleBuilder.clearReadCapacityUnit();
              break;
            case WRITE_CAPACITY_UNIT:
              throttleBuilder.clearWriteCapacityUnit();
              break;
            case ATOMIC_READ_SIZE:
              throttleBuilder.clearAtomicReadSize();
              break;
            case ATOMIC_REQUEST_NUMBER:
              throttleBuilder.clearAtomicReqNum();
              break;
            case ATOMIC_WRITE_SIZE:
              throttleBuilder.clearAtomicWriteSize();
              break;
            case REQUEST_HANDLER_USAGE_MS:
              throttleBuilder.clearReqHandlerUsageMs();
              break;
            default:
          }
          boolean hasThrottle = false;
          for (QuotaProtos.ThrottleType quotaType : QuotaProtos.ThrottleType.values()) {
            hasThrottle = hasThrottle(quotaType, throttleBuilder);
            if (hasThrottle) {
              break;
            }
          }
          if (!hasThrottle) {
            throttleBuilder = null;
          }
        } else {
          throttleBuilder = null;
        }

      } else {
        QuotaProtos.ThrottleRequest otherProto = otherThrottle.proto;
        validateTimedQuota(otherProto.getTimedQuota());
        if (throttleBuilder == null) {
          throttleBuilder = QuotaProtos.Throttle.newBuilder();
        }
        switch (otherProto.getType()) {
          case REQUEST_NUMBER:
            throttleBuilder.setReqNum(otherProto.getTimedQuota());
            break;
          case REQUEST_SIZE:
            throttleBuilder.setReqSize(otherProto.getTimedQuota());
            break;
          case WRITE_NUMBER:
            throttleBuilder.setWriteNum(otherProto.getTimedQuota());
            break;
          case WRITE_SIZE:
            throttleBuilder.setWriteSize(otherProto.getTimedQuota());
            break;
          case READ_NUMBER:
            throttleBuilder.setReadNum(otherProto.getTimedQuota());
            break;
          case READ_SIZE:
            throttleBuilder.setReadSize(otherProto.getTimedQuota());
            break;
          case REQUEST_CAPACITY_UNIT:
            throttleBuilder.setReqCapacityUnit(otherProto.getTimedQuota());
            break;
          case READ_CAPACITY_UNIT:
            throttleBuilder.setReadCapacityUnit(otherProto.getTimedQuota());
            break;
          case WRITE_CAPACITY_UNIT:
            throttleBuilder.setWriteCapacityUnit(otherProto.getTimedQuota());
            break;
          case ATOMIC_READ_SIZE:
            throttleBuilder.setAtomicReadSize(otherProto.getTimedQuota());
            break;
          case ATOMIC_REQUEST_NUMBER:
            throttleBuilder.setAtomicReqNum(otherProto.getTimedQuota());
            break;
          case ATOMIC_WRITE_SIZE:
            throttleBuilder.setAtomicWriteSize(otherProto.getTimedQuota());
            break;
          case REQUEST_HANDLER_USAGE_MS:
            throttleBuilder.setReqHandlerUsageMs(otherProto.getTimedQuota());
          default:
        }
      }
    }

    // Propagate the space quota portion
    QuotaProtos.SpaceQuota.Builder spaceBuilder =
      (spaceProto == null ? null : spaceProto.toBuilder());
    if (other instanceof SpaceLimitSettings) {
      if (spaceBuilder == null) {
        spaceBuilder = QuotaProtos.SpaceQuota.newBuilder();
      }
      SpaceLimitSettings settingsToMerge = (SpaceLimitSettings) other;

      QuotaProtos.SpaceLimitRequest spaceRequest = settingsToMerge.getProto();

      // The message contained the expect SpaceQuota object
      if (spaceRequest.hasQuota()) {
        SpaceQuota quotaToMerge = spaceRequest.getQuota();
        // Validate that the two settings are for the same target.
        // SpaceQuotas either apply to a table or a namespace (no user spacequota).
        if (
          !Objects.equals(getTableName(), settingsToMerge.getTableName())
            && !Objects.equals(getNamespace(), settingsToMerge.getNamespace())
        ) {
          throw new IllegalArgumentException("Cannot merge " + settingsToMerge + " into " + this);
        }

        if (quotaToMerge.getRemove()) {
          // It means it's a remove request
          // Update the builder to propagate the removal
          spaceBuilder.setRemove(true).clearSoftLimit().clearViolationPolicy();
        } else {
          // Add the new settings to the existing settings
          spaceBuilder.mergeFrom(quotaToMerge);
        }
      }
    }

    boolean removeSpaceBuilder =
      (spaceBuilder == null) || (spaceBuilder.hasRemove() && spaceBuilder.getRemove());

    Boolean bypassGlobals = this.bypassGlobals;
    if (other instanceof QuotaGlobalsSettingsBypass) {
      bypassGlobals = ((QuotaGlobalsSettingsBypass) other).getBypass();
    }

    if (throttleBuilder == null && removeSpaceBuilder && bypassGlobals == null) {
      return null;
    }

    return new GlobalQuotaSettingsImpl(getUserName(), getTableName(), getNamespace(),
      getRegionServer(), (throttleBuilder == null ? null : throttleBuilder.build()), bypassGlobals,
      (removeSpaceBuilder ? null : spaceBuilder.build()));
  }
Constructs a new {@link Quotas} message from {@code this}.
hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/GlobalQuotaSettingsImpl.java