Step 567: add leak corruption signal bridge
This commit is contained in:
154
editor/src/LeakCorruptionSignalBridge.h
Normal file
154
editor/src/LeakCorruptionSignalBridge.h
Normal file
@@ -0,0 +1,154 @@
|
||||
#pragma once
|
||||
// Step 567: Leak/Corruption Signal Bridge
|
||||
|
||||
#include "DebugValidationUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
enum class MemorySignalType {
|
||||
LeakSuspected,
|
||||
LeakConfirmed,
|
||||
CorruptionSuspected,
|
||||
CorruptionConfirmed
|
||||
};
|
||||
|
||||
enum class MemorySignalSeverity {
|
||||
Info = 0,
|
||||
Warning = 1,
|
||||
Error = 2,
|
||||
Critical = 3
|
||||
};
|
||||
|
||||
struct MemorySignalRecord {
|
||||
std::string signalId;
|
||||
std::string sessionId;
|
||||
std::string allocationId;
|
||||
MemorySignalType type = MemorySignalType::LeakSuspected;
|
||||
std::string message;
|
||||
std::uint64_t timestamp = 0;
|
||||
};
|
||||
|
||||
struct MemoryDiagnosticRecord {
|
||||
std::string diagnosticId;
|
||||
std::string sessionId;
|
||||
std::string allocationId;
|
||||
std::string paneKey;
|
||||
std::string message;
|
||||
MemorySignalSeverity severity = MemorySignalSeverity::Info;
|
||||
std::uint64_t timestamp = 0;
|
||||
};
|
||||
|
||||
class LeakCorruptionSignalBridge {
|
||||
public:
|
||||
bool ingestSignal(const MemorySignalRecord& signal, std::string* error) {
|
||||
if (!error) return false;
|
||||
error->clear();
|
||||
if (!hasRequiredDebugIds(signal.signalId, signal.sessionId)) return fail(error, "signal_or_session_missing");
|
||||
if (signal.allocationId.empty()) return fail(error, "allocation_id_missing");
|
||||
if (signal.message.empty()) return fail(error, "signal_message_missing");
|
||||
if (signal.timestamp == 0) return fail(error, "signal_timestamp_invalid");
|
||||
if (containsSignal(signal.signalId)) return fail(error, "signal_duplicate");
|
||||
|
||||
signals_.push_back(signal);
|
||||
diagnostics_.push_back(buildDiagnostic(signal));
|
||||
stableSortByTimestamp(&signals_);
|
||||
stableSortByTimestamp(&diagnostics_);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<MemoryDiagnosticRecord> diagnosticsForSession(const std::string& sessionId) const {
|
||||
std::vector<MemoryDiagnosticRecord> filtered;
|
||||
for (const auto& diagnostic : diagnostics_) {
|
||||
if (sessionId.empty() || diagnostic.sessionId == sessionId) filtered.push_back(diagnostic);
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
std::vector<MemorySignalRecord> signalsForAllocation(const std::string& allocationId) const {
|
||||
std::vector<MemorySignalRecord> filtered;
|
||||
for (const auto& signal : signals_) {
|
||||
if (allocationId.empty() || signal.allocationId == allocationId) filtered.push_back(signal);
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
MemorySignalSeverity highestSeverityForSession(const std::string& sessionId) const {
|
||||
MemorySignalSeverity highest = MemorySignalSeverity::Info;
|
||||
for (const auto& diagnostic : diagnostics_) {
|
||||
if (!sessionId.empty() && diagnostic.sessionId != sessionId) continue;
|
||||
if (static_cast<int>(diagnostic.severity) > static_cast<int>(highest)) highest = diagnostic.severity;
|
||||
}
|
||||
return highest;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<MemorySignalRecord> signals_;
|
||||
std::vector<MemoryDiagnosticRecord> diagnostics_;
|
||||
|
||||
static bool fail(std::string* error, const char* code) {
|
||||
*error = code;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool containsSignal(const std::string& signalId) const {
|
||||
for (const auto& signal : signals_) {
|
||||
if (signal.signalId == signalId) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static MemoryDiagnosticRecord buildDiagnostic(const MemorySignalRecord& signal) {
|
||||
MemoryDiagnosticRecord diagnostic;
|
||||
diagnostic.diagnosticId = "diag-" + signal.signalId;
|
||||
diagnostic.sessionId = signal.sessionId;
|
||||
diagnostic.allocationId = signal.allocationId;
|
||||
diagnostic.message = signal.message;
|
||||
diagnostic.timestamp = signal.timestamp;
|
||||
diagnostic.paneKey = paneForSignal(signal.type);
|
||||
diagnostic.severity = severityForSignal(signal.type);
|
||||
return diagnostic;
|
||||
}
|
||||
|
||||
static std::string paneForSignal(MemorySignalType type) {
|
||||
switch (type) {
|
||||
case MemorySignalType::LeakSuspected:
|
||||
case MemorySignalType::LeakConfirmed:
|
||||
return "memory-leaks";
|
||||
case MemorySignalType::CorruptionSuspected:
|
||||
case MemorySignalType::CorruptionConfirmed:
|
||||
return "memory-corruption";
|
||||
}
|
||||
return "memory-diagnostics";
|
||||
}
|
||||
|
||||
static MemorySignalSeverity severityForSignal(MemorySignalType type) {
|
||||
switch (type) {
|
||||
case MemorySignalType::LeakSuspected: return MemorySignalSeverity::Warning;
|
||||
case MemorySignalType::LeakConfirmed: return MemorySignalSeverity::Error;
|
||||
case MemorySignalType::CorruptionSuspected: return MemorySignalSeverity::Error;
|
||||
case MemorySignalType::CorruptionConfirmed: return MemorySignalSeverity::Critical;
|
||||
}
|
||||
return MemorySignalSeverity::Info;
|
||||
}
|
||||
|
||||
static void stableSortByTimestamp(std::vector<MemorySignalRecord>* signals) {
|
||||
std::stable_sort(signals->begin(),
|
||||
signals->end(),
|
||||
[](const MemorySignalRecord& a, const MemorySignalRecord& b) {
|
||||
if (a.timestamp != b.timestamp) return a.timestamp < b.timestamp;
|
||||
return a.signalId < b.signalId;
|
||||
});
|
||||
}
|
||||
|
||||
static void stableSortByTimestamp(std::vector<MemoryDiagnosticRecord>* diagnostics) {
|
||||
std::stable_sort(diagnostics->begin(),
|
||||
diagnostics->end(),
|
||||
[](const MemoryDiagnosticRecord& a, const MemoryDiagnosticRecord& b) {
|
||||
if (a.timestamp != b.timestamp) return a.timestamp < b.timestamp;
|
||||
return a.diagnosticId < b.diagnosticId;
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user