* -------------------------------------------------------------------------
* This file is part of the MindStudio project.
* Copyright (c) 2026 Huawei Technologies Co.,Ltd.
*
* MindStudio is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan
* PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the
* Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*/
#include "QueryMemSnapshotDetailHandler.h"
#include "MemSnapshotDefs.h"
#include "MemSnapshotService.h"
#include "MemSnapshotStateCache.h"
#include "SegmentSummaryCalculator.h"
#include "DataBaseManager.h"
#include <algorithm>
using namespace Dic::Module::MemSnapshot;
namespace Dic::Module::MemSnapshot {
bool QueryMemSnapshotDetailHandler::HandleRequest(std::unique_ptr<Protocol::Request> requestPtr) {
auto &request = dynamic_cast<MemSnapshotDetailRequest &>(*requestPtr);
std::unique_ptr<MemSnapshotDetailResponse> responsePtr = std::make_unique<MemSnapshotDetailResponse>();
auto &response = *responsePtr;
response.type = request.params.type;
SetBaseResponse(request, response);
std::string errMsg;
if (!request.params.CommonCheck(errMsg)) {
SendResponse(std::move(responsePtr), false, errMsg);
return false;
}
const auto database = GetMemSnapshotDatabaseByRequest(request);
if (database == nullptr || !database->IsOpen()) {
errMsg = LOG_TAG + "Failed to query detail: get database connection failed";
SendResponse(std::move(responsePtr), false, errMsg);
return false;
}
if (request.params.type == DETAIL_TYPE_BLOCK) {
auto block = database->QueryBlockById(request.params.id, request.params.deviceId);
if (!block.has_value()) {
errMsg =
LOG_TAG + "Failed to query block detail: block not found with id " + std::to_string(request.params.id);
SendResponse(std::move(responsePtr), false, errMsg);
return false;
}
auto blockDetail = std::make_unique<BlockDetailDTO>(block.value());
BuildBlockDetailDTO(*blockDetail, request.params.deviceId, database);
response.detail = std::move(blockDetail);
} else if (request.params.type == DETAIL_TYPE_EVENT) {
auto event = database->QueryTraceEntryById(request.params.id, request.params.deviceId);
if (!event.has_value()) {
errMsg =
LOG_TAG + "Failed to query event detail: event not found with id " + std::to_string(request.params.id);
SendResponse(std::move(responsePtr), false, errMsg);
return false;
}
response.detail = std::make_unique<TraceEntryDetailDTO>(event.value());
} else if (request.params.type == DETAIL_TYPE_SEGMENT) {
auto segmentDetail = BuildSegmentDetailDTO(request, database, errMsg);
if (segmentDetail == nullptr) {
SendResponse(std::move(responsePtr), false, errMsg);
return false;
}
response.detail = std::move(segmentDetail);
}
SendResponse(std::move(responsePtr), true);
return true;
}
void QueryMemSnapshotDetailHandler::BuildBlockDetailDTO(BlockDetailDTO &blockDetail, const std::string &deviceId,
const std::shared_ptr<FullDb::MemSnapshotDatabase> &database) {
if (blockDetail.allocEventId > 0) {
if (auto allocEntry = database->QueryTraceEntryById(blockDetail.allocEventId, deviceId);
allocEntry.has_value()) {
blockDetail.allocEvent = std::make_optional<TraceEntryDetailDTO>(allocEntry.value());
}
}
if (blockDetail.freeEventId > 0) {
if (auto freeCompletedEntry = database->QueryTraceEntryById(blockDetail.freeEventId, deviceId);
freeCompletedEntry.has_value()) {
blockDetail.freeCompletedEvent = std::make_optional<TraceEntryDetailDTO>(freeCompletedEntry.value());
}
}
if (auto freeRequestEntry = database->QueryFreeRequestedTraceEntryByBlock(blockDetail, deviceId);
freeRequestEntry.has_value()) {
blockDetail.freeRequestedEvent = std::make_optional<TraceEntryDetailDTO>(freeRequestEntry.value());
}
}
std::unique_ptr<Protocol::SegmentDetailDTO> QueryMemSnapshotDetailHandler::BuildSegmentDetailDTO(
const Protocol::MemSnapshotDetailRequest &request, const std::shared_ptr<FullDb::MemSnapshotDatabase> &database,
std::string &errMsg) {
uint64_t segmentAddress = 0;
if (!ParseSegmentAddress(request.params.segmentAddress, segmentAddress)) {
errMsg = "Failed to query segment detail: invalid segmentAddress " + request.params.segmentAddress;
return nullptr;
}
const auto dataKey = GetMemSnapshotDataKey(request);
auto cachedSegments = MemSnapshotStateCache::Get(dataKey, request.params.deviceId, request.params.eventId);
std::vector<Segment> segments;
if (cachedSegments.has_value()) {
segments = cachedSegments.value();
} else {
segments = MemSnapshotService::GetSegmentsByEventId(request.params.eventId, request.params.deviceId, database);
MemSnapshotStateCache::Put(dataKey, request.params.deviceId, request.params.eventId, segments);
}
auto segmentIter = std::find_if(segments.begin(), segments.end(), [&](const Segment &segment) {
return segment.address == segmentAddress && segment.stream == request.params.stream;
});
if (segmentIter == segments.end()) {
errMsg = LOG_TAG + "Failed to query segment detail: segment not found";
return nullptr;
}
auto segmentDetail =
std::make_unique<Protocol::SegmentDetailDTO>(*segmentIter, ComputeSegmentSummary(*segmentIter));
if (segmentIter->allocOrMapEventId >= 0) {
if (auto event = database->QueryTraceEntryById(segmentIter->allocOrMapEventId, request.params.deviceId);
event.has_value()) {
segmentDetail->allocOrMapEvent = std::make_optional<TraceEntryDetailDTO>(event.value());
}
}
return segmentDetail;
}
bool QueryMemSnapshotDetailHandler::ParseSegmentAddress(const std::string &address, uint64_t &value) {
try {
size_t parsed = 0;
value = std::stoull(address, &parsed, 0);
return parsed == address.size();
} catch (std::invalid_argument &) {
return false;
} catch (std::out_of_range &) {
return false;
}
}
}