aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrfree2monero <rfreemonero@op.pl>2015-02-24 20:12:56 +0100
committerrfree2monero <rfreemonero@op.pl>2015-02-24 20:12:56 +0100
commit0198ffb2201e6e089aa385f80a1407e450a9856b (patch)
tree1f8590d4c9c8be52adfc832873c65a160b151c35
parent2014 network limit 1.2 +utils +toc -doc -drmonero (diff)
downloadmonero-0198ffb2201e6e089aa385f80a1407e450a9856b.tar.xz
2014 network limit 1.3 fix log/path/data +utils
+toc -doc -drmonero Fixed the windows path, and improved logging and data (for graph) logging, fixed some locks and added more checks. Still there is a locking error, not added by my patches, but present in master version (locking of map/list of peers).
-rw-r--r--.gitignore1
-rw-r--r--contrib/otshell_utils/utils.cpp170
-rw-r--r--contrib/otshell_utils/utils.hpp16
-rw-r--r--src/common/util.cpp2
-rw-r--r--src/daemon/daemon.cpp6
-rw-r--r--src/p2p/connection_basic.cpp1
-rw-r--r--src/p2p/data_logger.cpp143
-rw-r--r--src/p2p/data_logger.hpp52
-rw-r--r--src/p2p/network_throttle.cpp1
-rw-r--r--tests/core_proxy/core_proxy.cpp3
-rw-r--r--tests/core_proxy/core_proxy.h2
-rw-r--r--tests/core_tests/CMakeLists.txt2
-rw-r--r--tests/core_tests/chaingen_main.cpp2
-rw-r--r--tests/functional_tests/main.cpp2
-rw-r--r--tests/net_load_tests/CMakeLists.txt2
-rw-r--r--tests/net_load_tests/clt.cpp3
-rw-r--r--tests/net_load_tests/srv.cpp4
-rw-r--r--tests/performance_tests/main.cpp2
-rw-r--r--tests/unit_tests/main.cpp2
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);