Repository: pinpoint-apm/pinpoint-c-agent (language: python)

Issue:
trace leak when load testing
**Describe the bug**

I found many leaked node, the traceId reached 10000.

If the parent trace node end before the child node, the child node would be leak




Discussion / hints:

Fix patch:
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index f80741bc2..9638f2888 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 3.13)
-project(common VERSION 0.4.14 DESCRIPTION  "pinpoint common library")
+project(common VERSION 0.4.15 DESCRIPTION  "pinpoint common library")
 
 set(CMAKE_CXX_STANDARD 11)
 
diff --git a/common/src/common.cpp b/common/src/common.cpp
index 573087271..18d2ef0b7 100644
--- a/common/src/common.cpp
+++ b/common/src/common.cpp
@@ -31,7 +31,7 @@
 #include "NodePool/PoolManager.h"
 #include "Util/Helper.h"
 #include "ConnectionPool/SpanConnectionPool.h"
-#include "define.h"
+#include "header.h"
 namespace Json = AliasJson;
 
 using Cache::SafeSharedState;
@@ -86,7 +86,7 @@ static NodeID do_start_trace(NodeID id, const char *opt = nullptr, va_list *args
     }
 }
 
-static void free_nodes_tree(NodeID id)
+void free_nodes_tree(NodeID id)
 {
     if (id == E_INVALID_NODE || id == E_ROOT_NODE)
     {
@@ -177,13 +177,15 @@ NodeID do_end_trace(NodeID Id)
             catch (const std::out_of_range &ex)
             {
                 pp_trace("current#%d dropped,due to parent is end", node.ID);
-                PoolManager::getInstance().freeNode(node);
+                // PoolManager::getInstance().freeNode(node);
+                free_nodes_tree(node.ID);
             }
         }
         else
         {
             pp_trace("current#%d dropped,due to checkOpt false", node.ID);
-            PoolManager::getInstance().freeNode(node);
+            free_nodes_tree(node.ID);
+            // PoolManager::getInstance().freeNode(node);
         }
 
         return parentId;
diff --git a/common/src/define.h b/common/src/define.h
deleted file mode 100644
index 6d2e4581a..000000000
--- a/common/src/define.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#pragma once
-
-#define likely(x) __builtin_expect(!!(x), 1)
-#define unlikely(x) __builtin_expect(!!(x), 0)
\ No newline at end of file
diff --git a/common/src/header.h b/common/src/header.h
new file mode 100644
index 000000000..56b1c0b56
--- /dev/null
+++ b/common/src/header.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+void free_nodes_tree(NodeID id);
\ No newline at end of file


Test patch:
diff --git a/common/test/test_node.cc b/common/test/test_node.cc
index 17f6dd61f..5ececf71e 100644
--- a/common/test/test_node.cc
+++ b/common/test/test_node.cc
@@ -1,6 +1,7 @@
 #include "common.h"
 #include <gtest/gtest.h>
 #include "Util/Helper.h"
+#include "header.h"
 #include "NodePool/PoolManager.h"
 #include <condition_variable>
 #include <thread>
@@ -287,7 +288,7 @@ TEST(node, tons_of_nodes_01)
     EXPECT_EQ(count, usedNode());
 }
 
-TEST(node, tons_of_nodes_02)
+TEST(node, tons_of_nodes_2k)
 {
     auto count = usedNode(); // PoolManager::getInstance().totoalNodesCount() - PoolManager::getInstance().freeNodesCount();
     NodeID root = pinpoint_start_trace(E_ROOT_NODE);
@@ -303,5 +304,39 @@ TEST(node, tons_of_nodes_02)
     }
     pinpoint_end_trace(root);
 
+    EXPECT_EQ(count, usedNode());
+}
+
+TEST(node, tons_of_nodes_leak)
+{
+    auto count = usedNode();
+
+    NodeID root, child_1, child_2;
+    root = pinpoint_start_trace(E_ROOT_NODE);
+
+    child_1 = pinpoint_start_trace(root);
+    child_2 = pinpoint_start_trace(child_1);
+
+    pinpoint_end_trace(child_2);
+
+    pinpoint_end_trace(root);
+    pinpoint_end_trace(child_1);
+    EXPECT_EQ(count, usedNode());
+}
+
+TEST(node, tons_of_nodes_free_all)
+{
+    auto count = usedNode();
+
+    NodeID root, child_1, child_2;
+    root = pinpoint_start_trace(E_ROOT_NODE);
+
+    child_1 = pinpoint_start_trace(root);
+    child_2 = pinpoint_start_trace(child_1);
+    free_nodes_tree(root);
+    pinpoint_end_trace(child_2);
+
+    pinpoint_end_trace(root);
+    pinpoint_end_trace(child_1);
     EXPECT_EQ(count, usedNode());
 }
\ No newline at end of file