diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | contrib/otshell_utils/utils.cpp | 170 | ||||
-rw-r--r-- | contrib/otshell_utils/utils.hpp | 16 | ||||
-rw-r--r-- | src/common/util.cpp | 2 | ||||
-rw-r--r-- | src/daemon/daemon.cpp | 6 | ||||
-rw-r--r-- | src/p2p/connection_basic.cpp | 1 | ||||
-rw-r--r-- | src/p2p/data_logger.cpp | 143 | ||||
-rw-r--r-- | src/p2p/data_logger.hpp | 52 | ||||
-rw-r--r-- | src/p2p/network_throttle.cpp | 1 | ||||
-rw-r--r-- | tests/core_proxy/core_proxy.cpp | 3 | ||||
-rw-r--r-- | tests/core_proxy/core_proxy.h | 2 | ||||
-rw-r--r-- | tests/core_tests/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/core_tests/chaingen_main.cpp | 2 | ||||
-rw-r--r-- | tests/functional_tests/main.cpp | 2 | ||||
-rw-r--r-- | tests/net_load_tests/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/net_load_tests/clt.cpp | 3 | ||||
-rw-r--r-- | tests/net_load_tests/srv.cpp | 4 | ||||
-rw-r--r-- | tests/performance_tests/main.cpp | 2 | ||||
-rw-r--r-- | tests/unit_tests/main.cpp | 2 |
19 files changed, 306 insertions, 110 deletions
diff --git a/.gitignore b/.gitignore index 755cb1043..18653c238 100644 --- a/.gitignore +++ b/.gitignore @@ -59,7 +59,6 @@ version/ ### CMake ### CMakeCache.txt CMakeFiles -Makefile cmake_install.cmake install_manifest.txt *.cmake diff --git a/contrib/otshell_utils/utils.cpp b/contrib/otshell_utils/utils.cpp index 043260807..ff39d15e8 100644 --- a/contrib/otshell_utils/utils.cpp +++ b/contrib/otshell_utils/utils.cpp @@ -160,7 +160,7 @@ std::unique_ptr<T> make_unique( Args&& ...args ) #endif // ==================================================================== -char cFilesystemUtils::GetDirSeparator() { +char cFilesystemUtils::GetDirSeparatorSys() { // TODO nicer os detection? #if defined(OS_TYPE_POSIX) return '/'; @@ -171,26 +171,49 @@ char cFilesystemUtils::GetDirSeparator() { #endif } +char cFilesystemUtils::GetDirSeparatorInter() { + return '/'; +} + +string cFilesystemUtils::FileInternalToSystem(const std::string &name) { + string ret; + ret.resize(name.size()); + std::replace_copy(name.begin(), name.end(), ret.begin(), + GetDirSeparatorInter() , GetDirSeparatorSys()); + return ret; +} + +string cFilesystemUtils::FileSystemToInternal(const std::string &name) { + string ret; + ret.reserve(name.size()); + std::replace_copy(name.begin(), name.end(), ret.begin(), + GetDirSeparatorSys() , GetDirSeparatorInter()); + return ret; +} + bool cFilesystemUtils::CreateDirTree(const std::string & dir, bool only_below) { const bool dbg=false; //struct stat st; - const char dirch = cFilesystemUtils::GetDirSeparator(); + const char dirchS = cFilesystemUtils::GetDirSeparatorSys(); + const char dirchI = cFilesystemUtils::GetDirSeparatorInter(); std::istringstream iss(dir); - string part, sofar=""; + string partI; // current par is in internal format (though it should not matter since it doesn't contain any slashes). eg "bar" + string sofarS=""; // sofarS - the so far created dir part is in SYSTEM format. eg "foo/bar" if (dir.size()<1) return false; // illegal name // dir[0] is valid from here - if (only_below && (dir[0]==dirch)) return false; // no jumping to top (on any os) - while (getline(iss,part,dirch)) { - if (dbg) cout << '['<<part<<']' << endl; - sofar += part; - if (part.size()<1) return false; // bad format? - if ((only_below) && (part=="..")) return false; // going up - - if (dbg) cout << "test ["<<sofar<<"]"<<endl; + if ( only_below && ((dir[0]==dirchS) || (dir[0]==dirchI))) return false; // no jumping to top (on any os) + + while (getline(iss,partI,dirchI)) { // get new component eg "bar" into part + if (dbg) cout << '['<<partI<<']' << endl; + sofarS += partI; + if (partI.size()<1) return false; // bad format? + if ((only_below) && (partI=="..")) return false; // trying to go up + + if (dbg) cout << "test ["<<sofarS<<"]"<<endl; // TODO nicer os detection? #if defined(OS_TYPE_POSIX) struct stat st; - bool exists = stat(sofar.c_str() ,&st) == 0; // * + bool exists = stat(sofarS.c_str() ,&st) == 0; // * if (exists) { if (! S_ISDIR(st.st_mode)) { // std::cerr << "This exists, but as a file: [" << sofar << "]" << (size_t)st.st_ino << endl; @@ -198,24 +221,24 @@ bool cFilesystemUtils::CreateDirTree(const std::string & dir, bool only_below) { } } #elif defined(OS_TYPE_WINDOWS) - DWORD dwAttrib = GetFileAttributesA(sofar.c_str()); + DWORD dwAttrib = GetFileAttributesA(sofarS.c_str()); bool exists = (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); #else #error "Do not know how to compile this for your platform." #endif if (!exists) { - if (dbg) cout << "mkdir ["<<sofar<<"]"<<endl; + if (dbg) cout << "mkdir ["<<sofarS<<"]"<<endl; #if defined(OS_TYPE_POSIX) - bool ok = 0== mkdir(sofar.c_str(), 0700); // *** + bool ok = 0== mkdir(sofarS.c_str(), 0700); // *** #elif defined(OS_TYPE_WINDOWS) - bool ok = (bool) CreateDirectoryA(sofar.c_str(), NULL); // TODO use -W() after conversion to unicode UTF16 + bool ok = (bool) CreateDirectoryA(sofarS.c_str(), NULL); // TODO use -W() after conversion to unicode UTF16 #else #error "Do not know how to compile this for your platform." #endif if (!ok) return false; } - sofar += cFilesystemUtils::GetDirSeparator(); + sofarS += dirchS; } return true; } @@ -225,7 +248,7 @@ namespace nDetail { cDebugScopeGuard::cDebugScopeGuard() : mLevel(-1) { } - + cDebugScopeGuard::~cDebugScopeGuard() { if (mLevel != -1) { gCurrentLogger.write_stream(mLevel,mChan) << mMsg << " ... end" << gCurrentLogger.endline() << std::flush; @@ -244,11 +267,15 @@ void cDebugScopeGuard::Assign(const string &chan, const int level, const string cLogger::cLogger() : mStream(NULL), +mStreamBrokenDebug(NULL), +mIsBroken(true), // before constructor finishes mLevel(85), mThread2Number_Biggest(0) // the CURRENT biggest value (no thread yet in map) { mStream = & std::cout; + mStreamBrokenDebug = & std::cerr; Thread2Number( std::this_thread::get_id() ); // convert current id to short number, useful to reserve a number so that main thread is usually called 1 + mIsBroken=false; // ok, constr. succeeded, so string is not broken now } cLogger::~cLogger() { @@ -259,12 +286,28 @@ cLogger::~cLogger() { } } +void cLogger::SetStreamBroken() { + SetStreamBroken("(no additional details about this problem)"); +} + +void cLogger::SetStreamBroken(const std::string &msg) { + if (!mIsBroken) { // if not already marked as broken + std::cerr << OT_CODE_STAMP << "WARNING: due to debug stream problem ("<<msg<<") - switching back to fallback stream (e.g. cerr)" << std::endl; + if (mStreamBrokenDebug == nullptr) { + std::cerr << OT_CODE_STAMP << " ERROR: in addition, while reporting this problem, mStreamBrokenDebug stream is NULL." << std::endl; + } else { + (*mStreamBrokenDebug) << OT_CODE_STAMP << "WARNING: due to debug stream problem ("<<msg<<") - switching back to fallback stream (e.g. cerr)" << std::endl; + } + mIsBroken = true; + } +} + std::ostream & cLogger::write_stream(int level) { return write_stream(level,""); } std::ostream & cLogger::write_stream(int level, const std::string & channel ) { - if ((level >= mLevel) && (mStream)) { + if ((level >= mLevel) && (mStream)) { // TODO now disabling mStream also disables writting to any channel ostream & output = SelectOutput(level,channel); output << icon(level) << ' '; std::thread::id this_id = std::this_thread::get_id(); @@ -278,33 +321,76 @@ std::string cLogger::GetLogBaseDir() const { return "log"; } -void cLogger::OpenNewChannel(const std::string & channel) { - size_t last_split = channel.find_last_of(cFilesystemUtils::GetDirSeparator()); - // log/test/aaa - // ^----- last_split - string dir = GetLogBaseDir() + cFilesystemUtils::GetDirSeparator() + channel.substr(0, last_split); - string basefile = channel.substr(last_split+1) + ".log"; - string fname = dir + cFilesystemUtils::GetDirSeparator() + cFilesystemUtils::GetDirSeparator() + basefile; - _dbg1("Starting debug to channel file: " + fname + " in directory ["+dir+"]"); - bool dirok = cFilesystemUtils::CreateDirTree(dir); - if (!dirok) { const string msg = "In logger failed to open directory (" + dir +")."; _erro(msg); throw std::runtime_error(msg); } - std::ofstream * thefile = new std::ofstream( fname.c_str() ); - *thefile << "====== (Log opened: " << fname << ") ======" << endl; - mChannels.insert( std::pair<string,std::ofstream*>(channel , thefile ) ); -} - -std::ostream & cLogger::SelectOutput(int level, const std::string & channel) { - if (channel=="") return *mStream; - auto obj = mChannels.find(channel); - if (obj == mChannels.end()) { // new channel - OpenNewChannel(channel); - return SelectOutput(level,channel); +void cLogger::OpenNewChannel(const std::string & channel) noexcept { + try { + std::cerr<<"openning channel for channel="<<channel<<endl; + OpenNewChannel_(channel); + } + catch (const std::exception &except) { + SetStreamBroken(OT_CODE_STAMP + " Got exception when opening debug channel: " + ToStr(except.what())); + } + catch (...) { + SetStreamBroken(OT_CODE_STAMP + " Got not-standard exception when opening debug channel."); + } +} + +void cLogger::OpenNewChannel_(const std::string & channel) { // channel=="net/sleep" + size_t last_split = channel.find_last_of(cFilesystemUtils::GetDirSeparatorInter()); + + string fname_system; // the full file name in system format + + if (last_split==string::npos) { // The channel name has no directory, eg channel=="test" + string dir = GetLogBaseDir(); + string basefile = channel + ".log"; + string fname = dir + cFilesystemUtils::GetDirSeparatorInter() + basefile; + fname_system = cFilesystemUtils::FileInternalToSystem(fname); // <- } - else { // existing - return * obj->second; + else { // there is a directory eg channel=="net/sleep" + // net/sleep + // ^----- last_split + string dir = GetLogBaseDir() + cFilesystemUtils::GetDirSeparatorInter() + channel.substr(0, last_split); + string basefile = channel.substr(last_split+1) + ".log"; + string fname = dir + cFilesystemUtils::GetDirSeparatorInter() + basefile; + fname_system = cFilesystemUtils::FileInternalToSystem(fname); // <- + bool dirok = cFilesystemUtils::CreateDirTree(dir); + if (!dirok) { string err = "In logger failed to open directory (" + dir +") for channel (" + channel +")"; throw std::runtime_error(err); } } + + std::ofstream * thefile = new std::ofstream( fname_system.c_str() ); // file system + *thefile << "====== Log opened: " << fname_system << " (in " << ((void*)thefile) << ") ======" << endl; + cerr << "====== Log opened: " << fname_system << " (in " << ((void*)thefile) << ") ======" << endl; + mChannels.insert( std::pair<string,std::ofstream*>(channel , thefile ) ); // <- created the channel mapping } +std::ostream & cLogger::SelectOutput(int level, const std::string & channel) noexcept { + try { + if (mIsBroken) return *mStreamBrokenDebug; + if (channel=="") return *mStream; + + auto obj = mChannels.find(channel); + if (obj == mChannels.end()) { // not found - need to make new channel + OpenNewChannel(channel); // <- create channel + obj = mChannels.find(channel); // find again + if (obj == mChannels.end()) { // still not found! something is wrong + SetStreamBroken( OT_CODE_STAMP + " WARNING: can not get stream for channel="+ToStr(channel)+" level="+ToStr(channel) ); + return *mStreamBrokenDebug; + } + } + auto the_stream_ptr = obj->second; + ASRT(the_stream_ptr); + return *the_stream_ptr; // <--- RETURN + } + catch (std::exception &except) { + SetStreamBroken( OT_CODE_STAMP + " Got exception: " + ToStr(except.what()) ); + return *mStreamBrokenDebug; + } + catch (...) { + SetStreamBroken( OT_CODE_STAMP + " Got not-standard exception."); + return *mStreamBrokenDebug; + } + + // dead code +} void cLogger::setOutStreamFile(const string &fname) { // switch to using this file _mark("WILL SWITCH DEBUG NOW to file: " << fname); diff --git a/contrib/otshell_utils/utils.hpp b/contrib/otshell_utils/utils.hpp index 83e6b822d..35b464b42 100644 --- a/contrib/otshell_utils/utils.hpp +++ b/contrib/otshell_utils/utils.hpp @@ -185,6 +185,7 @@ const char* DbgShortenCodeFileName(const char *s); ///< Returns a pointer to som /*** @brief Class to write debug into. Used it by calling the debug macros _dbg1(...) _info(...) _erro(...) etc, NOT directly! @author rfree (maintainer) +@thread this class is NOT thread safe and must used only by one thread at once (use it via ot_debug_macros like _info macro they do proper locking) */ class cLogger { public: @@ -201,15 +202,21 @@ class cLogger { std::string endline() const; ///< returns string to be written at end of message protected: + void SetStreamBroken(); ///< call in case of internal error in logger (e.g. can not open a file) + void SetStreamBroken(const std::string &msg); ///< same but with error message + unique_ptr<std::ofstream> mOutfile; std::ostream * mStream; ///< pointing only! can point to our own mOutfile, or maye to global null stream + std::ostream * mStreamBrokenDebug; ///< pointing only! this is a pointer to some stream that should be used when normal debugging is broken eg std::cerr + bool mIsBroken; ///< is the debugging system broken (this should be set when internal problems occur and should cause fallback to std::cerr) std::map< std::string , std::ofstream * > mChannels; // the ofstream objects are owned by this class int mLevel; ///< current debug level - std::ostream & SelectOutput(int level, const std::string & channel); - void OpenNewChannel(const std::string & channel); + std::ostream & SelectOutput(int level, const std::string & channel) noexcept; ///< returns a proper stream for this level and channel (always usable string) + void OpenNewChannel(const std::string & channel) noexcept; ///< tries to prepare this channel. does NOT guarantee to created mChannels[] entry! + void OpenNewChannel_(const std::string & channel); ///< internal function, will throw in case of problems std::string GetLogBaseDir() const; std::map< std::thread::id , int > mThread2Number; // change long thread IDs into a short nice number to show @@ -360,7 +367,10 @@ eSubjectType String2SubjectType(const string & type); class cFilesystemUtils { // if we do not want to use boost in given project (or we could optionally write boost here later) public: static bool CreateDirTree(const std::string & dir, bool only_below=false); - static char GetDirSeparator(); // eg '/' or '\' + static char GetDirSeparatorSys(); /// < eg '/' or '\' + static char GetDirSeparatorInter(); /// < internal is '/' + static string FileInternalToSystem(const std::string &name); ///< converts from internal file name string to system file name string + static string FileSystemToInternal(const std::string &name); ///< converts from system file name string to internal file name string }; diff --git a/src/common/util.cpp b/src/common/util.cpp index 907a87cee..94c1e042e 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -326,7 +326,7 @@ std::string get_nix_version_display_string() std::string config_folder; #ifdef WIN32 - config_folder = get_special_folder_path(CSIDL_APPDATA, true) + "/" + CRYPTONOTE_NAME; + config_folder = get_special_folder_path(CSIDL_APPDATA, true) + "\\" + CRYPTONOTE_NAME; #else std::string pathRet; char* pszHome = getenv("HOME"); diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 8497efbf2..8d584af5e 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -125,8 +125,9 @@ int main(int argc, char* argv[]) LOG_PRINT_L0("Starting..."); nOT::nUtils::cFilesystemUtils::CreateDirTree("log/dr-monero/net/"); - // _warn_c("log/test","Starting program"); // TODO - + _warn_c("test","Starting program (a test message)"); + _warn_c("main/program","Starting program"); + TRY_ENTRY(); boost::filesystem::path default_data_path {tools::get_default_data_dir()}; @@ -319,6 +320,7 @@ int main(int argc, char* argv[]) ccore.set_cryptonote_protocol(NULL); cprotocol.set_p2p_endpoint(NULL); + epee::net_utils::data_logger::get_instance().kill_instance(); LOG_PRINT("Node stopped.", LOG_LEVEL_0); return 0; diff --git a/src/p2p/connection_basic.cpp b/src/p2p/connection_basic.cpp index 4a4a32384..ed15c0986 100644 --- a/src/p2p/connection_basic.cpp +++ b/src/p2p/connection_basic.cpp @@ -272,6 +272,7 @@ void connection_basic::logger_handle_net_write(size_t size) { } double connection_basic::get_sleep_time(size_t cb) { + CRITICAL_REGION_LOCAL(epee::net_utils::network_throttle_manager::network_throttle_manager::m_lock_get_global_throttle_out); auto t = network_throttle_manager::get_global_throttle_out().get_sleep_time(cb); return t; } diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp index 77f647bed..d62af133e 100644 --- a/src/p2p/data_logger.cpp +++ b/src/p2p/data_logger.cpp @@ -1,4 +1,5 @@ #include "data_logger.hpp" +#include <stdexcept> #include <boost/chrono.hpp> #include <boost/filesystem.hpp> @@ -9,25 +10,25 @@ namespace epee { namespace net_utils { - data_logger &data_logger::get_instance() - { - static data_logger instance; - return instance; + data_logger &data_logger::get_instance() { + std::call_once(m_singleton, + [] { + _info_c("dbg/data","Creating singleton of data_logger"); + if (m_state != data_logger_state::state_before_init) { _erro_c("dbg/data","Internal error in singleton"); throw std::runtime_error("data_logger singleton"); } + m_state = data_logger_state::state_during_init; + m_obj.reset(new data_logger()); + m_state = data_logger_state::state_ready_to_use; + } + ); + return * m_obj; } - data_logger::data_logger() - { - //create timer - std::shared_ptr<std::thread> logger_thread(new std::thread([&]() - { - while (true) - { - std::this_thread::sleep_for(std::chrono::seconds(1)); - saveToFile(); - } - })); - logger_thread->detach(); + data_logger::data_logger() { + _warn_c("dbg/data","Starting data logger (for graphs data)"); + if (m_state != data_logger_state::state_during_init) { _erro_c("dbg/data","Singleton ctor state"); throw std::runtime_error("data_logger ctor state"); } + std::lock_guard<std::mutex> lock(mMutex); // lock + // prepare all the files for given data channels: mFilesMap["peers"] = data_logger::fileData("log/dr-monero/peers.data"); mFilesMap["download"] = data_logger::fileData("log/dr-monero/net/in-all.data"); mFilesMap["upload"] = data_logger::fileData("log/dr-monero/net/out-all.data"); @@ -44,25 +45,80 @@ namespace net_utils mFilesMap["peers_limit"].mLimitFile = true; mFilesMap["download_limit"].mLimitFile = true; mFilesMap["upload_limit"].mLimitFile = true; + + // do NOT modify mFilesMap below this point, since there is no locking for this used (yet) + + _note_c("dbg/data","Creating thread for data logger"); // create timer thread + m_thread_maybe_running=true; + std::shared_ptr<std::thread> logger_thread(new std::thread([&]() { + _note_c("dbg/data","Inside thread for data logger"); + while (m_state == data_logger_state::state_during_init) { // wait for creation to be done (in other thread, in singleton) before actually running + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + _note_c("dbg/data","Inside thread for data logger - going into main loop"); + while (m_state == data_logger_state::state_ready_to_use) { // run as long as we are not closing the single object + std::this_thread::sleep_for(std::chrono::seconds(1)); + saveToFile(); // save all the pending data + } + _note_c("dbg/data","Inside thread for data logger - done the main loop"); + m_thread_maybe_running=false; + })); + logger_thread->detach(); + _info_c("dbg/data","Data logger constructed"); + } + + data_logger::~data_logger() { + _note_c("dbg/data","Destructor of the data logger"); + { + std::lock_guard<std::mutex> lock(mMutex); + m_state = data_logger_state::state_dying; + } + _info_c("dbg/data","State was set to dying"); + while(m_thread_maybe_running) { // wait for the thread to exit + std::this_thread::sleep_for(std::chrono::seconds(1)); + _info_c("dbg/data","Waiting for background thread to exit"); + } + _info_c("dbg/data","Thread exited"); + } + + void data_logger::kill_instance() { + m_state = m_state = data_logger_state::state_dying; + m_obj.reset(); } - void data_logger::add_data(std::string filename, unsigned int data) - { - if (mFilesMap.find(filename) == mFilesMap.end()) - return; // TODO: exception - - - nOT::nUtils::cFilesystemUtils::CreateDirTree("log/dr-monero/net/"); + void data_logger::add_data(std::string filename, unsigned int data) { + std::lock_guard<std::mutex> lock(mMutex); + if (m_state != data_logger_state::state_ready_to_use) { _info_c("dbg/data","Data logger is not ready, returning."); return; } + + if (mFilesMap.find(filename) == mFilesMap.end()) { // no such file/counter + _erro_c("dbg/data","Trying to use not opened data file filename="<<filename); + _erro_c("dbg/data","Disabling saving of graphs due to error"); + m_save_graph=false; // <--- disabling saving graphs + return; + } - std::lock_guard<std::mutex> lock(mSaveMutex); - if (mFilesMap[filename].mLimitFile) + if (mFilesMap[filename].mLimitFile) { // this holds a number (that is not additive) - e.g. the limit setting mFilesMap[filename].mDataToSave = data; - else - mFilesMap[filename].mDataToSave += data; + } else { + mFilesMap[filename].mDataToSave += data; // this holds a number that should be sum of all accumulated samples + } + } + + void data_logger::saveToFile() { + _dbg2_c("dbg/data","saving to files"); + std::lock_guard<std::mutex> lock(mMutex); + if (m_state != data_logger_state::state_ready_to_use) { _info_c("dbg/data","Data logger is not ready, returning."); return; } + nOT::nUtils::cFilesystemUtils::CreateDirTree("log/dr-monero/net/"); + for (auto &element : mFilesMap) + { + element.second.save(); + if (!element.second.mLimitFile) element.second.mDataToSave = 0; + } } + + // the inner class: - double data_logger::fileData::get_current_time() - { + double data_logger::fileData::get_current_time() { using namespace boost::chrono; auto point = steady_clock::now(); auto time_from_epoh = point.time_since_epoch(); @@ -71,33 +127,28 @@ namespace net_utils return ms_f / 1000.; } - data_logger::fileData::fileData(std::string pFile) - { + data_logger::fileData::fileData(std::string pFile) { + _dbg3_c("dbg/data","opening data file named pFile="<<pFile<<" for this="<<this); mFile = std::make_shared<std::ofstream> (pFile); + _dbg1_c("dbg/data","opened data file named pFile="<<pFile<<" in mFile="<<mFile<<" for this="<<this); mPath = pFile; } - void data_logger::fileData::save() - { - if (!data_logger::m_save_graph) - return; + void data_logger::fileData::save() { + if (!data_logger::m_save_graph) return; // <--- disabled + _dbg2_c("dbg/data","saving to the file now, mFile="<<mFile); mFile->open(mPath, std::ios::app); *mFile << static_cast<int>(get_current_time()) << " " << mDataToSave << std::endl; mFile->close(); } - void data_logger::saveToFile() - { - std::lock_guard<std::mutex> lock(mSaveMutex); - for (auto &element : mFilesMap) - { - element.second.save(); - if (!element.second.mLimitFile) - element.second.mDataToSave = 0; - } - } -std::atomic<bool> data_logger::m_save_graph(false); +data_logger_state data_logger::m_state(data_logger_state::state_before_init); ///< (static) state of the singleton object +std::atomic<bool> data_logger::m_save_graph(false); // (static) +std::atomic<bool> data_logger::m_thread_maybe_running(false); // (static) +std::once_flag data_logger::m_singleton; // (static) +std::unique_ptr<data_logger> data_logger::m_obj; // (static) } // namespace } // namespace + diff --git a/src/p2p/data_logger.hpp b/src/p2p/data_logger.hpp index 50beb847a..215912167 100644 --- a/src/p2p/data_logger.hpp +++ b/src/p2p/data_logger.hpp @@ -13,34 +13,60 @@ namespace epee { namespace net_utils { + +enum class data_logger_state { state_before_init, state_during_init, state_ready_to_use, state_dying }; +/*** +@note: use it ONLY via singleton! It will be spawned then, and will auto destruct on program exit. +@note: do call ::kill_instance() before exiting main, at end of main. But before make sure no one else (e.g. no other threads) will try to use this/singleton +@note: it is not allowed to use this class from code "runnig before or after main", e.g. from ctors of static objects, because of static-creation-order races +@note: on creation (e.g. from singleton), it spawns a thread that saves all data in background +*/ class data_logger { public: - static data_logger &get_instance(); - data_logger(const data_logger &ob) = delete; + static data_logger &get_instance(); ///< singleton + static void kill_instance(); ///< call this before ending main to allow more gracefull shutdown of the main singleton and it's background thread + ~data_logger(); ///< destr, will be called when singleton is killed when global m_obj dies. will kill theads etc + + private: + data_logger(); ///< constructor is private, use only via singleton get_instance + + public: + data_logger(const data_logger &ob) = delete; // use only one per program data_logger(data_logger &&ob) = delete; - void add_data(std::string filename, unsigned int data); - static std::atomic<bool> m_save_graph; + data_logger & operator=(const data_logger&) = delete; + data_logger & operator=(data_logger&&) = delete; + + void add_data(std::string filename, unsigned int data); ///< use this to append data here. Use it only the singleton. It locks itself. + + static std::atomic<bool> m_save_graph; ///< global setting flag, should we save all the data or not (can disable logging graphs data) + private: - data_logger(); - class fileData - { + static std::once_flag m_singleton; ///< to guarantee singleton creates the object exactly once + static data_logger_state m_state; ///< state of the singleton object + static std::atomic<bool> m_thread_maybe_running; ///< is the background thread (more or less) running, or is it fully finished + static std::unique_ptr<data_logger> m_obj; ///< the singleton object. Only use it via get_instance(). Can be killed by kill_instance() + + /*** + * one graph/file with data + */ + class fileData { public: - fileData(){} + fileData() = default; fileData(const fileData &ob) = delete; fileData(std::string pFile); std::shared_ptr<std::ofstream> mFile; - long int mDataToSave = 0; + long int mDataToSave = 0; ///< sum of the data (in current interval, will be counted from 0 on next interval) static double get_current_time(); void save(); std::string mPath; - bool mLimitFile = false; + bool mLimitFile = false; ///< this holds a number (that is not additive) - e.g. the limit setting }; - std::map <std::string, fileData> mFilesMap; - std::mutex mSaveMutex; - void saveToFile(); + std::map<std::string, fileData> mFilesMap; + std::mutex mMutex; + void saveToFile(); ///< write data to the target files. do not use this directly }; } // namespace diff --git a/src/p2p/network_throttle.cpp b/src/p2p/network_throttle.cpp index 3d5edcdcd..7bc89881d 100644 --- a/src/p2p/network_throttle.cpp +++ b/src/p2p/network_throttle.cpp @@ -78,7 +78,6 @@ int network_throttle_manager::xxx; // ================================================================================================ // methods: i_network_throttle & network_throttle_manager::get_global_throttle_in() { - std::call_once(m_once_get_global_throttle_in, [] { m_obj_get_global_throttle_in.reset(new network_throttle("in/all","<<< global-IN",10)); } ); return * m_obj_get_global_throttle_in; } diff --git a/tests/core_proxy/core_proxy.cpp b/tests/core_proxy/core_proxy.cpp index de8f45fc6..879f83ebe 100644 --- a/tests/core_proxy/core_proxy.cpp +++ b/tests/core_proxy/core_proxy.cpp @@ -62,6 +62,8 @@ using namespace crypto; BOOST_CLASS_VERSION(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<tests::proxy_core> >, 1); +unsigned int epee::g_test_dbg_lock_sleep = 0; + int main(int argc, char* argv[]) { @@ -148,6 +150,7 @@ int main(int argc, char* argv[]) LOG_PRINT("Node stopped.", LOG_LEVEL_0); + epee::net_utils::data_logger::get_instance().kill_instance(); return 0; CATCH_ENTRY_L0("main", 1); diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h index 2b807564d..b40c5b216 100644 --- a/tests/core_proxy/core_proxy.h +++ b/tests/core_proxy/core_proxy.h @@ -82,5 +82,7 @@ namespace tests bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp){return true;} bool handle_get_objects(cryptonote::NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote::NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote::cryptonote_connection_context& context){return true;} cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); } + bool get_test_drop_download() {return true;} + bool get_test_drop_download_height() {return true;} }; } diff --git a/tests/core_tests/CMakeLists.txt b/tests/core_tests/CMakeLists.txt index ac536b29e..2b9e0cf81 100644 --- a/tests/core_tests/CMakeLists.txt +++ b/tests/core_tests/CMakeLists.txt @@ -60,6 +60,8 @@ add_executable(coretests target_link_libraries(coretests LINK_PRIVATE cryptonote_core + p2p + ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 0ec4d4581..a9ef8b00b 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -44,6 +44,8 @@ namespace const command_line::arg_descriptor<bool> arg_test_transactions = {"test_transactions", ""}; } +unsigned int epee::g_test_dbg_lock_sleep = 0; + int main(int argc, char* argv[]) { TRY_ENTRY(); diff --git a/tests/functional_tests/main.cpp b/tests/functional_tests/main.cpp index fda64303f..a653e7b1b 100644 --- a/tests/functional_tests/main.cpp +++ b/tests/functional_tests/main.cpp @@ -55,6 +55,8 @@ namespace const command_line::arg_descriptor<size_t> arg_test_repeat_count = {"test_repeat_count", "", 1}; } +unsigned int epee::g_test_dbg_lock_sleep = 0; + int main(int argc, char* argv[]) { TRY_ENTRY(); diff --git a/tests/net_load_tests/CMakeLists.txt b/tests/net_load_tests/CMakeLists.txt index 6095146fb..acd7c9ac9 100644 --- a/tests/net_load_tests/CMakeLists.txt +++ b/tests/net_load_tests/CMakeLists.txt @@ -39,6 +39,7 @@ target_link_libraries(net_load_tests_clt LINK_PRIVATE otshell_utils p2p + cryptonote_core ${GTEST_MAIN_LIBRARIES} ${Boost_CHRONO_LIBRARY} ${Boost_DATE_TIME_LIBRARY} @@ -60,6 +61,7 @@ target_link_libraries(net_load_tests_srv LINK_PRIVATE otshell_utils p2p + cryptonote_core ${GTEST_MAIN_LIBRARIES} ${Boost_CHRONO_LIBRARY} ${Boost_DATE_TIME_LIBRARY} diff --git a/tests/net_load_tests/clt.cpp b/tests/net_load_tests/clt.cpp index 7c9b86cbf..6307f18eb 100644 --- a/tests/net_load_tests/clt.cpp +++ b/tests/net_load_tests/clt.cpp @@ -623,6 +623,8 @@ TEST_F(net_load_test_clt, permament_open_and_close_and_connections_closed_by_ser ASSERT_EQ(RESERVED_CONN_CNT, m_tcp_server.get_config_object().get_connections_count()); } +unsigned int epee::g_test_dbg_lock_sleep = 0; + int main(int argc, char** argv) { epee::debug::get_set_enable_assert(true, false); @@ -631,5 +633,6 @@ int main(int argc, char** argv) epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); ::testing::InitGoogleTest(&argc, argv); + epee::net_utils::data_logger::get_instance().kill_instance(); return RUN_ALL_TESTS(); } diff --git a/tests/net_load_tests/srv.cpp b/tests/net_load_tests/srv.cpp index edb106ea7..582c9efdf 100644 --- a/tests/net_load_tests/srv.cpp +++ b/tests/net_load_tests/srv.cpp @@ -213,6 +213,8 @@ namespace }; } +unsigned int epee::g_test_dbg_lock_sleep = 0; + int main(int argc, char** argv) { //set up logging options @@ -232,6 +234,6 @@ int main(int argc, char** argv) if (!tcp_server.run_server(thread_count, true)) return 2; - + epee::net_utils::data_logger::get_instance().kill_instance(); return 0; } diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index 724b36386..588cf6529 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -42,6 +42,8 @@ #include "generate_key_image_helper.h" #include "is_out_to_acc.h" +unsigned int epee::g_test_dbg_lock_sleep = 0; + int main(int argc, char** argv) { set_process_affinity(1); diff --git a/tests/unit_tests/main.cpp b/tests/unit_tests/main.cpp index e187bf52d..471895b84 100644 --- a/tests/unit_tests/main.cpp +++ b/tests/unit_tests/main.cpp @@ -32,6 +32,8 @@ #include "include_base_utils.h" +unsigned int epee::g_test_dbg_lock_sleep = 0; + int main(int argc, char** argv) { epee::debug::get_set_enable_assert(true, false); |