#include "commit_request.hpp" #include "json_commit_request_parser.hpp" #include #include #include #include #include #include #include struct ArenaDebugger { const CommitRequest &commit_request; const ArenaAllocator &arena; std::unordered_set referenced_addresses; explicit ArenaDebugger(const CommitRequest &cr) : commit_request(cr), arena(cr.arena()) {} void analyze_references() { // Track all string_view data pointers from the parsed commit request if (commit_request.request_id().has_value()) { add_reference(commit_request.request_id()->data(), commit_request.request_id()->size()); } add_reference(commit_request.leader_id().data(), commit_request.leader_id().size()); for (const auto &precond : commit_request.preconditions()) { add_reference(precond.begin.data(), precond.begin.size()); add_reference(precond.end.data(), precond.end.size()); } for (const auto &op : commit_request.operations()) { add_reference(op.param1.data(), op.param1.size()); add_reference(op.param2.data(), op.param2.size()); } } void add_reference(const char *ptr, size_t size) { if (ptr && size > 0) { referenced_addresses.insert(ptr); // Also add end pointer to mark the range referenced_addresses.insert(ptr + size - 1); } } void visualize_arena() { std::cout << "=== Arena Visualization Debug Tool ===" << std::endl; std::cout << "Analyzing commit request and arena memory layout" << std::endl; std::cout << std::endl; // First, analyze what's referenced analyze_references(); // Print basic arena statistics std::cout << "Arena Statistics:" << std::endl; std::cout << "- Total allocated: " << arena.total_allocated() << " bytes" << std::endl; std::cout << "- Currently used: " << arena.used_bytes() << " bytes" << std::endl; std::cout << "- Number of blocks: " << arena.num_blocks() << " blocks" << std::endl; std::cout << "- Referenced addresses: " << referenced_addresses.size() << std::endl; std::cout << std::endl; // Use the arena's debug_dump with content visualization std::cout << "Raw Arena Memory Layout:" << std::endl; arena.debug_dump(std::cout, true, true, 1024); std::cout << std::endl; std::cout << "=== Pointer Analysis ===" << std::endl; // Scan for potential pointers in arena memory using the arena's built-in // method scan_arena_pointers(); std::cout << std::endl; std::cout << "=== Referenced Memory Regions ===" << std::endl; visualize_referenced_data(); } private: void scan_arena_pointers() { std::cout << "Arena memory analysis:" << std::endl; std::cout << "- Total scanned: " << arena.used_bytes() << " bytes across " << arena.num_blocks() << " blocks" << std::endl; std::cout << "- Memory utilization: " << (arena.total_allocated() > 0 ? (100.0 * arena.used_bytes() / arena.total_allocated()) : 0.0) << "%" << std::endl; } std::string_view find_string_view_for_data(const char *data) { if (commit_request.request_id().has_value() && commit_request.request_id()->data() == data) { return *commit_request.request_id(); } if (commit_request.leader_id().data() == data) { return commit_request.leader_id(); } for (const auto &precond : commit_request.preconditions()) { if (precond.begin.data() == data) return precond.begin; if (precond.end.data() == data) return precond.end; } for (const auto &op : commit_request.operations()) { if (op.param1.data() == data) return op.param1; if (op.param2.data() == data) return op.param2; } return {}; } void visualize_referenced_data() { std::cout << "Visualizing parsed commit request data references:" << std::endl; std::cout << std::endl; // Show request_id if (commit_request.request_id().has_value()) { std::cout << "request_id: "; visualize_string_data(*commit_request.request_id()); } // Show leader_id std::cout << "leader_id: "; visualize_string_data(commit_request.leader_id()); // Show read_version std::cout << "read_version: " << commit_request.read_version() << std::endl; // Show preconditions std::cout << "preconditions (" << commit_request.preconditions().size() << "):" << std::endl; for (size_t i = 0; i < commit_request.preconditions().size(); ++i) { const auto &precond = commit_request.preconditions()[i]; std::cout << " [" << i << "] type: " << precondition_type_to_string(precond.type) << ", version: " << precond.version << std::endl; std::cout << " begin: "; visualize_string_data(precond.begin, " "); std::cout << " end: "; visualize_string_data(precond.end, " "); } // Show operations std::cout << "operations (" << commit_request.operations().size() << "):" << std::endl; for (size_t i = 0; i < commit_request.operations().size(); ++i) { const auto &op = commit_request.operations()[i]; std::cout << " [" << i << "] type: " << operation_type_to_string(op.type) << std::endl; std::cout << " param1: "; visualize_string_data(op.param1, " "); std::cout << " param2: "; visualize_string_data(op.param2, " "); } } void visualize_string_data(std::string_view sv, const std::string &indent = "") { if (sv.empty()) { std::cout << "(empty)" << std::endl; return; } const char *data = sv.data(); size_t size = sv.size(); std::cout << "\"" << sv << "\" @ " << static_cast(data) << " [" << size << " bytes]"; if (referenced_addresses.count(data)) { std::cout << " (REFERENCED)"; } std::cout << std::endl; // Show hex dump of the string data if (size > 0 && size <= 64) { // Only show hex for reasonable sizes std::cout << indent << "Hex: "; for (size_t i = 0; i < size; ++i) { unsigned char byte = static_cast(data[i]); std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast(byte) << std::dec; if ((i + 1) % 4 == 0 && i < size - 1) std::cout << " "; } std::cout << std::endl; } } const char *precondition_type_to_string(Precondition::Type type) { switch (type) { case Precondition::Type::PointRead: return "point_read"; case Precondition::Type::RangeRead: return "range_read"; default: return "unknown"; } } const char *operation_type_to_string(Operation::Type type) { switch (type) { case Operation::Type::Write: return "write"; case Operation::Type::Delete: return "delete"; case Operation::Type::RangeDelete: return "range_delete"; default: return "unknown"; } } }; int main(int argc, char *argv[]) { if (argc != 2) { std::cerr << "Usage: " << argv[0] << " " << std::endl; std::cerr << "Debug tool to visualize arena memory layout from commit " "request JSON" << std::endl; return 1; } const char *filename = argv[1]; // Read JSON file std::ifstream file(filename); if (!file.is_open()) { std::cerr << "Error: Could not open file '" << filename << "'" << std::endl; return 1; } std::ostringstream ss; ss << file.rdbuf(); std::string json_content = ss.str(); file.close(); if (json_content.empty()) { std::cerr << "Error: File is empty or could not be read" << std::endl; return 1; } std::cout << "Reading commit request from: " << filename << std::endl; std::cout << "JSON size: " << json_content.size() << " bytes" << std::endl; std::cout << std::endl; // Parse the commit request CommitRequest commit_request; JsonCommitRequestParser parser; // Make a mutable copy for parsing (weaseljson requires mutable data) std::vector mutable_json(json_content.begin(), json_content.end()); mutable_json.push_back('\0'); // Null terminate for safety auto parse_result = parser.parse(commit_request, mutable_json.data(), mutable_json.size() - 1); if (parse_result != CommitRequestParser::ParseResult::Success) { std::cerr << "Error: Failed to parse JSON" << std::endl; if (parser.has_parse_error()) { std::cerr << "Parse error: " << parser.get_parse_error() << std::endl; } return 1; } std::cout << "Successfully parsed commit request!" << std::endl; std::cout << std::endl; // Create debugger and visualize ArenaDebugger debugger(commit_request); debugger.visualize_arena(); return 0; }