|
| 1 | + |
| 2 | + |
| 3 | +#include <algorithm> |
| 4 | +#include "extensions.hpp" |
| 5 | + |
| 6 | +/** Identification of this component (for log) */ |
| 7 | +static const char *comp_str = "Extensions"; |
| 8 | + |
| 9 | +void |
| 10 | +ipx_cfg_extensions::add_extension(ipx_instance *inst, unsigned int idx, struct ipx_ctx_ext *ext) |
| 11 | +{ |
| 12 | + auto ext_info = &m_extensions[ext->data_type][ext->data_name]; |
| 13 | + std::vector<struct plugin_rec> &vec_plugins = (ext->etype == IPX_EXTENSION_PRODUCER) |
| 14 | + ? ext_info->producers |
| 15 | + : ext_info->consumers; |
| 16 | + vec_plugins.push_back({inst->get_name(), idx, ext}); |
| 17 | +} |
| 18 | + |
| 19 | +void |
| 20 | +ipx_cfg_extensions::check_dependencies(const std::string &ident, const struct ext_rec &rec) |
| 21 | +{ |
| 22 | + std::string name_producers; |
| 23 | + std::string name_consumers; |
| 24 | + |
| 25 | + // Prepare list of produces and consumers for log |
| 26 | + for (const auto &producer : rec.producers) { |
| 27 | + if (!name_producers.empty()) { |
| 28 | + name_producers.append(", "); |
| 29 | + } |
| 30 | + name_producers.append("'" + producer.name + "'"); |
| 31 | + } |
| 32 | + for (const auto &consumer : rec.consumers) { |
| 33 | + if (!name_consumers.empty()) { |
| 34 | + name_consumers.append(", "); |
| 35 | + } |
| 36 | + name_consumers.append("'" + consumer.name + "'"); |
| 37 | + } |
| 38 | + |
| 39 | + // No producers? |
| 40 | + if (rec.producers.empty()) { |
| 41 | + throw std::runtime_error("No provider of Data Record extension " + ident + "found. " |
| 42 | + "The extension is required by " + name_consumers); |
| 43 | + } |
| 44 | + |
| 45 | + // Multiple producers? |
| 46 | + if (rec.producers.size() > 1) { |
| 47 | + throw std::runtime_error("Data Record extension " + ident + " is provided by " |
| 48 | + "multiple instances (" + name_producers + ")"); |
| 49 | + } |
| 50 | + |
| 51 | + // No consumer |
| 52 | + if (rec.consumers.empty()) { |
| 53 | + IPX_WARNING(comp_str, "Extension %s is provided by %s, but no other plugins use it. " |
| 54 | + "The provider can be probably removed.", ident.c_str(), name_producers.c_str()); |
| 55 | + return; |
| 56 | + } |
| 57 | + |
| 58 | + // Check if the producer is placed before all consumers |
| 59 | + const struct plugin_rec &producer_rec = rec.producers.front(); |
| 60 | + const auto min_cons = std::min_element(rec.consumers.cbegin(), rec.consumers.cend()); |
| 61 | + if (producer_rec.plugin_idx > min_cons->plugin_idx) { |
| 62 | + throw std::runtime_error("Instance '" + producer_rec.name + "', which is a provider " |
| 63 | + "of Data Record extension " + ident + ", is placed in the collector pipeline " |
| 64 | + "after '" + min_cons->name + "' instance, which depends on the extension. " |
| 65 | + "Please, swap the order of the plugin instances"); |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | + |
| 70 | +void |
| 71 | +ipx_cfg_extensions::resolve(std::vector<ipx_instance *> &plugins) |
| 72 | +{ |
| 73 | + // Add extensions and dependencies from all plugins |
| 74 | + unsigned int pos = 0; |
| 75 | + for (auto &it : plugins) { |
| 76 | + if (dynamic_cast<ipx_instance_input *>(it)) { |
| 77 | + // Input plugins cannot register extensions |
| 78 | + continue; |
| 79 | + } |
| 80 | + |
| 81 | + struct ipx_ctx_ext *arr_ptr = nullptr; |
| 82 | + size_t arr_size = 0; |
| 83 | + |
| 84 | + std::tie(arr_ptr, arr_size) = it->get_extensions(); |
| 85 | + for (size_t i = 0; i < arr_size; ++i) { |
| 86 | + add_extension(it, pos, &arr_ptr[i]); |
| 87 | + } |
| 88 | + |
| 89 | + if (!dynamic_cast<ipx_instance_output *>(it)) { |
| 90 | + // Increment position for all plugins except outputs |
| 91 | + pos++; |
| 92 | + } |
| 93 | + }; |
| 94 | + |
| 95 | + if (m_extensions.empty()) { |
| 96 | + // No extensions, no dependencies |
| 97 | + return; |
| 98 | + } |
| 99 | + |
| 100 | + size_t offset = 0; |
| 101 | + uint64_t mask = 1U; |
| 102 | + |
| 103 | + for (auto &ext_type : m_extensions) { |
| 104 | + for (auto &ext_name : ext_type.second) { |
| 105 | + if (!mask) { |
| 106 | + // No more bits in the mask! |
| 107 | + throw std::runtime_error("Maximum number of Data Record extensions has been reached!"); |
| 108 | + } |
| 109 | + |
| 110 | + struct ext_rec &ext = ext_name.second; |
| 111 | + assert(ext.producers.size() == 1 && "Exactly one producer"); |
| 112 | + |
| 113 | + // Check the extension |
| 114 | + std::string ident = "'" + ext_type.first + "/" + ext_name.first + "'"; |
| 115 | + check_dependencies(ident, ext_name.second); |
| 116 | + |
| 117 | + // Determine size, offset and bitset mask |
| 118 | + ext.size = ext.producers[0].rec->size; |
| 119 | + ext.offset = offset; |
| 120 | + ext.mask = mask; |
| 121 | + |
| 122 | + // Align the offset to multiple of 8 |
| 123 | + ext.offset += (ext.size % 8U == 0) ? ext.size : (((ext.size / 8U) + 1U) * 8U); |
| 124 | + ext.mask <<= 1U; |
| 125 | + |
| 126 | + IPX_DEBUG(comp_str, "Extension %s registered (size: %zu, offset: %zu)", |
| 127 | + ext.size, ext.offset); |
| 128 | + } |
| 129 | + } |
| 130 | + |
| 131 | + |
| 132 | + |
| 133 | + // TODO: save total size of all extensions |
| 134 | + |
| 135 | + |
| 136 | + |
| 137 | +} |
| 138 | + |
0 commit comments