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).
This commit is contained in:
rfree2monero 2015-02-24 20:12:56 +01:00
parent ae2a50659f
commit 0198ffb220
19 changed files with 306 additions and 110 deletions

1
.gitignore vendored
View file

@ -59,7 +59,6 @@ version/
### CMake ### ### CMake ###
CMakeCache.txt CMakeCache.txt
CMakeFiles CMakeFiles
Makefile
cmake_install.cmake cmake_install.cmake
install_manifest.txt install_manifest.txt
*.cmake *.cmake

View file

@ -160,7 +160,7 @@ std::unique_ptr<T> make_unique( Args&& ...args )
#endif #endif
// ==================================================================== // ====================================================================
char cFilesystemUtils::GetDirSeparator() { char cFilesystemUtils::GetDirSeparatorSys() {
// TODO nicer os detection? // TODO nicer os detection?
#if defined(OS_TYPE_POSIX) #if defined(OS_TYPE_POSIX)
return '/'; return '/';
@ -171,26 +171,49 @@ char cFilesystemUtils::GetDirSeparator() {
#endif #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) { bool cFilesystemUtils::CreateDirTree(const std::string & dir, bool only_below) {
const bool dbg=false; const bool dbg=false;
//struct stat st; //struct stat st;
const char dirch = cFilesystemUtils::GetDirSeparator(); const char dirchS = cFilesystemUtils::GetDirSeparatorSys();
const char dirchI = cFilesystemUtils::GetDirSeparatorInter();
std::istringstream iss(dir); 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 if (dir.size()<1) return false; // illegal name
// dir[0] is valid from here // dir[0] is valid from here
if (only_below && (dir[0]==dirch)) return false; // no jumping to top (on any os) if ( only_below && ((dir[0]==dirchS) || (dir[0]==dirchI))) 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; 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? // TODO nicer os detection?
#if defined(OS_TYPE_POSIX) #if defined(OS_TYPE_POSIX)
struct stat st; struct stat st;
bool exists = stat(sofar.c_str() ,&st) == 0; // * bool exists = stat(sofarS.c_str() ,&st) == 0; // *
if (exists) { if (exists) {
if (! S_ISDIR(st.st_mode)) { if (! S_ISDIR(st.st_mode)) {
// std::cerr << "This exists, but as a file: [" << sofar << "]" << (size_t)st.st_ino << endl; // 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) #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)); bool exists = (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
#else #else
#error "Do not know how to compile this for your platform." #error "Do not know how to compile this for your platform."
#endif #endif
if (!exists) { if (!exists) {
if (dbg) cout << "mkdir ["<<sofar<<"]"<<endl; if (dbg) cout << "mkdir ["<<sofarS<<"]"<<endl;
#if defined(OS_TYPE_POSIX) #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) #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 #else
#error "Do not know how to compile this for your platform." #error "Do not know how to compile this for your platform."
#endif #endif
if (!ok) return false; if (!ok) return false;
} }
sofar += cFilesystemUtils::GetDirSeparator(); sofarS += dirchS;
} }
return true; return true;
} }
@ -244,11 +267,15 @@ void cDebugScopeGuard::Assign(const string &chan, const int level, const string
cLogger::cLogger() : cLogger::cLogger() :
mStream(NULL), mStream(NULL),
mStreamBrokenDebug(NULL),
mIsBroken(true), // before constructor finishes
mLevel(85), mLevel(85),
mThread2Number_Biggest(0) // the CURRENT biggest value (no thread yet in map) mThread2Number_Biggest(0) // the CURRENT biggest value (no thread yet in map)
{ {
mStream = & std::cout; 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 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() { 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) { std::ostream & cLogger::write_stream(int level) {
return write_stream(level,""); return write_stream(level,"");
} }
std::ostream & cLogger::write_stream(int level, const std::string & channel ) { 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); ostream & output = SelectOutput(level,channel);
output << icon(level) << ' '; output << icon(level) << ' ';
std::thread::id this_id = std::this_thread::get_id(); std::thread::id this_id = std::this_thread::get_id();
@ -278,33 +321,76 @@ std::string cLogger::GetLogBaseDir() const {
return "log"; return "log";
} }
void cLogger::OpenNewChannel(const std::string & channel) { void cLogger::OpenNewChannel(const std::string & channel) noexcept {
size_t last_split = channel.find_last_of(cFilesystemUtils::GetDirSeparator()); try {
// log/test/aaa 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 { // there is a directory eg channel=="net/sleep"
// net/sleep
// ^----- last_split // ^----- last_split
string dir = GetLogBaseDir() + cFilesystemUtils::GetDirSeparator() + channel.substr(0, last_split); string dir = GetLogBaseDir() + cFilesystemUtils::GetDirSeparatorInter() + channel.substr(0, last_split);
string basefile = channel.substr(last_split+1) + ".log"; string basefile = channel.substr(last_split+1) + ".log";
string fname = dir + cFilesystemUtils::GetDirSeparator() + cFilesystemUtils::GetDirSeparator() + basefile; string fname = dir + cFilesystemUtils::GetDirSeparatorInter() + basefile;
_dbg1("Starting debug to channel file: " + fname + " in directory ["+dir+"]"); fname_system = cFilesystemUtils::FileInternalToSystem(fname); // <-
bool dirok = cFilesystemUtils::CreateDirTree(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); } 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.c_str() ); }
*thefile << "====== (Log opened: " << fname << ") ======" << endl;
mChannels.insert( std::pair<string,std::ofstream*>(channel , thefile ) ); 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) { std::ostream & cLogger::SelectOutput(int level, const std::string & channel) noexcept {
try {
if (mIsBroken) return *mStreamBrokenDebug;
if (channel=="") return *mStream; if (channel=="") return *mStream;
auto obj = mChannels.find(channel);
if (obj == mChannels.end()) { // new channel
OpenNewChannel(channel);
return SelectOutput(level,channel);
}
else { // existing
return * obj->second;
}
}
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 void cLogger::setOutStreamFile(const string &fname) { // switch to using this file
_mark("WILL SWITCH DEBUG NOW to file: " << fname); _mark("WILL SWITCH DEBUG NOW to file: " << fname);

View file

@ -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! @brief Class to write debug into. Used it by calling the debug macros _dbg1(...) _info(...) _erro(...) etc, NOT directly!
@author rfree (maintainer) @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 { class cLogger {
public: public:
@ -201,15 +202,21 @@ class cLogger {
std::string endline() const; ///< returns string to be written at end of message std::string endline() const; ///< returns string to be written at end of message
protected: 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; unique_ptr<std::ofstream> mOutfile;
std::ostream * mStream; ///< pointing only! can point to our own mOutfile, or maye to global null stream 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 std::map< std::string , std::ofstream * > mChannels; // the ofstream objects are owned by this class
int mLevel; ///< current debug level int mLevel; ///< current debug level
std::ostream & SelectOutput(int level, 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); 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::string GetLogBaseDir() const;
std::map< std::thread::id , int > mThread2Number; // change long thread IDs into a short nice number to show 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) class cFilesystemUtils { // if we do not want to use boost in given project (or we could optionally write boost here later)
public: public:
static bool CreateDirTree(const std::string & dir, bool only_below=false); 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
}; };

View file

@ -326,7 +326,7 @@ std::string get_nix_version_display_string()
std::string config_folder; std::string config_folder;
#ifdef WIN32 #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 #else
std::string pathRet; std::string pathRet;
char* pszHome = getenv("HOME"); char* pszHome = getenv("HOME");

View file

@ -125,7 +125,8 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Starting..."); LOG_PRINT_L0("Starting...");
nOT::nUtils::cFilesystemUtils::CreateDirTree("log/dr-monero/net/"); 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(); TRY_ENTRY();
@ -319,6 +320,7 @@ int main(int argc, char* argv[])
ccore.set_cryptonote_protocol(NULL); ccore.set_cryptonote_protocol(NULL);
cprotocol.set_p2p_endpoint(NULL); cprotocol.set_p2p_endpoint(NULL);
epee::net_utils::data_logger::get_instance().kill_instance();
LOG_PRINT("Node stopped.", LOG_LEVEL_0); LOG_PRINT("Node stopped.", LOG_LEVEL_0);
return 0; return 0;

View file

@ -272,6 +272,7 @@ void connection_basic::logger_handle_net_write(size_t size) {
} }
double connection_basic::get_sleep_time(size_t cb) { 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); auto t = network_throttle_manager::get_global_throttle_out().get_sleep_time(cb);
return t; return t;
} }

View file

@ -1,4 +1,5 @@
#include "data_logger.hpp" #include "data_logger.hpp"
#include <stdexcept>
#include <boost/chrono.hpp> #include <boost/chrono.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
@ -9,25 +10,25 @@ namespace epee
{ {
namespace net_utils namespace net_utils
{ {
data_logger &data_logger::get_instance() data_logger &data_logger::get_instance() {
{ std::call_once(m_singleton,
static data_logger instance; [] {
return instance; _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() data_logger::data_logger() {
{ _warn_c("dbg/data","Starting data logger (for graphs data)");
//create timer 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::shared_ptr<std::thread> logger_thread(new std::thread([&]() std::lock_guard<std::mutex> lock(mMutex); // lock
{
while (true)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
saveToFile();
}
}));
logger_thread->detach();
// prepare all the files for given data channels:
mFilesMap["peers"] = data_logger::fileData("log/dr-monero/peers.data"); mFilesMap["peers"] = data_logger::fileData("log/dr-monero/peers.data");
mFilesMap["download"] = data_logger::fileData("log/dr-monero/net/in-all.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"); 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["peers_limit"].mLimitFile = true;
mFilesMap["download_limit"].mLimitFile = true; mFilesMap["download_limit"].mLimitFile = true;
mFilesMap["upload_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");
} }
void data_logger::add_data(std::string filename, unsigned int data) data_logger::~data_logger() {
_note_c("dbg/data","Destructor of the data logger");
{ {
if (mFilesMap.find(filename) == mFilesMap.end()) std::lock_guard<std::mutex> lock(mMutex);
return; // TODO: exception 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();
}
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; }
std::lock_guard<std::mutex> lock(mSaveMutex); if (mFilesMap.find(filename) == mFilesMap.end()) { // no such file/counter
if (mFilesMap[filename].mLimitFile) _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;
}
if (mFilesMap[filename].mLimitFile) { // this holds a number (that is not additive) - e.g. the limit setting
mFilesMap[filename].mDataToSave = data; mFilesMap[filename].mDataToSave = data;
else } else {
mFilesMap[filename].mDataToSave += data; mFilesMap[filename].mDataToSave += data; // this holds a number that should be sum of all accumulated samples
}
} }
double data_logger::fileData::get_current_time() 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() {
using namespace boost::chrono; using namespace boost::chrono;
auto point = steady_clock::now(); auto point = steady_clock::now();
auto time_from_epoh = point.time_since_epoch(); auto time_from_epoh = point.time_since_epoch();
@ -71,33 +127,28 @@ namespace net_utils
return ms_f / 1000.; 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); 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; mPath = pFile;
} }
void data_logger::fileData::save() void data_logger::fileData::save() {
{ if (!data_logger::m_save_graph) return; // <--- disabled
if (!data_logger::m_save_graph) _dbg2_c("dbg/data","saving to the file now, mFile="<<mFile);
return;
mFile->open(mPath, std::ios::app); mFile->open(mPath, std::ios::app);
*mFile << static_cast<int>(get_current_time()) << " " << mDataToSave << std::endl; *mFile << static_cast<int>(get_current_time()) << " " << mDataToSave << std::endl;
mFile->close(); 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
} // namespace } // namespace

View file

@ -14,33 +14,59 @@ namespace epee
namespace net_utils 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 { class data_logger {
public: public:
static data_logger &get_instance(); static data_logger &get_instance(); ///< singleton
data_logger(const data_logger &ob) = delete; 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(data_logger &&ob) = delete; ~data_logger(); ///< destr, will be called when singleton is killed when global m_obj dies. will kill theads etc
void add_data(std::string filename, unsigned int data);
static std::atomic<bool> m_save_graph;
private: private:
data_logger(); data_logger(); ///< constructor is private, use only via singleton get_instance
class fileData
{
public: public:
fileData(){} data_logger(const data_logger &ob) = delete; // use only one per program
data_logger(data_logger &&ob) = delete;
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:
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() = default;
fileData(const fileData &ob) = delete; fileData(const fileData &ob) = delete;
fileData(std::string pFile); fileData(std::string pFile);
std::shared_ptr<std::ofstream> mFile; 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(); static double get_current_time();
void save(); void save();
std::string mPath; 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::map<std::string, fileData> mFilesMap;
std::mutex mSaveMutex; std::mutex mMutex;
void saveToFile(); void saveToFile(); ///< write data to the target files. do not use this directly
}; };
} // namespace } // namespace

View file

@ -78,7 +78,6 @@ int network_throttle_manager::xxx;
// ================================================================================================ // ================================================================================================
// methods: // methods:
i_network_throttle & network_throttle_manager::get_global_throttle_in() { 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)); } ); 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; return * m_obj_get_global_throttle_in;
} }

View file

@ -62,6 +62,8 @@ using namespace crypto;
BOOST_CLASS_VERSION(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<tests::proxy_core> >, 1); 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[]) int main(int argc, char* argv[])
{ {
@ -148,6 +150,7 @@ int main(int argc, char* argv[])
LOG_PRINT("Node stopped.", LOG_LEVEL_0); LOG_PRINT("Node stopped.", LOG_LEVEL_0);
epee::net_utils::data_logger::get_instance().kill_instance();
return 0; return 0;
CATCH_ENTRY_L0("main", 1); CATCH_ENTRY_L0("main", 1);

View file

@ -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 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;} 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."); } 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;}
}; };
} }

View file

@ -60,6 +60,8 @@ add_executable(coretests
target_link_libraries(coretests target_link_libraries(coretests
LINK_PRIVATE LINK_PRIVATE
cryptonote_core cryptonote_core
p2p
${Boost_CHRONO_LIBRARY}
${Boost_FILESYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY}
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}

View file

@ -44,6 +44,8 @@ namespace
const command_line::arg_descriptor<bool> arg_test_transactions = {"test_transactions", ""}; 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[]) int main(int argc, char* argv[])
{ {
TRY_ENTRY(); TRY_ENTRY();

View file

@ -55,6 +55,8 @@ namespace
const command_line::arg_descriptor<size_t> arg_test_repeat_count = {"test_repeat_count", "", 1}; 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[]) int main(int argc, char* argv[])
{ {
TRY_ENTRY(); TRY_ENTRY();

View file

@ -39,6 +39,7 @@ target_link_libraries(net_load_tests_clt
LINK_PRIVATE LINK_PRIVATE
otshell_utils otshell_utils
p2p p2p
cryptonote_core
${GTEST_MAIN_LIBRARIES} ${GTEST_MAIN_LIBRARIES}
${Boost_CHRONO_LIBRARY} ${Boost_CHRONO_LIBRARY}
${Boost_DATE_TIME_LIBRARY} ${Boost_DATE_TIME_LIBRARY}
@ -60,6 +61,7 @@ target_link_libraries(net_load_tests_srv
LINK_PRIVATE LINK_PRIVATE
otshell_utils otshell_utils
p2p p2p
cryptonote_core
${GTEST_MAIN_LIBRARIES} ${GTEST_MAIN_LIBRARIES}
${Boost_CHRONO_LIBRARY} ${Boost_CHRONO_LIBRARY}
${Boost_DATE_TIME_LIBRARY} ${Boost_DATE_TIME_LIBRARY}

View file

@ -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()); 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) int main(int argc, char** argv)
{ {
epee::debug::get_set_enable_assert(true, false); 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); epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);
epee::net_utils::data_logger::get_instance().kill_instance();
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }

View file

@ -213,6 +213,8 @@ namespace
}; };
} }
unsigned int epee::g_test_dbg_lock_sleep = 0;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
//set up logging options //set up logging options
@ -232,6 +234,6 @@ int main(int argc, char** argv)
if (!tcp_server.run_server(thread_count, true)) if (!tcp_server.run_server(thread_count, true))
return 2; return 2;
epee::net_utils::data_logger::get_instance().kill_instance();
return 0; return 0;
} }

View file

@ -42,6 +42,8 @@
#include "generate_key_image_helper.h" #include "generate_key_image_helper.h"
#include "is_out_to_acc.h" #include "is_out_to_acc.h"
unsigned int epee::g_test_dbg_lock_sleep = 0;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
set_process_affinity(1); set_process_affinity(1);

View file

@ -32,6 +32,8 @@
#include "include_base_utils.h" #include "include_base_utils.h"
unsigned int epee::g_test_dbg_lock_sleep = 0;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
epee::debug::get_set_enable_assert(true, false); epee::debug::get_set_enable_assert(true, false);