LCOV - code coverage report
Current view: top level - ut/tools/aclrtc/specialization - resource_registry.cpp Coverage Total Hit
Test: CHG Lines: 100.0 % 3 3
Test Date: 2026-08-25 14:27:46
Legend: Lines: hit not hit

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2025 Huawei Technologies Co., Ltd.
       3              :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4              :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5              :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6              :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7              :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8              :  * See LICENSE in the root of the software repository for the full text of the License.
       9              :  */
      10              : 
      11              : #include "resource_registry.h"
      12              : 
      13              : #include <algorithm>
      14              : #include <cerrno>
      15              : #include <cstdlib>
      16              : #include <cstring>
      17              : #include <dlfcn.h>
      18              : #include <fstream>
      19              : #include <set>
      20              : #include <utility>
      21              : #include <vector>
      22              : 
      23              : #include <boost/filesystem.hpp>
      24              : #include <boost/system/error_code.hpp>
      25              : 
      26              : #include "ascendc_manifest_abi.h"
      27              : #include "ascendc_tool_log.h"
      28              : #include "file_utils.h"
      29              : #include "nlohmann/json.hpp"
      30              : 
      31              : namespace ascendc {
      32              : namespace specialization_compile {
      33              : 
      34              : bool IsKernelMetaSavingEnabled() noexcept
      35              : {
      36              :     const char* environmentValue = std::getenv("ASCEND_OP_COMPILE_SAVE_KERNEL_META");
      37              :     if (environmentValue == nullptr) {
      38              :         return false;
      39              :     }
      40              : 
      41              :     const auto isWhitespace = [](char value) {
      42              :         return value == ' ' || value == '\t' || value == '\n' || value == '\r' || value == '\f' || value == '\v';
      43              :     };
      44              :     const char* firstValueCharacter = environmentValue;
      45              :     while (*firstValueCharacter != '\0' && isWhitespace(*firstValueCharacter)) {
      46              :         ++firstValueCharacter;
      47              :     }
      48              :     const char* valueEnd = firstValueCharacter;
      49              :     while (*valueEnd != '\0') {
      50              :         ++valueEnd;
      51              :     }
      52              :     while (valueEnd != firstValueCharacter && isWhitespace(*(valueEnd - 1))) {
      53              :         --valueEnd;
      54              :     }
      55              :     return valueEnd == firstValueCharacter + 1 && *firstValueCharacter == '1';
      56              : }
      57              : 
      58              : void LibraryDeleter::operator()(void* handle) const noexcept
      59              : {
      60              :     if (handle != nullptr && dlclose(handle) != 0) {
      61              :         ASCENDLOGW("Failed to close compile resource shared object: handle=%p reason=dlclose returned nonzero", handle);
      62              :     }
      63              : }
      64              : 
      65              : namespace {
      66              : 
      67              : namespace fs = boost::filesystem;
      68              : using Json = nlohmann::json;
      69              : 
      70              : constexpr char RELATIVE_JIT_ROOT[] = "op_impl/ai_core/tbe/kernel/jit";
      71              : constexpr char LIBRARY_NAME_SUFFIX[] = "_compile_database.so";
      72              : constexpr uint64_t MAX_MANIFEST_SIZE = 8U * 1024U * 1024U;
      73              : constexpr uint64_t MAX_PATH_SIZE = 4096U;
      74              : constexpr uint64_t MAX_RESOURCE_FILE_SIZE = 256U * 1024U * 1024U;
      75              : constexpr uint64_t MAX_MANIFEST_RESOURCE_SIZE = 512U * 1024U * 1024U;
      76              : constexpr uint64_t MAX_REGISTRY_RESOURCE_SIZE = 1024U * 1024U * 1024U;
      77              : constexpr uint64_t MAX_MANIFEST_COUNT = 4096U;
      78              : constexpr uint64_t MAX_EXTENSION_COUNT = 4096U;
      79              : constexpr uint64_t MAX_FILE_COUNT = 65536U;
      80              : constexpr uint64_t MAX_REGISTRY_FILE_COUNT = 131072U;
      81              : 
      82              : const char* SourceTypeName(ResourceSourceType sourceType) noexcept
      83              : {
      84              :     switch (sourceType) {
      85              :         case ResourceSourceType::External:
      86              :             return "external";
      87              :         case ResourceSourceType::Custom:
      88              :             return "custom";
      89              :         case ResourceSourceType::BuiltIn:
      90              :             return "built-in";
      91              :     }
      92              :     return "unknown";
      93              : }
      94              : 
      95              : const char* ResourceStatusName(ResourceStatus status) noexcept
      96              : {
      97              :     switch (status) {
      98              :         case ResourceStatus::Success:
      99              :             return "success";
     100              :         case ResourceStatus::NotFound:
     101              :             return "not_found";
     102              :         case ResourceStatus::Conflict:
     103              :             return "conflict";
     104              :         case ResourceStatus::InvalidResource:
     105              :             return "invalid_resource";
     106              :         case ResourceStatus::IoError:
     107              :             return "io_error";
     108              :         case ResourceStatus::LoadError:
     109              :             return "load_error";
     110              :         case ResourceStatus::InternalError:
     111              :             return "internal_error";
     112              :     }
     113              :     return "unknown";
     114              : }
     115              : 
     116              : void CleanupPath(const std::string& path) noexcept
     117              : {
     118              :     if (path.empty()) {
     119              :         return;
     120              :     }
     121              :     if (!FileUtils::RemoveAll(path)) {
     122              :         ASCENDLOGW("Failed to remove compile resource path: path=%s reason=recursive removal failed", path.c_str());
     123              :     }
     124              : }
     125              : 
     126              : ResourceStatus CreateTemporaryRoot(std::string& temporaryRoot)
     127              : {
     128              :     const char* environment = std::getenv("TMPDIR");
     129              :     const fs::path configured = environment == nullptr || *environment == '\0' ? "/tmp" : environment;
     130              :     boost::system::error_code error;
     131              :     const fs::path parent = fs::canonical(configured, error);
     132              :     if (error) {
     133              :         ASCENDLOGE(
     134              :             "Failed to resolve compile resource temporary parent: configured=%s error=%s", configured.c_str(),
     135              :             error.message().c_str());
     136              :         return ResourceStatus::IoError;
     137              :     }
     138              :     if (!fs::is_directory(parent, error)) {
     139              :         ASCENDLOGE(
     140              :             "Compile resource temporary parent is not a directory: configured=%s resolved=%s error=%s",
     141              :             configured.c_str(), parent.c_str(), error ? error.message().c_str() : "none");
     142              :         return ResourceStatus::IoError;
     143              :     }
     144              :     const std::string pattern = (parent / "aclrtc-resource-XXXXXX").string();
     145              :     std::vector<char> writable(pattern.begin(), pattern.end());
     146              :     writable.push_back('\0');
     147              :     char* created = mkdtemp(writable.data());
     148              :     if (created == nullptr) {
     149              :         ASCENDLOGE(
     150              :             "Failed to create compile resource temporary root: parent=%s error=%s", parent.c_str(),
     151              :             std::strerror(errno));
     152              :         return ResourceStatus::IoError;
     153              :     }
     154              :     const fs::path canonical = fs::canonical(created, error);
     155              :     if (error) {
     156              :         ASCENDLOGE(
     157              :             "Failed to resolve created compile resource temporary root: path=%s error=%s", created,
     158              :             error.message().c_str());
     159              :         CleanupPath(created);
     160              :         return ResourceStatus::IoError;
     161              :     }
     162              :     if (canonical != fs::path(created).lexically_normal()) {
     163              :         ASCENDLOGE(
     164              :             "Compile resource temporary root identity mismatch: expected=%s actual=%s", created, canonical.c_str());
     165              :         CleanupPath(created);
     166              :         return ResourceStatus::IoError;
     167              :     }
     168              :     temporaryRoot = canonical.string();
     169              :     ASCENDLOGI("Created compile resource temporary root: path=%s", temporaryRoot.c_str());
     170              :     return ResourceStatus::Success;
     171              : }
     172              : 
     173              : bool TryAddWithinLimit(uint64_t value, uint64_t limit, uint64_t& total) noexcept
     174              : {
     175              :     if (total > limit || value > limit - total) {
     176              :         return false;
     177              :     }
     178              :     total += value;
     179              :     return true;
     180              : }
     181              : 
     182              : ResourceStatus CopyString(const AcString& value, const char* field, uint64_t limit, std::string& output)
     183              : {
     184              :     if (value.size != 0U && value.data == nullptr) {
     185              :         ASCENDLOGE(
     186              :             "Compile resource string has null data: field=%s size=%" PRIu64 " expected=non-null data", field,
     187              :             value.size);
     188              :         return ResourceStatus::InvalidResource;
     189              :     }
     190              :     if (value.size > limit) {
     191              :         ASCENDLOGE(
     192              :             "Compile resource string exceeds size limit: field=%s actual=%" PRIu64 " limit=%" PRIu64, field, value.size,
     193              :             limit);
     194              :         return ResourceStatus::InvalidResource;
     195              :     }
     196              :     output.assign(value.size == 0U ? "" : value.data, value.size);
     197              :     return ResourceStatus::Success;
     198              : }
     199              : 
     200              : bool IsPlainName(const std::string& value)
     201              : {
     202              :     return !value.empty() && FileUtils::IsSafeRelativePath(value) && FileUtils::FileName(value) == value;
     203              : }
     204              : 
     205              : std::string Trim(const std::string& value)
     206              : {
     207              :     const size_t begin = value.find_first_not_of(" \t\r\n");
     208              :     if (begin == std::string::npos) {
     209              :         return {};
     210              :     }
     211              :     return value.substr(begin, value.find_last_not_of(" \t\r\n") - begin + 1U);
     212              : }
     213              : 
     214              : std::vector<std::string> SplitList(const char* value, char delimiter)
     215              : {
     216              :     std::vector<std::string> result;
     217              :     const std::string text(value == nullptr ? "" : value);
     218              :     size_t begin = 0U;
     219              :     while (begin <= text.size()) {
     220              :         const size_t end = text.find(delimiter, begin);
     221              :         const std::string item = Trim(text.substr(begin, end - begin));
     222              :         if (!item.empty() && std::find(result.begin(), result.end(), item) == result.end()) {
     223              :             result.push_back(item);
     224              :         }
     225              :         if (end == std::string::npos) {
     226              :             break;
     227              :         }
     228              :         begin = end + 1U;
     229              :     }
     230              :     return result;
     231              : }
     232              : 
     233              : ResourceStatus ValidateBundleHeader(const AcCompileResourceBundleHeader* header, const LibrarySpec& spec)
     234              : {
     235              :     if (header == nullptr) {
     236              :         ASCENDLOGE(
     237              :             "Compile resource bundle entry point returned null: source_type=%s so=%s", SourceTypeName(spec.sourceType),
     238              :             spec.path.c_str());
     239              :         return ResourceStatus::InvalidResource;
     240              :     }
     241              :     if (header->magic != AC_COMPILE_RESOURCE_MAGIC) {
     242              :         ASCENDLOGE(
     243              :             "Compile resource bundle magic mismatch: source_type=%s so=%s expected=0x%08x actual=0x%08x",
     244              :             SourceTypeName(spec.sourceType), spec.path.c_str(), AC_COMPILE_RESOURCE_MAGIC, header->magic);
     245              :         return ResourceStatus::InvalidResource;
     246              :     }
     247              :     if (header->abiVersion != AC_COMPILE_RESOURCE_ABI_VERSION) {
     248              :         ASCENDLOGE(
     249              :             "Compile resource bundle ABI version mismatch: source_type=%s so=%s expected=%u actual=%u",
     250              :             SourceTypeName(spec.sourceType), spec.path.c_str(), AC_COMPILE_RESOURCE_ABI_VERSION, header->abiVersion);
     251              :         return ResourceStatus::InvalidResource;
     252              :     }
     253              :     if (header->structSize != sizeof(AcCompileResourceBundle)) {
     254              :         ASCENDLOGE(
     255              :             "Compile resource bundle size mismatch: source_type=%s so=%s expected=%zu actual=%u",
     256              :             SourceTypeName(spec.sourceType), spec.path.c_str(), sizeof(AcCompileResourceBundle), header->structSize);
     257              :         return ResourceStatus::InvalidResource;
     258              :     }
     259              :     if (header->flags != 0U) {
     260              :         ASCENDLOGE(
     261              :             "Compile resource bundle has unsupported flags: source_type=%s so=%s expected=0 actual=0x%08x",
     262              :             SourceTypeName(spec.sourceType), spec.path.c_str(), header->flags);
     263              :         return ResourceStatus::InvalidResource;
     264              :     }
     265              :     return ResourceStatus::Success;
     266              : }
     267              : 
     268              : ResourceStatus ValidateManifestTable(const AcCompileResourceBundle& bundle, const LibrarySpec& spec)
     269              : {
     270              :     if (bundle.manifestCount == 0U) {
     271              :         ASCENDLOGE(
     272              :             "Compile resource bundle has no manifests: source_type=%s so=%s expected_count=1..%" PRIu64,
     273              :             SourceTypeName(spec.sourceType), spec.path.c_str(), MAX_MANIFEST_COUNT);
     274              :         return ResourceStatus::InvalidResource;
     275              :     }
     276              :     if (bundle.manifestCount > MAX_MANIFEST_COUNT) {
     277              :         ASCENDLOGE(
     278              :             "Compile resource manifest count exceeds limit: source_type=%s so=%s actual=%" PRIu64 " limit=%" PRIu64,
     279              :             SourceTypeName(spec.sourceType), spec.path.c_str(), bundle.manifestCount, MAX_MANIFEST_COUNT);
     280              :         return ResourceStatus::InvalidResource;
     281              :     }
     282              :     if (bundle.manifests == nullptr) {
     283              :         ASCENDLOGE(
     284              :             "Compile resource manifest table is null: source_type=%s so=%s count=%" PRIu64,
     285              :             SourceTypeName(spec.sourceType), spec.path.c_str(), bundle.manifestCount);
     286              :         return ResourceStatus::InvalidResource;
     287              :     }
     288              :     return ResourceStatus::Success;
     289              : }
     290              : 
     291              : ResourceStatus ValidateExtensionTable(const AcCompileResourceBundle& bundle, const LibrarySpec& spec)
     292              : {
     293              :     if (bundle.extensionCount == 0U) {
     294              :         if (bundle.extensions != nullptr) {
     295              :             ASCENDLOGE(
     296              :                 "Compile resource extension table is inconsistent: source_type=%s so=%s count=0 pointer=%p "
     297              :                 "expected=null",
     298              :                 SourceTypeName(spec.sourceType), spec.path.c_str(), static_cast<const void*>(bundle.extensions));
     299              :             return ResourceStatus::InvalidResource;
     300              :         }
     301              :         return ResourceStatus::Success;
     302              :     }
     303              :     if (bundle.extensionCount > MAX_EXTENSION_COUNT) {
     304              :         ASCENDLOGE(
     305              :             "Compile resource extension count exceeds limit: source_type=%s so=%s actual=%" PRIu64 " limit=%" PRIu64,
     306              :             SourceTypeName(spec.sourceType), spec.path.c_str(), bundle.extensionCount, MAX_EXTENSION_COUNT);
     307              :         return ResourceStatus::InvalidResource;
     308              :     }
     309              :     if (bundle.extensions == nullptr) {
     310              :         ASCENDLOGE(
     311              :             "Compile resource extension table is null: source_type=%s so=%s count=%" PRIu64,
     312              :             SourceTypeName(spec.sourceType), spec.path.c_str(), bundle.extensionCount);
     313              :         return ResourceStatus::InvalidResource;
     314              :     }
     315              :     for (uint64_t index = 0U; index < bundle.extensionCount; ++index) {
     316              :         const AcCompileResourceExtension& extension = bundle.extensions[index];
     317              :         const uint64_t unsupportedFlags = extension.flags & ~AC_COMPILE_RESOURCE_EXTENSION_REQUIRED;
     318              :         if (unsupportedFlags != 0U) {
     319              :             ASCENDLOGE(
     320              :                 "Compile resource extension has unsupported flags: source_type=%s so=%s extension=%" PRIu64
     321              :                 " type=%u version=%u flags=0x%" PRIx64 " supported_mask=0x%" PRIx64,
     322              :                 SourceTypeName(spec.sourceType), spec.path.c_str(), index, extension.type, extension.version,
     323              :                 extension.flags, static_cast<uint64_t>(AC_COMPILE_RESOURCE_EXTENSION_REQUIRED));
     324              :             return ResourceStatus::InvalidResource;
     325              :         }
     326              :         if (extension.dataSize != 0U && extension.data == nullptr) {
     327              :             ASCENDLOGE(
     328              :                 "Compile resource extension has null data: source_type=%s so=%s extension=%" PRIu64
     329              :                 " type=%u version=%u size=%" PRIu64 " expected=non-null data",
     330              :                 SourceTypeName(spec.sourceType), spec.path.c_str(), index, extension.type, extension.version,
     331              :                 extension.dataSize);
     332              :             return ResourceStatus::InvalidResource;
     333              :         }
     334              :         if ((extension.flags & AC_COMPILE_RESOURCE_EXTENSION_REQUIRED) != 0U) {
     335              :             ASCENDLOGE(
     336              :                 "Compile resource bundle requires an unsupported extension: source_type=%s so=%s extension=%" PRIu64
     337              :                 " type=%u version=%u",
     338              :                 SourceTypeName(spec.sourceType), spec.path.c_str(), index, extension.type, extension.version);
     339              :             return ResourceStatus::InvalidResource;
     340              :         }
     341              :     }
     342              :     return ResourceStatus::Success;
     343              : }
     344              : 
     345              : struct ManifestOwnership {
     346              :     Json document;
     347              :     std::string resourceId;
     348              :     std::string sourceFile;
     349              :     bool hasSourceFile = false;
     350              : };
     351              : 
     352              : ResourceStatus ParseResourceId(
     353              :     const Json& document, const LibrarySpec& spec, uint64_t manifestIndex, std::string& resourceId)
     354              : {
     355              :     if (!document.contains("resource_id")) {
     356              :         ASCENDLOGE(
     357              :             "Compile resource manifest is missing required field: source_type=%s so=%s manifest=%" PRIu64
     358              :             " field=resource_id",
     359              :             SourceTypeName(spec.sourceType), spec.path.c_str(), manifestIndex);
     360              :         return ResourceStatus::InvalidResource;
     361              :     }
     362              :     if (!document.at("resource_id").is_string()) {
     363              :         ASCENDLOGE(
     364              :             "Compile resource manifest field has invalid type: source_type=%s so=%s manifest=%" PRIu64
     365              :             " field=resource_id expected=string actual=%s",
     366              :             SourceTypeName(spec.sourceType), spec.path.c_str(), manifestIndex, document.at("resource_id").type_name());
     367              :         return ResourceStatus::InvalidResource;
     368              :     }
     369              :     resourceId = document.at("resource_id").get<std::string>();
     370           22 :     if (resourceId.empty()) {
     371              :         ASCENDLOGE(
     372              :             "Compile resource manifest field is empty: source_type=%s so=%s manifest=%" PRIu64
     373              :             " field=resource_id expected=non-empty string",
     374            2 :             SourceTypeName(spec.sourceType), spec.path.c_str(), manifestIndex);
     375            2 :         return ResourceStatus::InvalidResource;
     376              :     }
     377              :     return ResourceStatus::Success;
     378              : }
     379              : 
     380              : ResourceStatus ParseSourceFile(
     381              :     const Json& document, const LibrarySpec& spec, uint64_t manifestIndex, ManifestOwnership& ownership)
     382              : {
     383              :     ownership.hasSourceFile = document.contains("source_file");
     384              :     if (!ownership.hasSourceFile) {
     385              :         return ResourceStatus::Success;
     386              :     }
     387              :     if (!document.at("source_file").is_string()) {
     388              :         ASCENDLOGE(
     389              :             "Compile resource manifest field has invalid type: resource_id=%s source_type=%s so=%s manifest=%" PRIu64
     390              :             " field=source_file expected=string actual=%s",
     391              :             ownership.resourceId.c_str(), SourceTypeName(spec.sourceType), spec.path.c_str(), manifestIndex,
     392              :             document.at("source_file").type_name());
     393              :         return ResourceStatus::InvalidResource;
     394              :     }
     395              :     ownership.sourceFile = document.at("source_file").get<std::string>();
     396              :     if (!IsPlainName(ownership.sourceFile)) {
     397              :         ASCENDLOGE(
     398              :             "Compile resource manifest has unsafe source file name: resource_id=%s source_type=%s so=%s "
     399              :             "manifest=%" PRIu64 " source_file=%s expected=plain file name",
     400              :             ownership.resourceId.c_str(), SourceTypeName(spec.sourceType), spec.path.c_str(), manifestIndex,
     401              :             ownership.sourceFile.c_str());
     402              :         return ResourceStatus::InvalidResource;
     403              :     }
     404              :     return ResourceStatus::Success;
     405              : }
     406              : 
     407              : ResourceStatus ParseManifestOwnership(
     408              :     const AcCompileResourceManifest& unit, const LibrarySpec& spec, uint64_t manifestIndex,
     409              :     ManifestOwnership& ownership)
     410              : {
     411              :     std::string manifestText;
     412              :     ResourceStatus status = CopyString(unit.json, "manifest.json", MAX_MANIFEST_SIZE, manifestText);
     413              :     if (status != ResourceStatus::Success) {
     414              :         return status;
     415              :     }
     416              :     ownership.document = Json::parse(manifestText, nullptr, false);
     417              :     if (ownership.document.is_discarded()) {
     418              :         ASCENDLOGE(
     419              :             "Failed to parse compile resource manifest JSON: source_type=%s so=%s manifest=%" PRIu64
     420              :             " reason=malformed JSON",
     421              :             SourceTypeName(spec.sourceType), spec.path.c_str(), manifestIndex);
     422              :         return ResourceStatus::InvalidResource;
     423              :     }
     424              :     if (!ownership.document.is_object()) {
     425              :         ASCENDLOGE(
     426              :             "Compile resource manifest root has invalid type: source_type=%s so=%s manifest=%" PRIu64
     427              :             " expected=object actual=%s",
     428              :             SourceTypeName(spec.sourceType), spec.path.c_str(), manifestIndex, ownership.document.type_name());
     429              :         return ResourceStatus::InvalidResource;
     430              :     }
     431              :     status = ParseResourceId(ownership.document, spec, manifestIndex, ownership.resourceId);
     432              :     if (status != ResourceStatus::Success) {
     433              :         return status;
     434              :     }
     435              :     return ParseSourceFile(ownership.document, spec, manifestIndex, ownership);
     436              : }
     437              : 
     438              : ResourceStatus PrepareMaterializationRoot(
     439              :     const std::string& temporaryRoot, const std::string& resourceId, ResourceSourceType sourceType,
     440              :     std::string& categoryRoot, std::string& canonicalRoot)
     441              : {
     442              :     boost::system::error_code error;
     443              :     const fs::path randomComponent = fs::unique_path("materialize-%%%%%%%%%%%%%%%%", error);
     444              :     if (error || randomComponent.empty() || randomComponent.has_parent_path()) {
     445              :         ASCENDLOGE(
     446              :             "Failed to generate compile resource materialization path: resource_id=%s source_type=%s error=%s",
     447              :             resourceId.c_str(), SourceTypeName(sourceType), error ? error.message().c_str() : "invalid random path");
     448              :         return ResourceStatus::IoError;
     449              :     }
     450              :     const std::string categoryParent = FileUtils::JoinPath(temporaryRoot, SourceTypeName(sourceType));
     451              :     categoryRoot = FileUtils::JoinPath(categoryParent, randomComponent.string());
     452              :     if (!FileUtils::CreateDirectories(categoryRoot)) {
     453              :         ASCENDLOGE(
     454              :             "Failed to create compile resource materialization directory: resource_id=%s source_type=%s path=%s",
     455              :             resourceId.c_str(), SourceTypeName(sourceType), categoryRoot.c_str());
     456              :         return ResourceStatus::IoError;
     457              :     }
     458              :     const fs::path canonical = fs::canonical(categoryRoot, error);
     459              :     if (error) {
     460              :         ASCENDLOGE(
     461              :             "Failed to resolve compile resource materialization directory: resource_id=%s source_type=%s path=%s "
     462              :             "error=%s",
     463              :             resourceId.c_str(), SourceTypeName(sourceType), categoryRoot.c_str(), error.message().c_str());
     464              :         return ResourceStatus::IoError;
     465              :     }
     466              :     if (canonical != fs::path(categoryRoot).lexically_normal()) {
     467              :         ASCENDLOGE(
     468              :             "Compile resource materialization directory identity mismatch: resource_id=%s source_type=%s expected=%s "
     469              :             "actual=%s",
     470              :             resourceId.c_str(), SourceTypeName(sourceType), categoryRoot.c_str(), canonical.c_str());
     471              :         return ResourceStatus::IoError;
     472              :     }
     473              :     canonicalRoot = canonical.string();
     474              :     return ResourceStatus::Success;
     475              : }
     476              : 
     477              : ResourceStatus ResolveExplicitDiscoveryPath(const char* path, std::string& canonical)
     478              : {
     479              :     if (FileUtils::IsSymlink(path)) {
     480              :         ASCENDLOGE("Explicit compile resource SO must not be a symbolic link: path=%s expected=regular file", path);
     481              :         return ResourceStatus::InvalidResource;
     482              :     }
     483              :     if (!FileUtils::IsRegularFile(path)) {
     484              :         if (FileUtils::IsDirectory(path)) {
     485              :             ASCENDLOGE(
     486              :                 "Explicit compile resource path must be a regular SO file; directory input is unsupported: path=%s",
     487              :                 path);
     488              :         } else {
     489              :             ASCENDLOGE("Explicit compile resource path is not a regular SO file: path=%s", path);
     490              :         }
     491              :         return ResourceStatus::InvalidResource;
     492              :     }
     493              :     if (!FileUtils::ResolveCanonicalPath(path, canonical)) {
     494              :         ASCENDLOGE("Failed to resolve explicit compile resource SO: path=%s", path);
     495              :         return ResourceStatus::InvalidResource;
     496              :     }
     497              :     return ResourceStatus::Success;
     498              : }
     499              : 
     500              : ResourceStatus ValidateResourceFilePath(
     501              :     const std::string& resourceId, const std::string& fileName, const std::string& relativePath,
     502              :     std::set<std::string>& paths)
     503              : {
     504              :     if (!IsPlainName(fileName)) {
     505              :         ASCENDLOGE(
     506              :             "Compile resource file name is unsafe: resource_id=%s file_name=%s expected=plain file name",
     507              :             resourceId.c_str(), fileName.c_str());
     508              :         return ResourceStatus::InvalidResource;
     509              :     }
     510              :     if (!FileUtils::IsSafeRelativePath(relativePath)) {
     511              :         ASCENDLOGE(
     512              :             "Compile resource file path is unsafe: resource_id=%s path=%s expected=relative path without traversal",
     513              :             resourceId.c_str(), relativePath.c_str());
     514              :         return ResourceStatus::InvalidResource;
     515              :     }
     516              :     const std::string pathFileName = FileUtils::FileName(relativePath);
     517              :     if (pathFileName != fileName) {
     518              :         ASCENDLOGE(
     519              :             "Compile resource file name does not match its path: resource_id=%s file_name=%s path=%s "
     520              :             "path_file_name=%s",
     521              :             resourceId.c_str(), fileName.c_str(), relativePath.c_str(), pathFileName.c_str());
     522              :         return ResourceStatus::InvalidResource;
     523              :     }
     524              :     if (!paths.insert(relativePath).second) {
     525              :         ASCENDLOGE(
     526              :             "Compile resource file path is duplicated in manifest: resource_id=%s path=%s", resourceId.c_str(),
     527              :             relativePath.c_str());
     528              :         return ResourceStatus::InvalidResource;
     529              :     }
     530              :     return ResourceStatus::Success;
     531              : }
     532              : 
     533              : ResourceStatus ValidateResourceFilePayload(
     534              :     const AcCompileResourceFile& file, const std::string& resourceId, const std::string& relativePath,
     535              :     uint64_t& manifestBytes, StagedResources& staged)
     536              : {
     537              :     if (file.size > MAX_RESOURCE_FILE_SIZE) {
     538              :         ASCENDLOGE(
     539              :             "Compile resource file exceeds size limit: resource_id=%s path=%s actual=%" PRIu64 " limit=%" PRIu64,
     540              :             resourceId.c_str(), relativePath.c_str(), file.size, MAX_RESOURCE_FILE_SIZE);
     541              :         return ResourceStatus::InvalidResource;
     542              :     }
     543              :     if (file.size != 0U && file.data == nullptr) {
     544              :         ASCENDLOGE(
     545              :             "Compile resource file has null payload: resource_id=%s path=%s size=%" PRIu64 " expected=non-null data",
     546              :             resourceId.c_str(), relativePath.c_str(), file.size);
     547              :         return ResourceStatus::InvalidResource;
     548              :     }
     549              :     if (!TryAddWithinLimit(file.size, MAX_MANIFEST_RESOURCE_SIZE, manifestBytes)) {
     550              :         ASCENDLOGE(
     551              :             "Compile resource manifest payload exceeds size limit: resource_id=%s path=%s current=%" PRIu64
     552              :             " incoming=%" PRIu64 " limit=%" PRIu64,
     553              :             resourceId.c_str(), relativePath.c_str(), manifestBytes, file.size, MAX_MANIFEST_RESOURCE_SIZE);
     554              :         return ResourceStatus::InvalidResource;
     555              :     }
     556              :     if (!TryAddWithinLimit(file.size, MAX_REGISTRY_RESOURCE_SIZE, staged.bytes)) {
     557              :         ASCENDLOGE(
     558              :             "Staged compile resource payload exceeds registry size limit: resource_id=%s path=%s current=%" PRIu64
     559              :             " incoming=%" PRIu64 " limit=%" PRIu64,
     560              :             resourceId.c_str(), relativePath.c_str(), staged.bytes, file.size, MAX_REGISTRY_RESOURCE_SIZE);
     561              :         return ResourceStatus::InvalidResource;
     562              :     }
     563              :     return ResourceStatus::Success;
     564              : }
     565              : 
     566              : ResourceStatus ValidateManifestFileTable(
     567              :     const AcCompileResourceManifest& unit, const std::string& resourceId, const StagedResources& staged)
     568              : {
     569              :     if (unit.fileCount > MAX_FILE_COUNT) {
     570              :         ASCENDLOGE(
     571              :             "Compile resource manifest file count exceeds limit: resource_id=%s actual=%" PRIu64 " limit=%" PRIu64,
     572              :             resourceId.c_str(), unit.fileCount, MAX_FILE_COUNT);
     573              :         return ResourceStatus::InvalidResource;
     574              :     }
     575              :     if (unit.fileCount == 0U && unit.files != nullptr) {
     576              :         ASCENDLOGE(
     577              :             "Compile resource manifest has inconsistent file table: resource_id=%s count=0 pointer=%p "
     578              :             "expected_pointer=null",
     579              :             resourceId.c_str(), static_cast<const void*>(unit.files));
     580              :         return ResourceStatus::InvalidResource;
     581              :     }
     582              :     if (unit.fileCount != 0U && unit.files == nullptr) {
     583              :         ASCENDLOGE(
     584              :             "Compile resource manifest has inconsistent file table: resource_id=%s count=%" PRIu64
     585              :             " pointer=null expected_pointer=non-null",
     586              :             resourceId.c_str(), unit.fileCount);
     587              :         return ResourceStatus::InvalidResource;
     588              :     }
     589              :     if (staged.files > MAX_REGISTRY_FILE_COUNT || unit.fileCount > MAX_REGISTRY_FILE_COUNT - staged.files) {
     590              :         ASCENDLOGE(
     591              :             "Staged compile resource file count exceeds registry limit: resource_id=%s staged=%" PRIu64
     592              :             " incoming=%" PRIu64 " limit=%" PRIu64,
     593              :             resourceId.c_str(), staged.files, unit.fileCount, MAX_REGISTRY_FILE_COUNT);
     594              :         return ResourceStatus::InvalidResource;
     595              :     }
     596              :     return ResourceStatus::Success;
     597              : }
     598              : 
     599              : bool CheckRegistryLimits(const StagedResources& staged, ResourceSourceType sourceType, uint64_t& bytes, uint64_t& files)
     600              : {
     601              :     if (!staged.discovered || staged.conflict) {
     602              :         return true;
     603              :     }
     604              :     const uint64_t currentBytes = bytes;
     605              :     if (!TryAddWithinLimit(staged.bytes, MAX_REGISTRY_RESOURCE_SIZE, bytes)) {
     606              :         ASCENDLOGE(
     607              :             "Compile resource registry payload limit exceeded: source_type=%s current=%" PRIu64 " incoming=%" PRIu64
     608              :             " limit=%" PRIu64,
     609              :             SourceTypeName(sourceType), currentBytes, staged.bytes, MAX_REGISTRY_RESOURCE_SIZE);
     610              :         return false;
     611              :     }
     612              :     const uint64_t currentFiles = files;
     613              :     if (!TryAddWithinLimit(staged.files, MAX_REGISTRY_FILE_COUNT, files)) {
     614              :         ASCENDLOGE(
     615              :             "Compile resource registry file count limit exceeded: source_type=%s current=%" PRIu64 " incoming=%" PRIu64
     616              :             " limit=%" PRIu64,
     617              :             SourceTypeName(sourceType), currentFiles, staged.files, MAX_REGISTRY_FILE_COUNT);
     618              :         return false;
     619              :     }
     620              :     return true;
     621              : }
     622              : 
     623              : ResourceStatus MergeStagedLibrary(const LibrarySpec& spec, StagedResources& incoming, StagedResources& staged)
     624              : {
     625              :     for (const auto& item : incoming.resources) {
     626              :         const auto existing = staged.resources.find(item.first);
     627              :         if (existing != staged.resources.end()) {
     628              :             ASCENDLOGW(
     629              :                 "Skipping compile resource SO because its resource conflicts with an earlier SO: resource_id=%s "
     630              :                 "source_type=%s incoming_so=%s existing_so=%s",
     631              :                 item.first.c_str(), SourceTypeName(spec.sourceType), spec.path.c_str(),
     632              :                 existing->second->sourceSoPath.c_str());
     633              :             return ResourceStatus::Conflict;
     634              :         }
     635              :     }
     636              :     uint64_t bytes = staged.bytes;
     637              :     uint64_t files = staged.files;
     638              :     if (!TryAddWithinLimit(incoming.bytes, MAX_REGISTRY_RESOURCE_SIZE, bytes) ||
     639              :         !TryAddWithinLimit(incoming.files, MAX_REGISTRY_FILE_COUNT, files)) {
     640              :         ASCENDLOGW(
     641              :             "Skipping compile resource SO because cumulative staged resources exceed the registry limit: "
     642              :             "source_type=%s so=%s current_bytes=%" PRIu64 " incoming_bytes=%" PRIu64 " current_files=%" PRIu64
     643              :             " incoming_files=%" PRIu64,
     644              :             SourceTypeName(spec.sourceType), spec.path.c_str(), staged.bytes, incoming.bytes, staged.files,
     645              :             incoming.files);
     646              :         return ResourceStatus::InvalidResource;
     647              :     }
     648              :     staged.resources.merge(incoming.resources);
     649              :     staged.bytes = bytes;
     650              :     staged.files = files;
     651              :     return ResourceStatus::Success;
     652              : }
     653              : 
     654              : } // namespace
     655              : 
     656              : AutomaticRoots ResourceRegistry::AutomaticSearchRoots()
     657              : {
     658              :     AutomaticRoots roots;
     659              :     for (const std::string& path : SplitList(std::getenv("ASCEND_CUSTOM_OPP_PATH"), ':')) {
     660              :         roots.custom.push_back(FileUtils::JoinPath(path, RELATIVE_JIT_ROOT));
     661              :     }
     662              :     const char* environment = std::getenv("ASCEND_OPP_PATH");
     663              :     if (environment == nullptr || *environment == '\0') {
     664              :         ASCENDLOGD(
     665              :             "Automatic compile resource roots collected without built-in OPP path: custom_roots=%zu "
     666              :             "reason=ASCEND_OPP_PATH is unset",
     667              :             roots.custom.size());
     668              :         return roots;
     669              :     }
     670              :     std::string oppRoot;
     671              :     if (!FileUtils::ResolveCanonicalPath(environment, oppRoot)) {
     672              :         ASCENDLOGW(
     673              :             "Unable to normalize configured OPP root: path=%s; vendor and built-in discovery will be skipped",
     674              :             environment);
     675              :         return roots;
     676              :     }
     677              :     const std::string vendorConfig = FileUtils::JoinPath(oppRoot, "vendors/config.ini");
     678              :     std::string canonicalVendorConfig;
     679              :     if (!FileUtils::ResolveCanonicalPath(vendorConfig, canonicalVendorConfig)) {
     680              :         ASCENDLOGW(
     681              :             "Unable to normalize optional compile resource vendor configuration: path=%s; "
     682              :             "built-in discovery will continue",
     683              :             vendorConfig.c_str());
     684              :     } else {
     685              :         std::ifstream input(canonicalVendorConfig);
     686              :         if (!input.is_open()) {
     687              :             ASCENDLOGW(
     688              :                 "Unable to read optional compile resource vendor configuration: path=%s reason=open failed; "
     689              :                 "built-in discovery will continue",
     690              :                 canonicalVendorConfig.c_str());
     691              :         }
     692              :         std::string line;
     693              :         while (std::getline(input, line)) {
     694              :             const size_t separator = line.find('=');
     695              :             if (separator == std::string::npos || Trim(line.substr(0U, separator)) != "load_priority") {
     696              :                 continue;
     697              :             }
     698              :             for (const std::string& vendor : SplitList(line.substr(separator + 1U).c_str(), ',')) {
     699              :                 if (IsPlainName(vendor)) {
     700              :                     roots.custom.push_back(
     701              :                         FileUtils::JoinPath(FileUtils::JoinPath(oppRoot, "vendors/" + vendor), RELATIVE_JIT_ROOT));
     702              :                 } else {
     703              :                     ASCENDLOGW(
     704              :                         "Ignoring unsafe compile resource vendor name: path=%s vendor=%s expected=plain directory name",
     705              :                         canonicalVendorConfig.c_str(), vendor.c_str());
     706              :                 }
     707              :             }
     708              :             break;
     709              :         }
     710              :     }
     711              :     roots.builtIn.push_back(FileUtils::JoinPath(FileUtils::JoinPath(oppRoot, "built-in"), RELATIVE_JIT_ROOT));
     712              :     ASCENDLOGD(
     713              :         "Automatic compile resource roots collected: custom_roots=%zu built_in_roots=%zu opp_root=%s",
     714              :         roots.custom.size(), roots.builtIn.size(), oppRoot.c_str());
     715              :     return roots;
     716              : }
     717              : 
     718              : bool ResourceRegistry::IsLibraryName(const std::string& path)
     719              : {
     720              :     const std::string name = FileUtils::FileName(path);
     721              :     return name.size() > std::strlen("lib") + std::strlen(LIBRARY_NAME_SUFFIX) && name.rfind("lib", 0U) == 0U &&
     722              :            name.compare(
     723              :                name.size() - std::strlen(LIBRARY_NAME_SUFFIX), std::strlen(LIBRARY_NAME_SUFFIX), LIBRARY_NAME_SUFFIX) ==
     724              :                0;
     725              : }
     726              : 
     727              : void ResourceRegistry::AddLibrary(const std::string& path, std::set<std::string>& found)
     728              : {
     729              :     if (!IsLibraryName(path) || !FileUtils::IsRegularFile(path) || FileUtils::IsSymlink(path)) {
     730              :         return;
     731              :     }
     732              :     std::string canonical;
     733              :     if (!FileUtils::ResolveCanonicalPath(path, canonical)) {
     734              :         ASCENDLOGW("Ignoring compile resource SO with unresolved path: path=%s", path.c_str());
     735              :         return;
     736              :     }
     737              :     found.insert(canonical);
     738              : }
     739              : 
     740              : bool ResourceRegistry::CollectLibraries(
     741              :     const std::string& root, ResourceSourceType sourceType, bool recursive, std::set<std::string>& found)
     742              : {
     743              :     const size_t initialCount = found.size();
     744              :     ASCENDLOGD(
     745              :         "Scanning compile resource directory: source_type=%s root=%s recursive=%s", SourceTypeName(sourceType),
     746              :         root.c_str(), recursive ? "true" : "false");
     747              :     std::vector<std::string> pending = {root};
     748              :     boost::system::error_code error;
     749              :     while (!pending.empty()) {
     750              :         const std::string currentRoot = std::move(pending.back());
     751              :         pending.pop_back();
     752              :         fs::directory_iterator current(currentRoot, fs::directory_options::none, error);
     753              :         const fs::directory_iterator end;
     754              :         if (error) {
     755              :             ASCENDLOGE(
     756              :                 "Failed to scan compile resource directory: source_type=%s path=%s error=%s",
     757              :                 SourceTypeName(sourceType), currentRoot.c_str(), error.message().c_str());
     758              :             return false;
     759              :         }
     760              :         while (current != end) {
     761              :             const std::string path = current->path().string();
     762              :             AddLibrary(path, found);
     763              :             const fs::file_status status = recursive ? current->symlink_status(error) : fs::file_status();
     764              :             if (error) {
     765              :                 ASCENDLOGE(
     766              :                     "Failed to inspect compile resource path: source_type=%s path=%s error=%s",
     767              :                     SourceTypeName(sourceType), path.c_str(), error.message().c_str());
     768              :                 return false;
     769              :             }
     770              :             if (recursive && fs::is_directory(status)) {
     771              :                 pending.push_back(path);
     772              :             }
     773              :             current.increment(error);
     774              :             if (error) {
     775              :                 ASCENDLOGE(
     776              :                     "Failed to scan compile resource directory: source_type=%s path=%s error=%s",
     777              :                     SourceTypeName(sourceType), currentRoot.c_str(), error.message().c_str());
     778              :                 return false;
     779              :             }
     780              :         }
     781              :     }
     782              :     ASCENDLOGD(
     783              :         "Finished scanning compile resource directory: source_type=%s root=%s libraries_added=%zu",
     784              :         SourceTypeName(sourceType), root.c_str(), found.size() - initialCount);
     785              :     return true;
     786              : }
     787              : 
     788              : bool ResourceRegistry::CollectAutomaticLibraries(
     789              :     const std::vector<std::string>& roots, ResourceSourceType sourceType, std::set<std::string>& found)
     790              : {
     791              :     for (const std::string& root : roots) {
     792              :         if (!FileUtils::IsDirectory(root)) {
     793              :             ASCENDLOGD(
     794              :                 "Skipping missing automatic compile resource root: source_type=%s path=%s", SourceTypeName(sourceType),
     795              :                 root.c_str());
     796              :             continue;
     797              :         }
     798              :         if (!CollectLibraries(root, sourceType, true, found)) {
     799              :             return false;
     800              :         }
     801              :     }
     802              :     return true;
     803              : }
     804              : 
     805              : ResourceStatus ResourceRegistry::DiscoverLibraries(const char* directory, std::vector<LibrarySpec>& libraries)
     806              : {
     807              :     const bool automatic = directory == nullptr || *directory == '\0';
     808              :     ASCENDLOGI(
     809              :         "Discovering compile resource libraries: mode=%s path=%s", automatic ? "automatic" : "explicit",
     810              :         automatic ? "<environment>" : directory);
     811              :     if (!automatic) {
     812              :         std::string canonical;
     813              :         const ResourceStatus status = ResolveExplicitDiscoveryPath(directory, canonical);
     814              :         if (status != ResourceStatus::Success) {
     815              :             return status;
     816              :         }
     817              :         libraries.push_back({canonical, ResourceSourceType::External});
     818              :         ASCENDLOGI("Discovered explicit compile resource SO: path=%s", canonical.c_str());
     819              :         return ResourceStatus::Success;
     820              :     }
     821              :     const AutomaticRoots roots = AutomaticSearchRoots();
     822              :     std::set<std::string> custom;
     823              :     std::set<std::string> builtIn;
     824              :     if (!CollectAutomaticLibraries(roots.custom, ResourceSourceType::Custom, custom) ||
     825              :         !CollectAutomaticLibraries(roots.builtIn, ResourceSourceType::BuiltIn, builtIn)) {
     826              :         return ResourceStatus::IoError;
     827              :     }
     828              :     for (const std::string& path : custom) {
     829              :         libraries.push_back({path, ResourceSourceType::Custom});
     830              :     }
     831              :     for (const std::string& path : builtIn) {
     832              :         libraries.push_back({path, ResourceSourceType::BuiltIn});
     833              :     }
     834              :     if (libraries.empty()) {
     835              :         ASCENDLOGW(
     836              :             "No compile resource libraries found by automatic discovery: custom_roots=%zu built_in_roots=%zu "
     837              :             "pattern=lib*%s",
     838              :             roots.custom.size(), roots.builtIn.size(), LIBRARY_NAME_SUFFIX);
     839              :         return ResourceStatus::NotFound;
     840              :     }
     841              :     ASCENDLOGI(
     842              :         "Discovered compile resource libraries: mode=automatic custom=%zu built_in=%zu total=%zu", custom.size(),
     843              :         builtIn.size(), libraries.size());
     844              :     return ResourceStatus::Success;
     845              : }
     846              : 
     847              : ResourceStatus ResourceRegistry::GetBundle(
     848              :     const LibraryHandle& library, const LibrarySpec& spec, const AcCompileResourceBundle*& bundle)
     849              : {
     850              :     dlerror();
     851              :     const auto getter =
     852              :         reinterpret_cast<AscendcGetCompileResourceBundleFn>(dlsym(library.get(), "AscendcGetCompileResourceBundle"));
     853              :     const char* symbolError = dlerror();
     854              :     if (symbolError != nullptr || getter == nullptr) {
     855              :         ASCENDLOGE(
     856              :             "Failed to resolve compile resource bundle entry point: source_type=%s so=%s "
     857              :             "symbol=AscendcGetCompileResourceBundle error=%s",
     858              :             SourceTypeName(spec.sourceType), spec.path.c_str(),
     859              :             symbolError == nullptr ? "symbol resolved to null" : symbolError);
     860              :         return ResourceStatus::LoadError;
     861              :     }
     862              :     const AcCompileResourceBundleHeader* header = getter();
     863              :     ResourceStatus status = ValidateBundleHeader(header, spec);
     864              :     if (status != ResourceStatus::Success) {
     865              :         return status;
     866              :     }
     867              :     bundle = reinterpret_cast<const AcCompileResourceBundle*>(header);
     868              :     status = ValidateManifestTable(*bundle, spec);
     869              :     if (status == ResourceStatus::Success) {
     870              :         status = ValidateExtensionTable(*bundle, spec);
     871              :     }
     872              :     if (status == ResourceStatus::Success) {
     873              :         ASCENDLOGD(
     874              :             "Validated compile resource bundle: source_type=%s so=%s manifests=%" PRIu64 " extensions=%" PRIu64,
     875              :             SourceTypeName(spec.sourceType), spec.path.c_str(), bundle->manifestCount, bundle->extensionCount);
     876              :     }
     877              :     return status;
     878              : }
     879              : 
     880              : ResourceStatus ResourceRegistry::ResolveSourceRoot(
     881              :     const fs::path& searchRoot, const std::string& resourceId, std::string& canonicalRoot)
     882              : {
     883              :     boost::system::error_code error;
     884              :     const fs::file_status status = fs::symlink_status(searchRoot, error);
     885              :     if (error) {
     886              :         ASCENDLOGE(
     887              :             "Failed to inspect compile source root: resource_id=%s root=%s error=%s", resourceId.c_str(),
     888              :             searchRoot.c_str(), error.message().c_str());
     889              :         return error == boost::system::errc::no_such_file_or_directory ? ResourceStatus::InvalidResource :
     890              :                                                                          ResourceStatus::IoError;
     891              :     }
     892              :     if (fs::is_symlink(status)) {
     893              :         ASCENDLOGE(
     894              :             "Compile source root must not be a symbolic link: resource_id=%s root=%s", resourceId.c_str(),
     895              :             searchRoot.c_str());
     896              :         return ResourceStatus::InvalidResource;
     897              :     }
     898              :     if (!fs::is_directory(status)) {
     899              :         ASCENDLOGE(
     900              :             "Compile source root is not a directory: resource_id=%s root=%s", resourceId.c_str(), searchRoot.c_str());
     901              :         return ResourceStatus::InvalidResource;
     902              :     }
     903              :     const fs::path canonical = fs::canonical(searchRoot, error);
     904              :     if (error) {
     905              :         ASCENDLOGE(
     906              :             "Failed to resolve compile source root: resource_id=%s root=%s error=%s", resourceId.c_str(),
     907              :             searchRoot.c_str(), error.message().c_str());
     908              :         return ResourceStatus::IoError;
     909              :     }
     910              :     canonicalRoot = canonical.string();
     911              :     return ResourceStatus::Success;
     912              : }
     913              : 
     914              : ResourceStatus ResourceRegistry::AddSourceMatch(
     915              :     const fs::path& candidate, const std::string& sourceFile, const std::string& canonicalRoot,
     916              :     const std::string& resourceId, std::set<std::string>& matches)
     917              : {
     918              :     if (candidate.filename() != sourceFile) {
     919              :         return ResourceStatus::Success;
     920              :     }
     921              :     boost::system::error_code error;
     922              :     const fs::file_status status = fs::symlink_status(candidate, error);
     923              :     if (error) {
     924              :         ASCENDLOGE(
     925              :             "Failed to inspect compile source candidate: resource_id=%s path=%s error=%s", resourceId.c_str(),
     926              :             candidate.c_str(), error.message().c_str());
     927              :         return ResourceStatus::IoError;
     928              :     }
     929              :     if (!fs::is_regular_file(status)) {
     930              :         return ResourceStatus::Success;
     931              :     }
     932              :     const fs::path canonical = fs::canonical(candidate, error);
     933              :     if (error) {
     934              :         ASCENDLOGE(
     935              :             "Failed to resolve compile source candidate: resource_id=%s path=%s error=%s", resourceId.c_str(),
     936              :             candidate.c_str(), error.message().c_str());
     937              :         return ResourceStatus::IoError;
     938              :     }
     939              :     if (!FileUtils::IsPathWithin(canonical.string(), canonicalRoot)) {
     940              :         ASCENDLOGE(
     941              :             "Compile source candidate escaped root: resource_id=%s candidate=%s canonical=%s root=%s",
     942              :             resourceId.c_str(), candidate.c_str(), canonical.c_str(), canonicalRoot.c_str());
     943              :         return ResourceStatus::InvalidResource;
     944              :     }
     945              :     matches.insert(canonical.parent_path().string());
     946              :     return ResourceStatus::Success;
     947              : }
     948              : 
     949              : ResourceStatus ResourceRegistry::LocateSourceFile(
     950              :     const LibrarySpec& spec, const std::string& resourceId, const std::string& sourceFile, std::string& located)
     951              : {
     952              :     // Relative path example:
     953              :     //   kernel/jit/ascend910b/libfoo_compile_database.so  <- resource SO
     954              :     //   kernel/ascend910b/impl/foo.cpp                    <- source file
     955              :     // Derive the SoC and kernel root from the SO path, then recursively search the sibling kernel/<soc> tree.
     956              :     // Exactly one regular-file match is required; located is set to that file's parent directory.
     957              :     const fs::path soPath(spec.path);
     958              :     const fs::path soc = soPath.parent_path().filename();
     959              :     const fs::path jitRoot = soPath.parent_path().parent_path();
     960              :     const fs::path kernelRoot = jitRoot.parent_path();
     961              :     if (soc.empty() || jitRoot.filename() != "jit" || kernelRoot.filename() != "kernel") {
     962              :         ASCENDLOGE(
     963              :             "Compile resource SO is outside kernel/jit/<soc>: resource_id=%s source_type=%s so=%s", resourceId.c_str(),
     964              :             SourceTypeName(spec.sourceType), spec.path.c_str());
     965              :         return ResourceStatus::InvalidResource;
     966              :     }
     967              :     const fs::path searchRoot = kernelRoot / soc;
     968              :     std::string canonicalRoot;
     969              :     ResourceStatus status = ResolveSourceRoot(searchRoot, resourceId, canonicalRoot);
     970              :     if (status != ResourceStatus::Success) {
     971              :         return status;
     972              :     }
     973              :     std::set<std::string> matches;
     974              :     boost::system::error_code error;
     975              :     fs::recursive_directory_iterator current(canonicalRoot, fs::directory_options::none, error);
     976              :     const fs::recursive_directory_iterator end;
     977              :     while (!error && current != end) {
     978              :         status = AddSourceMatch(current->path(), sourceFile, canonicalRoot, resourceId, matches);
     979              :         if (status != ResourceStatus::Success) {
     980              :             return status;
     981              :         }
     982              :         current.increment(error);
     983              :     }
     984              :     if (error) {
     985              :         ASCENDLOGE(
     986              :             "Failed to search compile source: resource_id=%s root=%s error=%s", resourceId.c_str(), searchRoot.c_str(),
     987              :             error.message().c_str());
     988              :         return ResourceStatus::IoError;
     989              :     }
     990              :     if (matches.size() != 1U) {
     991              :         ASCENDLOGE(
     992              :             "Compile source file must have exactly one match: resource_id=%s root=%s source_file=%s actual_matches=%zu "
     993              :             "expected_matches=1",
     994              :             resourceId.c_str(), searchRoot.c_str(), sourceFile.c_str(), matches.size());
     995              :         return ResourceStatus::InvalidResource;
     996              :     }
     997              :     located = *matches.begin();
     998              :     ASCENDLOGD(
     999              :         "Located compile source file: resource_id=%s source_file=%s directory=%s", resourceId.c_str(),
    1000              :         sourceFile.c_str(), located.c_str());
    1001              :     return ResourceStatus::Success;
    1002              : }
    1003              : 
    1004              : bool ResourceRegistry::FindPathConflict(const std::set<std::string>& paths)
    1005              : {
    1006              :     for (const std::string& path : paths) {
    1007              :         size_t separator = path.find('/');
    1008              :         while (separator != std::string::npos) {
    1009              :             if (paths.count(path.substr(0U, separator)) != 0U) {
    1010              :                 const std::string parent = path.substr(0U, separator);
    1011              :                 ASCENDLOGE(
    1012              :                     "Compile resource file path conflicts with another file: parent=%s child=%s "
    1013              :                     "reason=a file cannot also be a directory",
    1014              :                     parent.c_str(), path.c_str());
    1015              :                 return true;
    1016              :             }
    1017              :             separator = path.find('/', separator + 1U);
    1018              :         }
    1019              :     }
    1020              :     return false;
    1021              : }
    1022              : 
    1023              : ResourceStatus ResourceRegistry::AppendFile(
    1024              :     const AcCompileResourceFile& file, const std::string& resourceId, ResourceEntry& entry,
    1025              :     std::set<std::string>& paths, uint64_t& manifestBytes, StagedResources& staged)
    1026              : {
    1027              :     std::string fileName;
    1028              :     std::string relativePath;
    1029              :     ResourceStatus status = CopyString(file.fileName, "resource.fileName", MAX_PATH_SIZE, fileName);
    1030              :     if (status == ResourceStatus::Success) {
    1031              :         status = CopyString(file.filePath, "resource.filePath", MAX_PATH_SIZE, relativePath);
    1032              :     }
    1033              :     if (status != ResourceStatus::Success) {
    1034              :         return status;
    1035              :     }
    1036              :     status = ValidateResourceFilePath(resourceId, fileName, relativePath, paths);
    1037              :     if (status == ResourceStatus::Success) {
    1038              :         status = ValidateResourceFilePayload(file, resourceId, relativePath, manifestBytes, staged);
    1039              :     }
    1040              :     if (status != ResourceStatus::Success) {
    1041              :         return status;
    1042              :     }
    1043              :     std::vector<uint8_t> bytes;
    1044              :     if (file.size != 0U) {
    1045              :         bytes.assign(file.data, file.data + file.size);
    1046              :     }
    1047              :     entry.files.push_back({std::move(fileName), std::move(relativePath), std::move(bytes)});
    1048              :     return ResourceStatus::Success;
    1049              : }
    1050              : 
    1051              : ResourceStatus ResourceRegistry::CopyManifestFiles(
    1052              :     const AcCompileResourceManifest& unit, const std::string& resourceId, ResourceEntry& entry, StagedResources& staged)
    1053              : {
    1054              :     const ResourceStatus tableStatus = ValidateManifestFileTable(unit, resourceId, staged);
    1055              :     if (tableStatus != ResourceStatus::Success) {
    1056              :         return tableStatus;
    1057              :     }
    1058              :     entry.files.reserve(static_cast<size_t>(unit.fileCount));
    1059              :     std::set<std::string> paths;
    1060              :     uint64_t manifestBytes = 0U;
    1061              :     for (uint64_t index = 0U; index < unit.fileCount; ++index) {
    1062              :         const ResourceStatus status = AppendFile(unit.files[index], resourceId, entry, paths, manifestBytes, staged);
    1063              :         if (status != ResourceStatus::Success) {
    1064              :             return status;
    1065              :         }
    1066              :     }
    1067              :     if (FindPathConflict(paths)) {
    1068              :         return ResourceStatus::InvalidResource;
    1069              :     }
    1070              :     staged.files += unit.fileCount;
    1071              :     std::sort(entry.files.begin(), entry.files.end(), [](const ResourceFileData& left, const ResourceFileData& right) {
    1072              :         return left.relativePath < right.relativePath;
    1073              :     });
    1074              :     ASCENDLOGD(
    1075              :         "Validated compile resource manifest files: resource_id=%s files=%" PRIu64 " bytes=%" PRIu64,
    1076              :         resourceId.c_str(), unit.fileCount, manifestBytes);
    1077              :     return ResourceStatus::Success;
    1078              : }
    1079              : 
    1080              : StagedResources& ResourceRegistry::SelectStagedResources(StageState& stage, ResourceSourceType sourceType)
    1081              : {
    1082              :     if (sourceType == ResourceSourceType::Custom) {
    1083              :         return stage.custom;
    1084              :     }
    1085              :     return sourceType == ResourceSourceType::BuiltIn ? stage.builtIn : stage.external;
    1086              : }
    1087              : 
    1088              : ResourceStatus ResourceRegistry::LoadManifest(
    1089              :     const AcCompileResourceManifest& unit, const LibrarySpec& spec, uint64_t manifestIndex, StageState& stage)
    1090              : {
    1091              :     ASCENDLOGI(
    1092              :         "Loading compile resource manifest: source_type=%s so=%s manifest=%" PRIu64, SourceTypeName(spec.sourceType),
    1093              :         spec.path.c_str(), manifestIndex);
    1094              :     ManifestOwnership ownership;
    1095              :     ResourceStatus status = ParseManifestOwnership(unit, spec, manifestIndex, ownership);
    1096              :     if (status != ResourceStatus::Success) {
    1097              :         return status;
    1098              :     }
    1099              :     std::unique_ptr<ResourceEntry> entry(new ResourceEntry());
    1100              :     if (ownership.hasSourceFile) {
    1101              :         status = LocateSourceFile(spec, ownership.resourceId, ownership.sourceFile, entry->data.sourceFilePath);
    1102              :     }
    1103              :     StagedResources& staged = SelectStagedResources(stage, spec.sourceType);
    1104              :     if (status == ResourceStatus::Success) {
    1105              :         status = CopyManifestFiles(unit, ownership.resourceId, *entry, staged);
    1106              :     }
    1107              :     if (status != ResourceStatus::Success) {
    1108              :         return status;
    1109              :     }
    1110              :     entry->data.json = std::move(ownership.document);
    1111              :     entry->sourceSoPath = spec.path;
    1112              :     entry->sourceType = spec.sourceType;
    1113              :     const auto existing = staged.resources.find(ownership.resourceId);
    1114              :     if (existing != staged.resources.end()) {
    1115              :         ASCENDLOGE(
    1116              :             "Duplicate resource_id in load transaction: resource_id=%s incoming_source_type=%s incoming_so=%s "
    1117              :             "existing_source_type=%s existing_so=%s",
    1118              :             ownership.resourceId.c_str(), SourceTypeName(entry->sourceType), entry->sourceSoPath.c_str(),
    1119              :             SourceTypeName(existing->second->sourceType), existing->second->sourceSoPath.c_str());
    1120              :         return ResourceStatus::Conflict;
    1121              :     }
    1122              :     const size_t fileCount = entry->files.size();
    1123              :     staged.resources.emplace(ownership.resourceId, std::move(entry));
    1124              :     ASCENDLOGI(
    1125              :         "Loaded compile resource manifest: resource_id=%s source_type=%s so=%s manifest=%" PRIu64 " files=%zu",
    1126              :         ownership.resourceId.c_str(), SourceTypeName(spec.sourceType), spec.path.c_str(), manifestIndex, fileCount);
    1127              :     return ResourceStatus::Success;
    1128              : }
    1129              : 
    1130              : ResourceStatus ResourceRegistry::LoadLibrary(const LibrarySpec& spec, StageState& stage)
    1131              : {
    1132              :     LibrarySpec canonicalSpec = spec;
    1133              :     if (!FileUtils::ResolveCanonicalPath(spec.path, canonicalSpec.path)) {
    1134              :         ASCENDLOGE(
    1135              :             "Failed to normalize compile resource SO path before loading: source_type=%s so=%s",
    1136              :             SourceTypeName(spec.sourceType), spec.path.c_str());
    1137              :         return ResourceStatus::InvalidResource;
    1138              :     }
    1139              :     ASCENDLOGI(
    1140              :         "Loading compile resource SO: source_type=%s so=%s", SourceTypeName(canonicalSpec.sourceType),
    1141              :         canonicalSpec.path.c_str());
    1142              :     LibraryHandle library(dlopen(canonicalSpec.path.c_str(), RTLD_NOW | RTLD_LOCAL));
    1143              :     if (!library) {
    1144              :         const char* error = dlerror();
    1145              :         ASCENDLOGE(
    1146              :             "Failed to open compile resource SO: source_type=%s so=%s error=%s",
    1147              :             SourceTypeName(canonicalSpec.sourceType), canonicalSpec.path.c_str(), error == nullptr ? "unknown" : error);
    1148              :         return ResourceStatus::LoadError;
    1149              :     }
    1150              :     const AcCompileResourceBundle* bundle = nullptr;
    1151              :     ResourceStatus status = GetBundle(library, canonicalSpec, bundle);
    1152              :     if (status != ResourceStatus::Success) {
    1153              :         return status;
    1154              :     }
    1155              :     for (uint64_t manifestIndex = 0U; manifestIndex < bundle->manifestCount; ++manifestIndex) {
    1156              :         status = LoadManifest(bundle->manifests[manifestIndex], canonicalSpec, manifestIndex, stage);
    1157              :         if (status != ResourceStatus::Success) {
    1158              :             ASCENDLOGE(
    1159              :                 "Stopped loading compile resource SO at manifest: source_type=%s so=%s manifest=%" PRIu64
    1160              :                 " status=%s(%d)",
    1161              :                 SourceTypeName(canonicalSpec.sourceType), canonicalSpec.path.c_str(), manifestIndex,
    1162              :                 ResourceStatusName(status), static_cast<int>(status));
    1163              :             return status;
    1164              :         }
    1165              :     }
    1166              :     ASCENDLOGI(
    1167              :         "Loaded compile resource SO: source_type=%s so=%s manifests=%" PRIu64, SourceTypeName(canonicalSpec.sourceType),
    1168              :         canonicalSpec.path.c_str(), bundle->manifestCount);
    1169              :     return ResourceStatus::Success;
    1170              : }
    1171              : 
    1172              : ResourceStatus ResourceRegistry::LoadLibraries(const std::vector<LibrarySpec>& libraries, StageState& stage)
    1173              : {
    1174              :     ASCENDLOGI("Loading compile resource SO list: count=%zu", libraries.size());
    1175              :     size_t loaded = 0U;
    1176              :     size_t skipped = 0U;
    1177              :     ResourceStatus firstFailure = ResourceStatus::Success;
    1178              :     for (const LibrarySpec& library : libraries) {
    1179              :         StagedResources& staged = SelectStagedResources(stage, library.sourceType);
    1180              :         staged.discovered = true;
    1181              :         StageState libraryStage;
    1182              :         StagedResources& incoming = SelectStagedResources(libraryStage, library.sourceType);
    1183              :         incoming.discovered = true;
    1184              :         ResourceStatus status = LoadLibrary(library, libraryStage);
    1185              :         if (status == ResourceStatus::Success) {
    1186              :             status = MergeStagedLibrary(library, incoming, staged);
    1187              :         }
    1188              :         if (status != ResourceStatus::Success) {
    1189              :             if (firstFailure == ResourceStatus::Success) {
    1190              :                 firstFailure = status;
    1191              :             }
    1192              :             ++skipped;
    1193              :             ASCENDLOGW(
    1194              :                 "Skipping failed compile resource SO and continuing with the next SO: source_type=%s so=%s "
    1195              :                 "status=%s(%d)",
    1196              :                 SourceTypeName(library.sourceType), library.path.c_str(), ResourceStatusName(status),
    1197              :                 static_cast<int>(status));
    1198              :             continue;
    1199              :         }
    1200              :         ++loaded;
    1201              :     }
    1202              :     if (loaded == 0U && !libraries.empty()) {
    1203              :         ASCENDLOGW(
    1204              :             "No compile resource SO was loaded successfully: total=%zu skipped=%zu first_failure=%s(%d)",
    1205              :             libraries.size(), skipped, ResourceStatusName(firstFailure), static_cast<int>(firstFailure));
    1206              :         return firstFailure;
    1207              :     }
    1208              :     ASCENDLOGI("Loaded compile resource SO list: total=%zu loaded=%zu skipped=%zu", libraries.size(), loaded, skipped);
    1209              :     return ResourceStatus::Success;
    1210              : }
    1211              : 
    1212              : ResourceStatus ResourceRegistry::WriteMaterializedFiles(
    1213              :     const std::vector<ResourceFileData>& files, const std::string& root)
    1214              : {
    1215              :     ASCENDLOGD("Writing materialized compile resource files: root=%s files=%zu", root.c_str(), files.size());
    1216              :     for (const ResourceFileData& file : files) {
    1217              :         const std::string path = FileUtils::JoinPath(root, file.relativePath);
    1218              :         const std::string parent = FileUtils::ParentPath(path);
    1219              :         if (!FileUtils::CreateDirectories(parent)) {
    1220              :             ASCENDLOGE(
    1221              :                 "Failed to create materialized compile resource parent directory: root=%s relative_path=%s "
    1222              :                 "parent=%s",
    1223              :                 root.c_str(), file.relativePath.c_str(), parent.c_str());
    1224              :             return ResourceStatus::IoError;
    1225              :         }
    1226              :         std::string canonicalRoot;
    1227              :         std::string canonicalParent;
    1228              :         if (!FileUtils::ResolveCanonicalPath(root, canonicalRoot) ||
    1229              :             !FileUtils::ResolveCanonicalPath(parent, canonicalParent)) {
    1230              :             ASCENDLOGE(
    1231              :                 "Failed to normalize materialized compile resource output path: root=%s relative_path=%s parent=%s",
    1232              :                 root.c_str(), file.relativePath.c_str(), parent.c_str());
    1233              :             return ResourceStatus::IoError;
    1234              :         }
    1235              :         if (!FileUtils::IsPathWithin(canonicalParent, canonicalRoot)) {
    1236              :             ASCENDLOGE(
    1237              :                 "Rejected materialized compile resource output outside its root: root=%s resolved_root=%s "
    1238              :                 "relative_path=%s resolved_parent=%s",
    1239              :                 root.c_str(), canonicalRoot.c_str(), file.relativePath.c_str(), canonicalParent.c_str());
    1240              :             return ResourceStatus::IoError;
    1241              :         }
    1242              :         const std::string canonicalPath = FileUtils::JoinPath(canonicalParent, FileUtils::FileName(file.relativePath));
    1243              :         errno = 0;
    1244              :         std::ofstream output(canonicalPath.c_str(), std::ios::binary | std::ios::trunc);
    1245              :         if (!output.is_open()) {
    1246              :             const int openError = errno;
    1247              :             ASCENDLOGE(
    1248              :                 "Failed to open materialized compile resource file: root=%s relative_path=%s path=%s error=%s",
    1249              :                 root.c_str(), file.relativePath.c_str(), canonicalPath.c_str(),
    1250              :                 openError == 0 ? "stream open failed" : std::strerror(openError));
    1251              :             return ResourceStatus::IoError;
    1252              :         }
    1253              :         if (!file.bytes.empty()) {
    1254              :             output.write(
    1255              :                 reinterpret_cast<const char*>(file.bytes.data()), static_cast<std::streamsize>(file.bytes.size()));
    1256              :         }
    1257              :         if (!FileUtils::FinalizeOutput(output)) {
    1258              :             ASCENDLOGE(
    1259              :                 "Failed to finalize materialized compile resource file: root=%s relative_path=%s path=%s "
    1260              :                 "reason=write, flush, or close failed",
    1261              :                 root.c_str(), file.relativePath.c_str(), canonicalPath.c_str());
    1262              :             return ResourceStatus::IoError;
    1263              :         }
    1264              :     }
    1265              :     ASCENDLOGD("Wrote materialized compile resource files: root=%s files=%zu", root.c_str(), files.size());
    1266              :     return ResourceStatus::Success;
    1267              : }
    1268              : 
    1269              : ResourceRegistry& ResourceRegistry::Instance()
    1270              : {
    1271              :     static ResourceRegistry registry;
    1272              :     return registry;
    1273              : }
    1274              : 
    1275              : ResourceRegistry::ResourceRegistry() = default;
    1276              : 
    1277              : ResourceRegistry::~ResourceRegistry()
    1278              : {
    1279              :     if (!keepTemporaryRoot_) {
    1280              :         CleanupPath(temporaryRoot_);
    1281              :     }
    1282              : }
    1283              : 
    1284              : ResourceEntry* ResourceRegistry::FindResource(const std::string& resourceId) noexcept
    1285              : {
    1286              :     const auto external = externalResources_.find(resourceId);
    1287              :     if (external != externalResources_.end()) {
    1288              :         return external->second.get();
    1289              :     }
    1290              :     const auto custom = customResources_.find(resourceId);
    1291              :     if (custom != customResources_.end()) {
    1292              :         return custom->second.get();
    1293              :     }
    1294              :     const auto builtIn = builtInResources_.find(resourceId);
    1295              :     return builtIn == builtInResources_.end() ? nullptr : builtIn->second.get();
    1296              : }
    1297              : 
    1298              : bool ResourceRegistry::HasCommitConflict(const ResourceStore& incoming, const ResourceStore& committed) const
    1299              : {
    1300              :     for (const auto& item : incoming) {
    1301              :         const auto existing = committed.find(item.first);
    1302              :         if (existing != committed.end()) {
    1303              :             ASCENDLOGW(
    1304              :                 "Compile resource conflicts with an already registered resource and will not be added: "
    1305              :                 "resource_id=%s incoming_source_type=%s incoming_so=%s "
    1306              :                 "existing_source_type=%s existing_so=%s",
    1307              :                 item.first.c_str(), SourceTypeName(item.second->sourceType), item.second->sourceSoPath.c_str(),
    1308              :                 SourceTypeName(existing->second->sourceType), existing->second->sourceSoPath.c_str());
    1309              :             return true;
    1310              :         }
    1311              :     }
    1312              :     return false;
    1313              : }
    1314              : 
    1315              : ResourceStatus ResourceRegistry::Commit(StageState& stage)
    1316              : {
    1317              :     std::lock_guard<std::mutex> lock(registryMutex_);
    1318              :     ASCENDLOGI(
    1319              :         "Committing compile resources: external=%zu custom=%zu built_in=%zu", stage.external.resources.size(),
    1320              :         stage.custom.resources.size(), stage.builtIn.resources.size());
    1321              :     ResourceStatus status = ResourceStatus::Success;
    1322              :     auto checkCategory = [this, &status](
    1323              :                              StagedResources& staged, ResourceStore& committed, ResourceSourceType sourceType) {
    1324              :         if (!staged.discovered && !staged.conflict) {
    1325              :             return;
    1326              :         }
    1327              :         if (!staged.conflict && HasCommitConflict(staged.resources, committed)) {
    1328              :             staged.conflict = true;
    1329              :         }
    1330              :         if (staged.conflict) {
    1331              :             ASCENDLOGW(
    1332              :                 "Compile resource category will not be committed because conflicts were detected: source_type=%s "
    1333              :                 "resource_count=%zu",
    1334              :                 SourceTypeName(sourceType), staged.resources.size());
    1335              :             status = ResourceStatus::Conflict;
    1336              :             return;
    1337              :         }
    1338              :         committed.reserve(committed.size() + staged.resources.size());
    1339              :     };
    1340              :     checkCategory(stage.external, externalResources_, ResourceSourceType::External);
    1341              :     checkCategory(stage.custom, customResources_, ResourceSourceType::Custom);
    1342              :     checkCategory(stage.builtIn, builtInResources_, ResourceSourceType::BuiltIn);
    1343              :     uint64_t bytes = resourceBytes_;
    1344              :     uint64_t files = resourceFileCount_;
    1345              :     if (!CheckRegistryLimits(stage.external, ResourceSourceType::External, bytes, files) ||
    1346              :         !CheckRegistryLimits(stage.custom, ResourceSourceType::Custom, bytes, files) ||
    1347              :         !CheckRegistryLimits(stage.builtIn, ResourceSourceType::BuiltIn, bytes, files)) {
    1348              :         return ResourceStatus::InvalidResource;
    1349              :     }
    1350              :     auto commitCategory = [](StagedResources& staged, ResourceStore& committed) {
    1351              :         if (!staged.discovered || staged.conflict) {
    1352              :             return;
    1353              :         }
    1354              :         committed.merge(staged.resources);
    1355              :     };
    1356              :     commitCategory(stage.external, externalResources_);
    1357              :     commitCategory(stage.custom, customResources_);
    1358              :     commitCategory(stage.builtIn, builtInResources_);
    1359              :     resourceBytes_ = bytes;
    1360              :     resourceFileCount_ = files;
    1361              :     ASCENDLOGI(
    1362              :         "Finished committing compile resources: status=%s(%d) registered_external=%zu registered_custom=%zu "
    1363              :         "registered_built_in=%zu total_files=%" PRIu64 " total_bytes=%" PRIu64,
    1364              :         ResourceStatusName(status), static_cast<int>(status), externalResources_.size(), customResources_.size(),
    1365              :         builtInResources_.size(), resourceFileCount_, resourceBytes_);
    1366              :     return status;
    1367              : }
    1368              : 
    1369              : ResourceStatus ResourceRegistry::Load(const char* directory)
    1370              : {
    1371              :     const bool automatic = directory == nullptr || *directory == '\0';
    1372              :     std::lock_guard<std::mutex> loadLock(loadMutex_);
    1373              :     if (automatic && automaticLoadAttempted_) {
    1374              :         ASCENDLOGI(
    1375              :             "Returning cached automatic compile resource load result: status=%s(%d)",
    1376              :             ResourceStatusName(automaticLoadStatus_), static_cast<int>(automaticLoadStatus_));
    1377              :         return automaticLoadStatus_;
    1378              :     }
    1379              :     ASCENDLOGI(
    1380              :         "Loading compile resources: mode=%s directory=%s", automatic ? "automatic" : "explicit",
    1381              :         automatic ? "<environment>" : directory);
    1382              :     std::vector<LibrarySpec> libraries;
    1383              :     ResourceStatus status = DiscoverLibraries(directory, libraries);
    1384              :     if (status != ResourceStatus::Success) {
    1385              :         ASCENDLOGE(
    1386              :             "Compile resource load stopped during discovery: mode=%s path=%s status=%s(%d)",
    1387              :             automatic ? "automatic" : "explicit", automatic ? "<environment>" : directory, ResourceStatusName(status),
    1388              :             static_cast<int>(status));
    1389              :     } else {
    1390              :         ASCENDLOGI(
    1391              :             "Compile resource discovery completed: mode=%s libraries=%zu", automatic ? "automatic" : "explicit",
    1392              :             libraries.size());
    1393              :         StageState stage;
    1394              :         status = LoadLibraries(libraries, stage);
    1395              :         if (status == ResourceStatus::Success) {
    1396              :             status = Commit(stage);
    1397              :         }
    1398              :     }
    1399              :     if (automatic) {
    1400              :         automaticLoadAttempted_ = true;
    1401              :         automaticLoadStatus_ = status;
    1402              :     }
    1403              :     if (status == ResourceStatus::Success) {
    1404              :         ASCENDLOGI(
    1405              :             "Finished loading compile resources: mode=%s libraries=%zu status=%s(%d)",
    1406              :             automatic ? "automatic" : "explicit", libraries.size(), ResourceStatusName(status),
    1407              :             static_cast<int>(status));
    1408              :     }
    1409              :     return status;
    1410              : }
    1411              : 
    1412              : ResourceStatus ResourceRegistry::Materialize(
    1413              :     const std::string& resourceId, const ResourceEntry& entry, ResourceData& resource)
    1414              : {
    1415              :     ASCENDLOGI(
    1416              :         "Materializing compile resource: resource_id=%s source_type=%s so=%s files=%zu", resourceId.c_str(),
    1417              :         SourceTypeName(entry.sourceType), entry.sourceSoPath.c_str(), entry.files.size());
    1418              :     std::string temporaryRoot;
    1419              :     {
    1420              :         std::lock_guard<std::mutex> lock(registryMutex_);
    1421              :         if (temporaryRoot_.empty()) {
    1422              :             keepTemporaryRoot_ = IsKernelMetaSavingEnabled();
    1423              :             const ResourceStatus status = CreateTemporaryRoot(temporaryRoot_);
    1424              :             if (status != ResourceStatus::Success) {
    1425              :                 return status;
    1426              :             }
    1427              :         }
    1428              :         temporaryRoot = temporaryRoot_;
    1429              :     }
    1430              :     ASCENDLOGD(
    1431              :         "Compile resource temporary root is ready: resource_id=%s path=%s", resourceId.c_str(), temporaryRoot.c_str());
    1432              :     std::string categoryRoot;
    1433              :     std::string canonicalRoot;
    1434              :     ResourceStatus status =
    1435              :         PrepareMaterializationRoot(temporaryRoot, resourceId, entry.sourceType, categoryRoot, canonicalRoot);
    1436              :     if (status == ResourceStatus::Success) {
    1437              :         ASCENDLOGD(
    1438              :             "Compile resource materialization directory is ready: resource_id=%s path=%s", resourceId.c_str(),
    1439              :             canonicalRoot.c_str());
    1440              :         status = WriteMaterializedFiles(entry.files, canonicalRoot);
    1441              :     }
    1442              :     if (status != ResourceStatus::Success) {
    1443              :         if (!keepTemporaryRoot_) {
    1444              :             CleanupPath(categoryRoot);
    1445              :         }
    1446              :         resource.resourceDir.clear();
    1447              :         return status;
    1448              :     }
    1449              :     resource.resourceDir = canonicalRoot;
    1450              :     ASCENDLOGI(
    1451              :         "Compile resource materialized: resource_id=%s source_type=%s so=%s files=%zu directory=%s", resourceId.c_str(),
    1452              :         SourceTypeName(entry.sourceType), entry.sourceSoPath.c_str(), entry.files.size(), resource.resourceDir.c_str());
    1453              :     return ResourceStatus::Success;
    1454              : }
    1455              : 
    1456              : ResourceStatus ResourceRegistry::Lookup(const char* resourceId, ResourceData& resource)
    1457              : {
    1458              :     resource = ResourceData{};
    1459              :     if (resourceId == nullptr) {
    1460              :         ASCENDLOGE("Compile resource lookup rejected: resource_id=<null> reason=identifier pointer is null");
    1461              :         return ResourceStatus::InvalidResource;
    1462              :     }
    1463              :     if (*resourceId == '\0') {
    1464              :         ASCENDLOGE("Compile resource lookup rejected: resource_id=<empty> reason=identifier is empty");
    1465              :         return ResourceStatus::InvalidResource;
    1466              :     }
    1467              :     ASCENDLOGD("Looking up compile resource: resource_id=%s", resourceId);
    1468              :     ResourceEntry* entry = nullptr;
    1469              :     {
    1470              :         std::lock_guard<std::mutex> lock(registryMutex_);
    1471              :         entry = FindResource(resourceId);
    1472              :     }
    1473              :     if (entry == nullptr) {
    1474              :         ASCENDLOGD("Compile resource lookup missed: resource_id=%s reason=not registered", resourceId);
    1475              :         return ResourceStatus::NotFound;
    1476              :     }
    1477              :     ASCENDLOGD(
    1478              :         "Compile resource lookup matched: resource_id=%s source_type=%s so=%s", resourceId,
    1479              :         SourceTypeName(entry->sourceType), entry->sourceSoPath.c_str());
    1480              :     std::lock_guard<std::mutex> materializeLock(entry->materializeMutex);
    1481              :     ResourceData materialized = entry->data;
    1482              :     materialized.resourceDir.clear();
    1483              :     const ResourceStatus status = Materialize(resourceId, *entry, materialized);
    1484              :     if (status == ResourceStatus::Success) {
    1485              :         resource = std::move(materialized);
    1486              :         ASCENDLOGD(
    1487              :             "Compile resource lookup completed: resource_id=%s directory=%s", resourceId, resource.resourceDir.c_str());
    1488              :     }
    1489              :     return status;
    1490              : }
    1491              : 
    1492              : } // namespace specialization_compile
    1493              : } // namespace ascendc
        

Generated by: LCOV version 2.0-1