Files
netris-cdc-file-transfer/common/log.cc
Lutz Justen 5a909bb443 [cdc_rsync] Improve throughput for local copies (#74)
On Windows, fclose() seems to be very expensive for large files, where
closing a 1 GB file takes up to 5 seconds. This CL calls fclose() in
background threads. This tremendously improves local syncs, e.g.
copying a 4.5 GB, 300 files data set takes only 7 seconds instead of
30 seconds.

Also increases the buffer size for copying from 16K to 128K (better
throughput for local copies), and adds a timestamp to debug and
verbose console logs (useful when comparing client and server logs).
2023-01-31 16:33:03 +01:00

172 lines
4.2 KiB
C++

// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "log.h"
#include <cassert>
#include "common/platform.h"
#if PLATFORM_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
namespace cdc_ft {
namespace {
const char* GetLogLevelString(LogLevel level) {
switch (level) {
case LogLevel::kVerbose:
return "VERBOSE";
case LogLevel::kDebug:
return "DEBUG";
case LogLevel::kInfo:
return "INFO";
case LogLevel::kWarning:
return "WARNING";
case LogLevel::kError:
return "ERROR";
}
return "UnknownLogLevel";
}
} // namespace
// static
void Log::Initialize(std::unique_ptr<Log> log) {
assert(!instance_);
instance_ = log.release();
}
// static
void Log::Shutdown() {
assert(instance_);
delete instance_;
instance_ = nullptr;
}
// static
Log* Log::Instance() {
assert(instance_);
return instance_;
}
// static
Log* Log::MaybeNullInstance() { return instance_; }
Log* Log::instance_ = nullptr;
Log::~Log() = default;
// static
LogLevel Log::VerbosityToLogLevel(int verbosity) {
if (verbosity >= 4) {
return LogLevel::kVerbose;
}
if (verbosity >= 3) {
return LogLevel::kDebug;
}
if (verbosity >= 2) {
return LogLevel::kInfo;
}
return LogLevel::kWarning;
}
// static
void Log::DefaultWriteLogMessage(LogLevel level, const char* file, int line,
const char* message) {
// Only print warnings and above.
if (level < LogLevel::kWarning) return;
fprintf(stderr, "%-7s %s(%i): %s\n", GetLogLevelString(level), file, line,
message);
}
#if PLATFORM_WINDOWS
enum Colors {
kLightGray = 7,
kGray = 8,
kBlue = 9,
kCyan = 11,
kRed = 12,
kYellow = 14,
kWhite = 15
};
WORD GetConsoleColor(LogLevel level) {
switch (level) {
case LogLevel::kVerbose:
return kGray;
case LogLevel::kDebug:
return kCyan;
case LogLevel::kInfo:
return kWhite;
case LogLevel::kWarning:
return kYellow;
case LogLevel::kError:
return kRed;
}
return 15;
}
#endif
void ConsoleLog::WriteLogMessage(LogLevel level, const char* file, int line,
const char* func, const char* message) {
absl::MutexLock lock(&mutex_);
// Show leaner log messages in non-verbose mode.
bool show_time_file_func = GetLogLevel() <= LogLevel::kDebug;
FILE* stdfile = level >= LogLevel::kError ? stderr : stdout;
#if PLATFORM_WINDOWS
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, GetConsoleColor(level));
if (show_time_file_func) {
fprintf(stdfile, "%0.3f %s(%i): %s(): %s\n", stopwatch_.ElapsedSeconds(),
file, line, func, message);
} else {
fprintf(stdfile, "%s\n", message);
}
SetConsoleTextAttribute(hConsole, kLightGray);
#else
if (show_time_file_func) {
fprintf(stdfile, "%-7s %0.3f %s(%i): %s(): %s\n", GetLogLevelString(level),
stopwatch_.ElapsedSeconds(), file, line, func, message);
} else {
fprintf(stdfile, "%-7s %s\n", GetLogLevelString(level), message);
}
#endif
}
FileLog::FileLog(LogLevel log_level, const char* path) : Log(log_level) {
file_ = fopen(path, "wt");
if (!file_) fprintf(stderr, "Failed to open log file '%s'", path);
}
FileLog::~FileLog() {
if (file_) fclose(file_);
}
void FileLog::WriteLogMessage(LogLevel level, const char* file, int line,
const char* func, const char* message) {
if (!file_) return;
std::string timestamp = clock_.FormatNow("%Y-%m-%d %H:%M:%S.", true);
absl::MutexLock lock(&mutex_);
fprintf(file_, "%s %-7s %s(%i): %s(): %s\n", timestamp.c_str(),
GetLogLevelString(level), file, line, func, message);
fflush(file_);
}
} // namespace cdc_ft