dremio SetOptionHandler 简单说明

SetOptionHandler 可以进行基于sql 的配置处理,以下是一个简单说明

SetOptionHandler 的创建

是在CommandCreator中

  • 参考代码
case SET_OPTION:
  if (sqlNode instanceof SqlAlterTableSetOption) {
    return direct.create(new AlterTableSetOptionHandler(catalog, context.getSession()));
  } else if (sqlNode instanceof SqlAlterTableChangeColumnSetOption) {
    return direct.create(new AlterTableChangeColumnSetOptionHandler(catalog));
  } else if (sqlNode instanceof SqlSetOption) {
    checkIfAllowedToSetOption(sqlNode);
    // 创建sql 处理,注意此sql 是在协调节点执行的
    return direct.create(new SetOptionHandler(context));
  }
  throw new IllegalArgumentException("Must have a correct SQL Node for SET_OPTION case");

SetOptionHandler 内部处理

 public List<SimpleCommandResult> toResult(String sql, SqlNode sqlNode) throws ValidationException, RelConversionException, IOException,
      ForemanSetupException {
    // 基于了OptionManager 里边包装的各种options 实现处理
    final OptionManager options = context.getOptions();
    final SqlSetOption option = SqlNodeUtil.unwrap(sqlNode, SqlSetOption.class);
    final String name = option.getName().toString();
 
    final SqlNode value = option.getValue();
    if (value != null && !(value instanceof SqlLiteral)) {
      throw UserException.validationError()
          .message("Dremio does not support assigning non-literal values in SET statements.")
          .build(logger);
    }
 
    final String scope = option.getScope();
    final OptionValue.OptionType type;
    if (scope == null) { // No scope mentioned assumed SESSION
      type = OptionType.SESSION;
    } else {
      switch (scope.toLowerCase()) {
        case "session":
          type = OptionType.SESSION;
          break;
        case "system":
          type = OptionType.SYSTEM;
          break;
        default:
          throw UserException.validationError()
              .message("Invalid OPTION scope %s. Scope must be SESSION or SYSTEM.", scope)
              .build(logger);
      }
    }
 
    // Currently, we convert multi-part identifier to a string.
    if (value != null) { // SET option
      final OptionValue optionValue = createOptionValue(name, type, (SqlLiteral) value);
      options.setOption(optionValue);
    } else { // RESET option
      if ("ALL".equalsIgnoreCase(name)) {
        session.setDefaultSchemaPath(null);
        options.deleteAllOptions(type);
      } else {
        options.deleteOption(name, type);
      }
    }
 
    return Collections.singletonList(SimpleCommandResult.successful("%s updated.", name));
  }

OptionManager参考实现

实现子类,可以看到比较多,对于不同的实现内部处理上稍有不同

  • SystemOptionManager 系统级实现简单说明
    系统级实现是所有节点都可见的,因为配置需要持久化内部使用了kv,同时此服务是在那个节点都包含,实现了service 接口,在start 中
    同时还包含了一个基于定时任务的数据刷新
    数据刷新
if (scheduler.get() != null) {
  scheduler.get().schedule(Schedule.Builder.everyMinutes(FETCH_SYSTEM_OPTION_POLLING_FREQUENCY_MIN).build(),
    new FetchSystemOptionTask());
}

设置处理

public boolean setOption(final OptionValue value) {
    checkArgument(value.getType() == OptionType.SYSTEM, "OptionType must be SYSTEM.");
    final String name = value.getName().toLowerCase(Locale.ROOT);
    final OptionValidator validator = optionValidatorListing.getValidator(name);
    validator.validate(value); // validate the option
 
    final Map<String, OptionValueProto> optionMap = new HashMap<>(); // temp map for convenient lookups
    getOptionProtoList().forEach(optionProto -> optionMap.put(optionProto.getName(), optionProto));
 
    // no need to set option if value is the same
    if (optionMap.containsKey(name) && optionMap.get(name).equals(OptionValueProtoUtils.toOptionValueProto(value))) {
      return true;
    }
 
    // Handle setting option to the default value
    if (value.equals(validator.getDefault())) {
      if (optionMap.containsKey(value.getName())) {
        // If option was previously set, remove it
        optionMap.remove(value.getName());
      } else {
        // If option was not set, skip the set completely
        return true;
      }
    }
    optionMap.put(name, OptionValueProtoUtils.toOptionValueProto(value));
   // kv 存储设置
    options.put(OPTIONS_KEY, OptionValueProtoUtils.toOptionValueProtoList(optionMap.values()));
   // 通过OptionChangeBroadcaster 进行通知更新,通知所有协调节点
    refreshAndNotifySiblings();
    // 通知监听 主要是实时通知一些查询任务
    notifyListeners();
    return true;
}

notifyListeners 使用到的模块

说明

以上是对于SetOptionHandler的简单说明,系统的配置参数还是比较重要的,了解一些配置参数可以规避或者临时解决一些dremio 限制问题,对于
系统选项还包含了一个系统表sys.options 可以参考

参考资料

sabot/kernel/src/main/java/com/dremio/exec/planner/sql/handlers/direct/SetOptionHandler.java
sabot/kernel/src/main/java/com/dremio/exec/planner/sql/handlers/commands/CommandCreator.java
sabot/kernel/src/main/java/com/dremio/exec/server/options/SystemOptionManager.java
services/options/src/main/java/com/dremio/options/OptionManager.java
sabot/kernel/src/main/java/com/dremio/exec/server/options/OptionChangeBroadcaster.java

posted on 2024-03-10 08:00  荣锋亮  阅读(3)  评论(0编辑  收藏  举报

导航