Cap log unit allocation in logger

This commit is contained in:
Julien Letessier 2026-01-15 16:11:30 +01:00
parent 13e36df7c8
commit 560dbe7fc7
5 changed files with 73 additions and 1 deletions

View File

@ -197,6 +197,7 @@ LogUnit* Logger::getLogUnit()
mFree.resize(mFree.size() - 1); mFree.resize(mFree.size() - 1);
} else if (mLogUnitCnt < mFree.capacity()) { } else if (mLogUnitCnt < mFree.capacity()) {
++mLogUnitCnt; ++mLogUnitCnt;
log = new LogUnit();
} else { } else {
++mMissLogs; ++mMissLogs;
return nullptr; return nullptr;
@ -208,6 +209,7 @@ LogUnit* Logger::getLogUnit()
mFree.resize(mFree.size() - 1); mFree.resize(mFree.size() - 1);
} else if (mLogUnitCnt < mFree.capacity()) { } else if (mLogUnitCnt < mFree.capacity()) {
++mLogUnitCnt; ++mLogUnitCnt;
log = new LogUnit();
} else { } else {
while (mFree.empty() && !mStop) { while (mFree.empty() && !mStop) {
mCond.wait(lck); mCond.wait(lck);
@ -220,7 +222,7 @@ LogUnit* Logger::getLogUnit()
} }
} }
} }
return log ? log : new LogUnit(); return log;
} }
int Logger::logFileFd() const int Logger::logFileFd() const

View File

@ -92,6 +92,10 @@ public:
} }
void log(LogLevel::Type lvl, const char* file, int line, const char* fmt, ...); void log(LogLevel::Type lvl, const char* file, int line, const char* fmt, ...);
int logFileFd() const; int logFileFd() const;
unsigned logUnitCount() const
{
return mLogUnitCnt;
}
static Logger* gInst; static Logger* gInst;
private: private:
LogUnit* getLogUnit(); LogUnit* getLogUnit();

View File

@ -0,0 +1,18 @@
/*
* Ensure Logger does not create more LogUnit instances than its capacity.
*/
#include "../src/Logger.h"
int main() {
Logger logger(1);
logger.setAllowMissLog(true);
logger.setLogSample(LogLevel::Info, 1);
for (int i = 0; i < 1000; ++i) {
logger.log(LogLevel::Info, __FILE__, __LINE__, "msg %d", i);
}
if (logger.logUnitCount() > 1) {
return 1;
}
return 0;
}

View File

@ -0,0 +1,47 @@
#!/usr/bin/env python3
#
# Build and run the Logger LogUnit cap test.
#
import os
import subprocess
import tempfile
from test_util import parse_args, exit_with_result
def run_test(project_root):
src = os.path.join(project_root, "test", "logger_unbounded_logunit.cpp")
if not os.path.exists(src):
print("FAIL: logger_unbounded_logunit.cpp not found")
return False
with tempfile.TemporaryDirectory() as tmp:
exe = os.path.join(tmp, "logger_unbounded_logunit")
cmd = [
"g++",
"-std=c++11",
src,
os.path.join(project_root, "src", "Logger.cpp"),
os.path.join(project_root, "src", "LogFileSink.cpp"),
os.path.join(project_root, "src", "Timer.cpp"),
"-o",
exe,
]
try:
subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except Exception as exc:
print("FAIL: compile logger_unbounded_logunit:", exc)
return False
try:
subprocess.check_call([exe], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except subprocess.CalledProcessError as exc:
print("FAIL: logger_unbounded_logunit returned", exc.returncode)
return False
return True
if __name__ == "__main__":
_ = parse_args("Logger logunit cap test")
root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
success = run_test(root)
exit_with_result(success, "logger logunit cap", "logger logunit cap")

View File

@ -148,6 +148,7 @@ TESTS=(
"test/buffer_vsnprintf.py" "test/buffer_vsnprintf.py"
"test/logunit_vsnprintf.py" "test/logunit_vsnprintf.py"
"test/logger_thread_init.py" "test/logger_thread_init.py"
"test/logger_unbounded_logunit.py"
"test/pubsub_long_name.py" "test/pubsub_long_name.py"
"test/pubsub_large_message.py" "test/pubsub_large_message.py"
"test/transaction_forbid.py" "test/transaction_forbid.py"