From cfd299006f7e3d70d5b050f2804f0d95f5cb100a Mon Sep 17 00:00:00 2001 From: jyelon Date: Fri, 11 Mar 2022 19:01:02 -0500 Subject: [PATCH] Replay logging almost done. Only thing missing is stdout. --- luprex/core/cpp/driver-common.cpp | 11 ++-- luprex/core/cpp/driver-util.cpp | 92 ++++++++++++++++++------------ luprex/core/cpp/driver-util.hpp | 37 +++++++----- luprex/core/rep.log | Bin 0 -> 11317 bytes 4 files changed, 83 insertions(+), 57 deletions(-) create mode 100644 luprex/core/rep.log diff --git a/luprex/core/cpp/driver-common.cpp b/luprex/core/cpp/driver-common.cpp index f642e851..02a4505b 100644 --- a/luprex/core/cpp/driver-common.cpp +++ b/luprex/core/cpp/driver-common.cpp @@ -474,10 +474,10 @@ public: drv::ReplayPlayer player; player.open_logfile(fn); while (true) { - drv::ReplayPlayer::Error err = player.step(); - if (err != drv::ReplayPlayer::ERR_NONE) { - player.print_error(std::cerr); - return (err != drv::ReplayPlayer::ERR_LOGFILE_EOF) ? 1 : 0; + drv::ReplayPlayer::Status st = player.step(); + if (st != drv::ReplayPlayer::ST_REPLAYING) { + player.print_status(std::cerr); + return (st == drv::ReplayPlayer::ST_CLEAN_EXIT) ? 0 : 1; } } } @@ -567,6 +567,9 @@ public: SSL_CTX_free(ssl_ctx_with_root_certs_); SSL_CTX_free(ssl_ctx_with_server_certs_); DrivenEngine::set(nullptr); + + recorder_.clean_exit(); + return 0; } }; diff --git a/luprex/core/cpp/driver-util.cpp b/luprex/core/cpp/driver-util.cpp index dd85278e..096f6bfc 100644 --- a/luprex/core/cpp/driver-util.cpp +++ b/luprex/core/cpp/driver-util.cpp @@ -44,6 +44,7 @@ std::vector parse_control_lst(std::string_view ctrl) { enum DrvAction { CREATE_ENGINE, + CLEAN_EXIT, DRV_CLEAR_NEW_OUTGOING, DRV_SENT_OUTGOING, DRV_RECV_INCOMING, @@ -55,9 +56,10 @@ enum DrvAction { DRV_INVOKE_EVENT_UPDATE }; -static const char *action_string(DrvAction act) { +inline static const char *action_string(DrvAction act) { switch(act) { case CREATE_ENGINE: return "CREATE_ENGINE"; + case CLEAN_EXIT: return "CLEAN_EXIT"; case DRV_CLEAR_NEW_OUTGOING: return "DRV_CLEAR_NEW_OUTGOING"; case DRV_SENT_OUTGOING: return "DRV_SENT_OUTGOING"; case DRV_RECV_INCOMING: return "DRV_RECV_INCOMING"; @@ -71,7 +73,6 @@ static const char *action_string(DrvAction act) { } } - static void wlog_uint8(std::ofstream &s, uint8_t v) { s.put((char)v); } @@ -104,7 +105,7 @@ static void wlog_string(std::ofstream &s, std::string_view v) { } static void wlog_cmd_hash(std::ofstream &s, DrvAction act, uint32_t hash) { - std::cerr << "Logging " << action_string(act) << " " << hash << std::endl; + // std::cerr << "Logging " << action_string(act) << " " << hash << std::endl; wlog_uint8(s, act); wlog_uint32(s, hash); } @@ -158,7 +159,7 @@ std::string_view rlog_string(std::ifstream &s, char *rlog_buf) { } ReplayPlayer::ReplayPlayer() { - error_ = ERR_NONE; + status_ = ST_REPLAYING; buf_.reset(new char[RLOG_BUFSIZE]); } @@ -185,25 +186,26 @@ bool ReplayRecorder::open_logfile(const char *fn) { } -ReplayPlayer::Error ReplayPlayer::step() { - if (error_ != ERR_NONE) return error_; +ReplayPlayer::Status ReplayPlayer::step() { + if (status_ != ST_REPLAYING) return status_; uint8_t code = rlog_uint8(f_); if (f_.eof()) { - set_error(ERR_LOGFILE_EOF); - return error_; + set_status(ST_LOGFILE_ENDS_ABRUPTLY); + return status_; } int hash = rlog_uint32(f_); if (!f_.good()) { - set_error(ERR_LOGFILE_CORRUPT); - return error_; + set_status(ST_LOGFILE_CORRUPT); + return status_; } - std::cerr << "Executing: " << action_string(DrvAction(code)) << " " << eng::memhash() << std::endl; + // std::cerr << "Executing: " << action_string(DrvAction(code)) << " " << eng::memhash() << std::endl; if (hash != eng::memhash()) { - set_error(ERR_NONDERMINISTIC); - return error_; + set_status(ST_NONDERMINISTIC); + return status_; } switch (code) { case CREATE_ENGINE: create_engine(); break; + case CLEAN_EXIT: clean_exit(); break; case DRV_CLEAR_NEW_OUTGOING: drv_clear_new_outgoing(); break; case DRV_SENT_OUTGOING: drv_sent_outgoing(); break; case DRV_RECV_INCOMING: drv_recv_incoming(); break; @@ -216,33 +218,36 @@ ReplayPlayer::Error ReplayPlayer::step() { default: assert(false && "Replay Log contains invalid command."); } - return error_; + return status_; } -void ReplayPlayer::set_error(Error e) { - error_ = e; +void ReplayPlayer::set_status(Status e) { + status_ = e; f_.close(); f_.clear(); } -void ReplayPlayer::print_error(std::ostream &s) { - switch (error_) { - case ERR_NONE: +void ReplayPlayer::print_status(std::ostream &s) { + switch (status_) { + case ST_REPLAYING: s << "No errors detected: " << logfn_ << std::endl; return; - case ERR_OPEN_LOGFILE: + case ST_CLEAN_EXIT: + s << "Engine exited cleanly without errors: " << logfn_ << std::endl; + return; + case ST_ERR_OPENING_LOGFILE: s << "Could not open logfile: " << logfn_ << std::endl; return; - case ERR_LOGFILE_EOF: + case ST_LOGFILE_ENDS_ABRUPTLY: s << "Logfile reached end-of-file: " << logfn_ << std::endl; return; - case ERR_LOGFILE_CORRUPT: + case ST_LOGFILE_CORRUPT: s << "Logfile corrupt: " << logfn_ << std::endl; return; - case ERR_NONDERMINISTIC: + case ST_NONDERMINISTIC: s << "Nondeterminism detected: " << logfn_ << std::endl; return; - case ERR_CREATE_ENGINE: + case ST_COULDNT_CREATE_ENGINE: s << "Could not create engine: " << logfn_ << " " << engine_ << std::endl; return; } @@ -253,7 +258,7 @@ bool ReplayPlayer::open_logfile(const char *fn) { f_.clear(); f_.open(fn, std::ios_base::in | std::ios_base::binary); if (!f_.good()) { - set_error(ERR_OPEN_LOGFILE); + set_status(ST_ERR_OPENING_LOGFILE); return false; } return true; @@ -273,18 +278,29 @@ bool ReplayRecorder::create_engine(const char *kind) { void ReplayPlayer::create_engine() { std::string_view kind = rlog_string(f_, buf_.get()); if (!f_.good()) { - set_error(ERR_LOGFILE_CORRUPT); + set_status(ST_LOGFILE_CORRUPT); return; } engine_ = std::string(kind); e_ = DrivenEngine::make(kind); DrivenEngine::set(e_.get()); if (e_ == nullptr) { - set_error(ERR_CREATE_ENGINE); + set_status(ST_COULDNT_CREATE_ENGINE); return; } } +void ReplayRecorder::clean_exit() { + if (logging_) { + wlog_cmd_hash(f_, CLEAN_EXIT, eng::memhash()); + flush(); + } +} + +void ReplayPlayer::clean_exit() { + set_status(ST_CLEAN_EXIT); +} + void ReplayRecorder::drv_clear_new_outgoing() { if (logging_) { wlog_cmd_hash(f_, DRV_CLEAR_NEW_OUTGOING, eng::memhash()); @@ -316,16 +332,16 @@ void ReplayPlayer::drv_sent_outgoing() { int nbytes = rlog_uint16(f_); uint64_t hash = rlog_uint64(f_); if (!f_.good()) { - set_error(ERR_LOGFILE_CORRUPT); + set_status(ST_LOGFILE_CORRUPT); return; } std::string_view data = e_->drv_peek_outgoing(chid); if (nbytes > int(data.size())) { - set_error(ERR_NONDERMINISTIC); + set_status(ST_NONDERMINISTIC); return; } if (hash != SpookyHash::QkHash64(data.data(), nbytes)) { - set_error(ERR_NONDERMINISTIC); + set_status(ST_NONDERMINISTIC); return; } e_->drv_sent_outgoing(chid, nbytes); @@ -345,7 +361,7 @@ void ReplayPlayer::drv_recv_incoming() { int chid = rlog_uint16(f_); std::string_view data = rlog_string(f_, buf_.get()); if (!f_.good()) { - set_error(ERR_LOGFILE_CORRUPT); + set_status(ST_LOGFILE_CORRUPT); return; } e_->drv_recv_incoming(chid, data); @@ -365,7 +381,7 @@ void ReplayPlayer::drv_notify_close() { int chid = rlog_uint16(f_); std::string_view err = rlog_string(f_, buf_.get()); if (!f_.good()) { - set_error(ERR_LOGFILE_CORRUPT); + set_status(ST_LOGFILE_CORRUPT); return; } e_->drv_notify_close(chid, err); @@ -383,7 +399,7 @@ int ReplayRecorder::drv_notify_accept(int port) { void ReplayPlayer::drv_notify_accept() { int port = rlog_uint16(f_); if (!f_.good()) { - set_error(ERR_LOGFILE_CORRUPT); + set_status(ST_LOGFILE_CORRUPT); return; } e_->drv_notify_accept(port); @@ -415,7 +431,7 @@ void ReplayPlayer::drv_add_lua_source() { std::string fn(rlog_string(f_, buf_.get())); std::string_view data = rlog_string(f_, buf_.get()); if (!f_.good()) { - set_error(ERR_LOGFILE_CORRUPT); + set_status(ST_LOGFILE_CORRUPT); return; } e_->drv_add_lua_source(fn, data); @@ -438,17 +454,17 @@ void ReplayPlayer::drv_invoke_event_init() { std::vector argv; int argc = rlog_uint16(f_); if (!f_.good()) { - set_error(ERR_LOGFILE_CORRUPT); + set_status(ST_LOGFILE_CORRUPT); return; } if (argc > MAX_ARGC) { - set_error(ERR_LOGFILE_CORRUPT); + set_status(ST_LOGFILE_CORRUPT); return; } for (int i = 0; i < argc; i++) { std::string_view arg = rlog_string(f_, buf_.get()); if (!f_.good()) { - set_error(ERR_LOGFILE_CORRUPT); + set_status(ST_LOGFILE_CORRUPT); return; } argv.emplace_back(arg); @@ -472,7 +488,7 @@ void ReplayRecorder::drv_invoke_event_update(double clock) { void ReplayPlayer::drv_invoke_event_update() { double clock = rlog_double(f_); if (!f_.good()) { - set_error(ERR_LOGFILE_CORRUPT); + set_status(ST_LOGFILE_CORRUPT); return; } e_->drv_invoke_event_update(clock); diff --git a/luprex/core/cpp/driver-util.hpp b/luprex/core/cpp/driver-util.hpp index 1494941c..2d3f0af2 100644 --- a/luprex/core/cpp/driver-util.hpp +++ b/luprex/core/cpp/driver-util.hpp @@ -49,6 +49,11 @@ public: // bool create_engine(const char *kind); + // Report to the logger that the engine is about to exit cleanly, + // without any error. + // + void clean_exit(); + // These don't need to be logged. // const eng::vector &drv_get_listen_ports() const { return e_->drv_get_listen_ports(); } @@ -75,25 +80,27 @@ public: class ReplayPlayer { public: - enum Error { - ERR_NONE, - ERR_OPEN_LOGFILE, - ERR_LOGFILE_EOF, - ERR_LOGFILE_CORRUPT, - ERR_NONDERMINISTIC, - ERR_CREATE_ENGINE, + enum Status { + ST_REPLAYING, + ST_CLEAN_EXIT, + ST_ERR_OPENING_LOGFILE, + ST_LOGFILE_ENDS_ABRUPTLY, + ST_LOGFILE_CORRUPT, + ST_NONDERMINISTIC, + ST_COULDNT_CREATE_ENGINE, }; private: std::ifstream f_; UniqueDrivenEngine e_; std::unique_ptr buf_; - Error error_; + Status status_; std::string logfn_; std::string engine_; - void set_error(Error e); + void set_status(Status e); void create_engine(); + void clean_exit(); void drv_clear_new_outgoing(); void drv_sent_outgoing(); void drv_recv_incoming(); @@ -114,16 +121,16 @@ public: // Execute a single step from the replay log. // - // Returns an error code, which is usually ERR_NONE. - // If it's anything else, display an error and stop. + // Returns a status code, which is usually ST_REPLAYING. + // If it's anything else, display the status and stop. // - Error step(); + Status step(); - // Print an error message. + // Print a status message. // - // Print a message associated with the most recent error. + // Print a message associated with the most recent status report. // - void print_error(std::ostream &s); + void print_status(std::ostream &s); }; } // namespace drv diff --git a/luprex/core/rep.log b/luprex/core/rep.log new file mode 100644 index 0000000000000000000000000000000000000000..40bc80d4a9d1ab3a0d88131b06629761109483ff GIT binary patch literal 11317 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 literal 0 HcmV?d00001