#include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int NO_ELEMENTS_IN_CONFIG; } namespace { using namespace Poco::Util; struct Pattern { struct Retention { UInt64 age; UInt64 precision; }; std::string regexp; std::string function; std::vector retentions; UInt16 priority; UInt8 is_default; }; static Pattern readOnePattern( const AbstractConfiguration & config, const std::string & path) { Pattern pattern; AbstractConfiguration::Keys keys; config.keys(path, keys); if (keys.empty()) throw Exception("Empty pattern in Graphite rollup configuration", ErrorCodes::NO_ELEMENTS_IN_CONFIG); for (const auto & key : keys) { const String key_path = path + "." + key; if (startsWith(key, "regexp")) { pattern.regexp = config.getString(key_path); } else if (startsWith(key, "function")) { pattern.function = config.getString(key_path); } else if (startsWith(key, "retention")) { pattern.retentions.push_back(Pattern::Retention{0, 0}); pattern.retentions.back().age = config.getUInt64(key_path + ".age", 0); pattern.retentions.back().precision = config.getUInt64(key_path + ".precision", 0); } } return pattern; } static std::vector readPatterns( const AbstractConfiguration & config, const std::string & section) { AbstractConfiguration::Keys keys; std::vector result; size_t count = 0; config.keys(section, keys); for (const auto & key : keys) { if (startsWith(key, "pattern")) { Pattern pattern(readOnePattern(config, section + "." + key)); pattern.is_default = false; pattern.priority = ++count; result.push_back(pattern); } else if (startsWith(key, "default")) { Pattern pattern(readOnePattern(config, section + "." + key)); pattern.is_default = true; pattern.priority = std::numeric_limits::max(); result.push_back(pattern); } } return result; } static Strings getAllGraphiteSections(const AbstractConfiguration & config) { Strings result; AbstractConfiguration::Keys keys; config.keys(keys); for (const auto & key : keys) { if (startsWith(key, "graphite_")) result.push_back(key); } return result; } } // namespace StorageSystemGraphite::StorageSystemGraphite(const std::string & name_) : name(name_) { setColumns(ColumnsDescription({ {"config_name", std::make_shared()}, {"regexp", std::make_shared()}, {"function", std::make_shared()}, {"age", std::make_shared()}, {"precision", std::make_shared()}, {"priority", std::make_shared()}, {"is_default", std::make_shared()}, })); } BlockInputStreams StorageSystemGraphite::read( const Names & column_names, const SelectQueryInfo &, const Context & context, QueryProcessingStage::Enum & processed_stage, size_t /*max_block_size*/, unsigned /*num_streams*/) { check(column_names); processed_stage = QueryProcessingStage::FetchColumns; MutableColumns res_columns = getSampleBlock().cloneEmptyColumns(); const auto & config = context.getConfigRef(); Strings sections = getAllGraphiteSections(config); for (const auto & section : sections) { const auto patterns = readPatterns(config, section); for (const auto & pattern : patterns) { for (const auto & ret : pattern.retentions) { res_columns[0]->insert(Field(section)); res_columns[1]->insert(Field(pattern.regexp)); res_columns[2]->insert(Field(pattern.function)); res_columns[3]->insert(nearestFieldType(ret.age)); res_columns[4]->insert(nearestFieldType(ret.precision)); res_columns[5]->insert(nearestFieldType(pattern.priority)); res_columns[6]->insert(nearestFieldType(pattern.is_default)); } } } return BlockInputStreams(1, std::make_shared(getSampleBlock().cloneWithColumns(std::move(res_columns)))); } }