Convert DrivenEngine rlog/wlog to use BaseWriter

This commit is contained in:
2023-07-25 16:46:56 -04:00
parent b9c64fcffb
commit 2dff145885
3 changed files with 88 additions and 139 deletions

View File

@@ -213,100 +213,42 @@ inline static const char *action_string(DrvAction act) {
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
class PlayLogfile : public std::ofstream { using std::ofstream::ofstream; }; class PlayLogfile : public BaseWriter<PlayLogfile>, public std::ofstream {
class ReplayLogfile : public std::ifstream { using std::ifstream::ifstream; }; using std::ofstream::ofstream;
public:
static uint8_t rlog_uint8(EngineWrapper *w) { void write_bytes(const char *n, size_t size) { write(n, size); }
uint8_t result; void raise_truncated() {
w->rlog->read((char *)&result, 1); fprintf(stderr, "number exceeds allowable size\n");
if (!w->rlog->good()) return 0; std::abort();
return result;
}
static uint32_t rlog_uint32(EngineWrapper *w) {
uint32_t result;
w->rlog->read((char *)&result, 4);
if (!w->rlog->good()) return 0;
return result;
}
static uint64_t rlog_uint64(EngineWrapper *w) {
uint64_t result;
w->rlog->read((char *)&result, 8);
if (!w->rlog->good()) return 0;
return result;
}
static double rlog_double(EngineWrapper *w) {
double result;
w->rlog->read((char *)&result, 8);
if (!w->rlog->good()) return 0.0;
return result;
}
std::string_view rlog_short_string(EngineWrapper *w) {
uint32_t len = rlog_uint8(w);
if (len == 255) {
len = rlog_uint32(w);
} }
assert (len <= DRV_SHORTSTRING_SIZE); void write_short_string(std::string_view v) {
if (len > 0) w->rlog->read(w->databuffer, len); assert(v.size() < DRV_SHORTSTRING_SIZE);
if (!w->rlog->good()) return std::string_view(); write_string(v);
return std::string_view(w->databuffer, len);
}
std::string rlog_string(EngineWrapper *w) {
uint32_t len = rlog_uint8(w);
if (len == 255) {
len = rlog_uint32(w);
} }
std::string result(len, ' '); void write_cmd_hash(DrvAction act, uint32_t hash) {
if (len > 0) w->rlog->read(&result[0], len); write_uint8(act);
if (!w->rlog->good()) return ""; write_uint32(hash);
return result;
}
static void wlog_uint8(EngineWrapper *w, uint8_t v) {
w->wlog->put((char)v);
}
static void wlog_uint32(EngineWrapper *w, uint32_t v) {
w->wlog->write((const char *)&v, 4);
}
static void wlog_uint64(EngineWrapper *w, uint64_t v) {
w->wlog->write((const char *)&v, 8);
}
static void wlog_double(EngineWrapper *w, double v) {
w->wlog->write((const char *)&v, 8);
}
static void wlog_short_string(EngineWrapper *w, std::string_view v) {
assert (v.size() <= DRV_SHORTSTRING_SIZE);
if (v.size() >= 255) {
wlog_uint8(w, 0xFF);
wlog_uint32(w, v.size());
} else {
wlog_uint8(w, v.size());
} }
w->wlog->write(v.data(), v.size()); };
}
static void wlog_string(EngineWrapper *w, std::string_view v) { class ReplayLogfile : public BaseReader<ReplayLogfile>, public std::ifstream {
if (v.size() >= 255) { using std::ifstream::ifstream;
wlog_uint8(w, 0xFF); public:
wlog_uint32(w, v.size()); using read_string_type = std::string;
} else { void read_bytes_into(char *n, size_t size) { read(n, size); }
wlog_uint8(w, v.size()); bool read_beyond_eof() { return !good(); }
void raise_string_too_long() {
fprintf(stderr, "string in logfile is too long");
std::abort();
} }
w->wlog->write(v.data(), v.size()); std::string_view read_short_string(EngineWrapper *w) {
} size_t size = read_length();
assert(size <= DRV_SHORTSTRING_SIZE);
static void wlog_cmd_hash(EngineWrapper *w, DrvAction act, uint32_t hash) { if (size > 0) read(w->databuffer, size);
wlog_uint8(w, act); if (!good()) return std::string_view();
wlog_uint32(w, hash); return std::string_view(w->databuffer, size);
} }
};
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -350,7 +292,7 @@ static void reset_wrapper(EngineWrapper *w, const char *format, ...) {
static void release(EngineWrapper *w) { static void release(EngineWrapper *w) {
if (w->wlog != nullptr) { if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_RELEASE, eng::memhash()); w->wlog->write_cmd_hash(PLAY_RELEASE, eng::memhash());
} }
reset_wrapper(w, ""); reset_wrapper(w, "");
}; };
@@ -630,12 +572,12 @@ static void play_initialize(EngineWrapper *w, uint32_t argc, char **argv, uint32
// If we have a logfile, then log this initialization. // If we have a logfile, then log this initialization.
if (w->wlog != nullptr) { if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_INITIALIZE, eng::memhash()); w->wlog->write_cmd_hash(PLAY_INITIALIZE, eng::memhash());
wlog_uint32(w, argc); w->wlog->write_uint32(argc);
for (uint32_t i = 0; i < argc; i++) { for (uint32_t i = 0; i < argc; i++) {
wlog_string(w, argv[i]); w->wlog->write_string(argv[i]);
} }
wlog_string(w, std::string_view(srcpk, srcpklen)); w->wlog->write_string(std::string_view(srcpk, srcpklen));
w->wlog->flush(); w->wlog->flush();
} }
@@ -662,11 +604,11 @@ static void play_initialize(EngineWrapper *w, uint32_t argc, char **argv, uint32
static void replay_initialize(EngineWrapper *w) { static void replay_initialize(EngineWrapper *w) {
assert(w->rlog != nullptr); assert(w->rlog != nullptr);
std::vector<std::string> argvstr; std::vector<std::string> argvstr;
uint32_t argc = rlog_uint32(w); uint32_t argc = w->rlog->read_uint32();
for (uint32_t i = 0; i < argc; i++) { for (uint32_t i = 0; i < argc; i++) {
argvstr.push_back(rlog_string(w)); argvstr.push_back(w->rlog->read_string());
} }
std::string srcpk = rlog_string(w); std::string srcpk = w->rlog->read_string();
if (!w->rlog->good()) { if (!w->rlog->good()) {
return reset_wrapper(w, "replay log corrupt in replay_initialize"); return reset_wrapper(w, "replay log corrupt in replay_initialize");
@@ -697,7 +639,7 @@ static void replay_initialize(EngineWrapper *w) {
static void play_clear_new_outgoing(EngineWrapper *w) { static void play_clear_new_outgoing(EngineWrapper *w) {
assert(w->rlog == nullptr); assert(w->rlog == nullptr);
if (w->wlog != nullptr) { if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_CLEAR_NEW_OUTGOING, eng::memhash()); w->wlog->write_cmd_hash(PLAY_CLEAR_NEW_OUTGOING, eng::memhash());
w->wlog->flush(); w->wlog->flush();
} }
w->engine->drv_clear_new_outgoing(); w->engine->drv_clear_new_outgoing();
@@ -717,19 +659,19 @@ static void play_sent_outgoing(EngineWrapper *w, uint32_t chid, uint32_t nbytes)
uint32_t ndata; const char *data; uint32_t ndata; const char *data;
w->engine->drv_get_outgoing(chid, &ndata, &data); w->engine->drv_get_outgoing(chid, &ndata, &data);
assert(nbytes <= ndata); assert(nbytes <= ndata);
wlog_cmd_hash(w, PLAY_SENT_OUTGOING, eng::memhash()); w->wlog->write_cmd_hash(PLAY_SENT_OUTGOING, eng::memhash());
wlog_uint32(w, chid); w->wlog->write_uint32(chid);
wlog_uint32(w, nbytes); w->wlog->write_uint32(nbytes);
wlog_uint64(w, SpookyHash::QkHash64(data, nbytes)); w->wlog->write_uint64(SpookyHash::QkHash64(data, nbytes));
w->wlog->flush(); w->wlog->flush();
} }
w->engine->drv_sent_outgoing(chid, nbytes); w->engine->drv_sent_outgoing(chid, nbytes);
} }
static void replay_sent_outgoing(EngineWrapper *w) { static void replay_sent_outgoing(EngineWrapper *w) {
uint32_t chid = rlog_uint32(w); uint32_t chid = w->rlog->read_uint32();
uint32_t nbytes = rlog_uint32(w); uint32_t nbytes = w->rlog->read_uint32();
uint64_t hash = rlog_uint64(w); uint64_t hash = w->rlog->read_uint64();
if (!w->rlog->good()) { if (!w->rlog->good()) {
return reset_wrapper(w, "replay log corrupt in replay_sent_outgoing"); return reset_wrapper(w, "replay log corrupt in replay_sent_outgoing");
@@ -753,18 +695,18 @@ static void replay_sent_outgoing(EngineWrapper *w) {
static void play_recv_incoming(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data) { static void play_recv_incoming(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data) {
assert(w->rlog == nullptr); assert(w->rlog == nullptr);
if (w->wlog != nullptr) { if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_RECV_INCOMING, eng::memhash()); w->wlog->write_cmd_hash(PLAY_RECV_INCOMING, eng::memhash());
wlog_uint32(w, chid); w->wlog->write_uint32(chid);
wlog_short_string(w, std::string_view(data, len)); w->wlog->write_short_string(std::string_view(data, len));
w->wlog->flush(); w->wlog->flush();
} }
w->engine->drv_recv_incoming(chid, len, data); w->engine->drv_recv_incoming(chid, len, data);
} }
static void replay_recv_incoming(EngineWrapper *w) { static void replay_recv_incoming(EngineWrapper *w) {
uint32_t chid = rlog_uint32(w); uint32_t chid = w->rlog->read_uint32();
std::string_view data = rlog_short_string(w); std::string_view data = w->rlog->read_short_string(w);
if (!w->rlog->good()) { if (!w->rlog->good()) {
return reset_wrapper(w, "replay log corrupt in replay_recv_incoming"); return reset_wrapper(w, "replay log corrupt in replay_recv_incoming");
} }
@@ -779,9 +721,9 @@ static void replay_recv_incoming(EngineWrapper *w) {
static void play_notify_close(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data) { static void play_notify_close(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data) {
assert(w->rlog == nullptr); assert(w->rlog == nullptr);
if (w->wlog != nullptr) { if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_NOTIFY_CLOSE, eng::memhash()); w->wlog->write_cmd_hash(PLAY_NOTIFY_CLOSE, eng::memhash());
wlog_uint32(w, chid); w->wlog->write_uint32(chid);
wlog_string(w, std::string_view(data, len)); w->wlog->write_string(std::string_view(data, len));
w->wlog->flush(); w->wlog->flush();
} }
@@ -789,8 +731,8 @@ static void play_notify_close(EngineWrapper *w, uint32_t chid, uint32_t len, con
} }
static void replay_notify_close(EngineWrapper *w) { static void replay_notify_close(EngineWrapper *w) {
uint32_t chid = rlog_uint32(w); uint32_t chid = w->rlog->read_uint32();
std::string message = rlog_string(w); std::string message = w->rlog->read_string();
if (!w->rlog->good()) { if (!w->rlog->good()) {
return reset_wrapper(w, "replay log corrupt in replay_notify_close"); return reset_wrapper(w, "replay log corrupt in replay_notify_close");
@@ -806,8 +748,8 @@ static void replay_notify_close(EngineWrapper *w) {
static uint32_t play_notify_accept(EngineWrapper *w, uint32_t port) { static uint32_t play_notify_accept(EngineWrapper *w, uint32_t port) {
assert(w->rlog == nullptr); assert(w->rlog == nullptr);
if (w->wlog != nullptr) { if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_NOTIFY_ACCEPT, eng::memhash()); w->wlog->write_cmd_hash(PLAY_NOTIFY_ACCEPT, eng::memhash());
wlog_uint32(w, port); w->wlog->write_uint32(port);
w->wlog->flush(); w->wlog->flush();
} }
@@ -815,7 +757,7 @@ static uint32_t play_notify_accept(EngineWrapper *w, uint32_t port) {
} }
static void replay_notify_accept(EngineWrapper *w) { static void replay_notify_accept(EngineWrapper *w) {
uint32_t port = rlog_uint32(w); uint32_t port = w->rlog->read_uint32();
if (!w->rlog->good()) { if (!w->rlog->good()) {
return reset_wrapper(w, "replay log corrupt in replay_notify_accept"); return reset_wrapper(w, "replay log corrupt in replay_notify_accept");
@@ -831,8 +773,8 @@ static void replay_notify_accept(EngineWrapper *w) {
static void play_invoke_event_update(EngineWrapper *w, double clock) { static void play_invoke_event_update(EngineWrapper *w, double clock) {
assert(w->rlog == nullptr); assert(w->rlog == nullptr);
if (w->wlog != nullptr) { if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_INVOKE_EVENT_UPDATE, eng::memhash()); w->wlog->write_cmd_hash(PLAY_INVOKE_EVENT_UPDATE, eng::memhash());
wlog_double(w, clock); w->wlog->write_double(clock);
w->wlog->flush(); w->wlog->flush();
} }
@@ -840,8 +782,7 @@ static void play_invoke_event_update(EngineWrapper *w, double clock) {
} }
static void replay_invoke_event_update(EngineWrapper *w) { static void replay_invoke_event_update(EngineWrapper *w) {
double clock = rlog_double(w); double clock = w->rlog->read_double();
if (!w->rlog->good()) { if (!w->rlog->good()) {
return reset_wrapper(w, "replay log corrupt in replay_event_update"); return reset_wrapper(w, "replay log corrupt in replay_event_update");
} }
@@ -856,8 +797,8 @@ static void replay_invoke_event_update(EngineWrapper *w) {
void play_set_lua_source(EngineWrapper *w, uint32_t srcpklen, const char *srcpk) { void play_set_lua_source(EngineWrapper *w, uint32_t srcpklen, const char *srcpk) {
assert(w->rlog == nullptr); assert(w->rlog == nullptr);
if (w->wlog != nullptr) { if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_SET_LUA_SOURCE, eng::memhash()); w->wlog->write_cmd_hash(PLAY_SET_LUA_SOURCE, eng::memhash());
wlog_string(w, std::string_view(srcpk, srcpklen)); w->wlog->write_string(std::string_view(srcpk, srcpklen));
w->wlog->flush(); w->wlog->flush();
} }
@@ -865,7 +806,7 @@ void play_set_lua_source(EngineWrapper *w, uint32_t srcpklen, const char *srcpk)
} }
void replay_set_lua_source(EngineWrapper *w) { void replay_set_lua_source(EngineWrapper *w) {
std::string srcpack = rlog_string(w); std::string srcpack = w->rlog->read_string();
if (!w->rlog->good()) { if (!w->rlog->good()) {
return reset_wrapper(w, "replay log corrupt in replay_set_lua_source"); return reset_wrapper(w, "replay log corrupt in replay_set_lua_source");
@@ -900,8 +841,8 @@ static void replaycore_initialize(EngineWrapper *w, const char *logfn) {
} }
// Read one step from the logfile, and make sure it's an initialize step. // Read one step from the logfile, and make sure it's an initialize step.
uint8_t code = rlog_uint8(w); uint8_t code = w->rlog->read_uint8();
int hash = rlog_uint32(w); int hash = w->rlog->read_uint32();
if (!w->rlog->good()) { if (!w->rlog->good()) {
return reset_wrapper(w, "logfile corrupt in initial step"); return reset_wrapper(w, "logfile corrupt in initial step");
} }
@@ -924,11 +865,11 @@ static void replaycore_step(EngineWrapper *w) {
return; return;
} }
uint8_t code = rlog_uint8(w); uint8_t code = w->rlog->read_uint8();
if (w->rlog->eof()) { if (w->rlog->eof()) {
return reset_wrapper(w, "logfile terminated abruptly"); return reset_wrapper(w, "logfile terminated abruptly");
} }
int hash = rlog_uint32(w); int hash = w->rlog->read_uint32();
if (!w->rlog->good()) { if (!w->rlog->good()) {
return reset_wrapper(w, "logfile corrupt in replay step"); return reset_wrapper(w, "logfile corrupt in replay step");
} }

View File

@@ -381,7 +381,11 @@ public:
// Throw a StreamCorruption exception. // Throw a StreamCorruption exception.
void raise_truncated() { throw StreamCorruption(); } void raise_truncated() { throw StreamCorruption(); }
void raise_string_too_long() { throw StreamCorruption(); } void raise_string_too_long() { throw StreamCorruption(); }
// This is always false, because this module throws exceptions
// when reading beyond EOF.
bool read_beyond_eof() { return false; }
private: private:
// Start and end of the allocated block. // Start and end of the allocated block.
char *buf_lo_; char *buf_lo_;

View File

@@ -31,14 +31,13 @@
// void write_length(size_t data) // void write_length(size_t data)
// void write_string(std::string_view data) // void write_string(std::string_view data)
// //
// In order to derive from BaseWriter, you must use the CRTP pattern: // You should derive from BaseWriter using the CRTP pattern:
// //
// class DerivedWriter : public BaseWriter<DerivedWriter> // class DerivedWriter : public BaseWriter<DerivedWriter>
// //
// And you must provide two methods in the derived class: // You must provide two methods in the derived class:
// //
// write_bytes(const char *n, size_t size) // write_bytes(const char *n, size_t size)
//
// raise_truncated() // raise_truncated()
// //
/////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////
@@ -111,15 +110,16 @@ public:
// String read_string_limit(uint64_t size); // String read_string_limit(uint64_t size);
// String read_string(); // String read_string();
// //
// In order to derive from BaseReader, you must use the CRTP pattern: // You should derive from BaseReader using the CRTP pattern:
// //
// class DerivedReader : public BaseReader<DerivedReader> // class DerivedReader : public BaseReader<DerivedReader>
// //
// The derived class must provide: // The derived class must provide:
// //
// using read_string_type = std::string; // or similar // using read_string_type = std::string; // or compatible
// void read_bytes_into(char *n, size_t size) // void read_bytes_into(char *n, size_t size)
// void raise_string_too_long(); // void raise_string_too_long();
// bool read_beyond_eof();
// //
/////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////
@@ -129,7 +129,9 @@ protected:
template<class T> template<class T>
T read_value_core() { T read_value_core() {
T result; T result;
static_cast<Derived*>(this)->read_bytes_into((char *)(&result), sizeof(result)); Derived *dthis = static_cast<Derived*>(this);
dthis->read_bytes_into((char *)(&result), sizeof(result));
if (dthis->read_beyond_eof()) result = 0;
return result; return result;
} }
@@ -159,9 +161,11 @@ public:
auto read_string_limit(uint64_t limit) { auto read_string_limit(uint64_t limit) {
size_t len = read_length(); size_t len = read_length();
if (len > limit) static_cast<Derived*>(this)->raise_string_too_long(); Derived *dthis = static_cast<Derived*>(this);
if (len > limit) dthis->raise_string_too_long();
typename Derived::read_string_type result(len, ' '); typename Derived::read_string_type result(len, ' ');
static_cast<Derived*>(this)->read_bytes_into(&(result[0]), len); dthis->read_bytes_into(&(result[0]), len);
if (dthis->read_beyond_eof()) result.clear();
return result; return result;
} }