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 ReplayLogfile : public std::ifstream { using std::ifstream::ifstream; };
class PlayLogfile : public BaseWriter<PlayLogfile>, public std::ofstream {
using std::ofstream::ofstream;
public:
void write_bytes(const char *n, size_t size) { write(n, size); }
void raise_truncated() {
fprintf(stderr, "number exceeds allowable size\n");
std::abort();
}
void write_short_string(std::string_view v) {
assert(v.size() < DRV_SHORTSTRING_SIZE);
write_string(v);
}
void write_cmd_hash(DrvAction act, uint32_t hash) {
write_uint8(act);
write_uint32(hash);
}
};
static uint8_t rlog_uint8(EngineWrapper *w) {
uint8_t result;
w->rlog->read((char *)&result, 1);
if (!w->rlog->good()) return 0;
return result;
class ReplayLogfile : public BaseReader<ReplayLogfile>, public std::ifstream {
using std::ifstream::ifstream;
public:
using read_string_type = std::string;
void read_bytes_into(char *n, size_t size) { read(n, size); }
bool read_beyond_eof() { return !good(); }
void raise_string_too_long() {
fprintf(stderr, "string in logfile is too long");
std::abort();
}
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);
if (len > 0) w->rlog->read(w->databuffer, len);
if (!w->rlog->good()) return std::string_view();
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, ' ');
if (len > 0) w->rlog->read(&result[0], len);
if (!w->rlog->good()) return "";
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) {
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_cmd_hash(EngineWrapper *w, DrvAction act, uint32_t hash) {
wlog_uint8(w, act);
wlog_uint32(w, hash);
std::string_view read_short_string(EngineWrapper *w) {
size_t size = read_length();
assert(size <= DRV_SHORTSTRING_SIZE);
if (size > 0) read(w->databuffer, size);
if (!good()) return std::string_view();
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) {
if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_RELEASE, eng::memhash());
w->wlog->write_cmd_hash(PLAY_RELEASE, eng::memhash());
}
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 (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_INITIALIZE, eng::memhash());
wlog_uint32(w, argc);
w->wlog->write_cmd_hash(PLAY_INITIALIZE, eng::memhash());
w->wlog->write_uint32(argc);
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();
}
@@ -662,11 +604,11 @@ static void play_initialize(EngineWrapper *w, uint32_t argc, char **argv, uint32
static void replay_initialize(EngineWrapper *w) {
assert(w->rlog != nullptr);
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++) {
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()) {
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) {
assert(w->rlog == 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->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;
w->engine->drv_get_outgoing(chid, &ndata, &data);
assert(nbytes <= ndata);
wlog_cmd_hash(w, PLAY_SENT_OUTGOING, eng::memhash());
wlog_uint32(w, chid);
wlog_uint32(w, nbytes);
wlog_uint64(w, SpookyHash::QkHash64(data, nbytes));
w->wlog->write_cmd_hash(PLAY_SENT_OUTGOING, eng::memhash());
w->wlog->write_uint32(chid);
w->wlog->write_uint32(nbytes);
w->wlog->write_uint64(SpookyHash::QkHash64(data, nbytes));
w->wlog->flush();
}
w->engine->drv_sent_outgoing(chid, nbytes);
}
static void replay_sent_outgoing(EngineWrapper *w) {
uint32_t chid = rlog_uint32(w);
uint32_t nbytes = rlog_uint32(w);
uint64_t hash = rlog_uint64(w);
uint32_t chid = w->rlog->read_uint32();
uint32_t nbytes = w->rlog->read_uint32();
uint64_t hash = w->rlog->read_uint64();
if (!w->rlog->good()) {
return reset_wrapper(w, "replay log corrupt in replay_sent_outgoing");
@@ -753,17 +695,17 @@ static void replay_sent_outgoing(EngineWrapper *w) {
static void play_recv_incoming(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data) {
assert(w->rlog == nullptr);
if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_RECV_INCOMING, eng::memhash());
wlog_uint32(w, chid);
wlog_short_string(w, std::string_view(data, len));
w->wlog->write_cmd_hash(PLAY_RECV_INCOMING, eng::memhash());
w->wlog->write_uint32(chid);
w->wlog->write_short_string(std::string_view(data, len));
w->wlog->flush();
}
w->engine->drv_recv_incoming(chid, len, data);
}
static void replay_recv_incoming(EngineWrapper *w) {
uint32_t chid = rlog_uint32(w);
std::string_view data = rlog_short_string(w);
uint32_t chid = w->rlog->read_uint32();
std::string_view data = w->rlog->read_short_string(w);
if (!w->rlog->good()) {
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) {
assert(w->rlog == nullptr);
if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_NOTIFY_CLOSE, eng::memhash());
wlog_uint32(w, chid);
wlog_string(w, std::string_view(data, len));
w->wlog->write_cmd_hash(PLAY_NOTIFY_CLOSE, eng::memhash());
w->wlog->write_uint32(chid);
w->wlog->write_string(std::string_view(data, len));
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) {
uint32_t chid = rlog_uint32(w);
std::string message = rlog_string(w);
uint32_t chid = w->rlog->read_uint32();
std::string message = w->rlog->read_string();
if (!w->rlog->good()) {
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) {
assert(w->rlog == nullptr);
if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_NOTIFY_ACCEPT, eng::memhash());
wlog_uint32(w, port);
w->wlog->write_cmd_hash(PLAY_NOTIFY_ACCEPT, eng::memhash());
w->wlog->write_uint32(port);
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) {
uint32_t port = rlog_uint32(w);
uint32_t port = w->rlog->read_uint32();
if (!w->rlog->good()) {
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) {
assert(w->rlog == nullptr);
if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_INVOKE_EVENT_UPDATE, eng::memhash());
wlog_double(w, clock);
w->wlog->write_cmd_hash(PLAY_INVOKE_EVENT_UPDATE, eng::memhash());
w->wlog->write_double(clock);
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) {
double clock = rlog_double(w);
double clock = w->rlog->read_double();
if (!w->rlog->good()) {
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) {
assert(w->rlog == nullptr);
if (w->wlog != nullptr) {
wlog_cmd_hash(w, PLAY_SET_LUA_SOURCE, eng::memhash());
wlog_string(w, std::string_view(srcpk, srcpklen));
w->wlog->write_cmd_hash(PLAY_SET_LUA_SOURCE, eng::memhash());
w->wlog->write_string(std::string_view(srcpk, srcpklen));
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) {
std::string srcpack = rlog_string(w);
std::string srcpack = w->rlog->read_string();
if (!w->rlog->good()) {
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.
uint8_t code = rlog_uint8(w);
int hash = rlog_uint32(w);
uint8_t code = w->rlog->read_uint8();
int hash = w->rlog->read_uint32();
if (!w->rlog->good()) {
return reset_wrapper(w, "logfile corrupt in initial step");
}
@@ -924,11 +865,11 @@ static void replaycore_step(EngineWrapper *w) {
return;
}
uint8_t code = rlog_uint8(w);
uint8_t code = w->rlog->read_uint8();
if (w->rlog->eof()) {
return reset_wrapper(w, "logfile terminated abruptly");
}
int hash = rlog_uint32(w);
int hash = w->rlog->read_uint32();
if (!w->rlog->good()) {
return reset_wrapper(w, "logfile corrupt in replay step");
}

View File

@@ -382,6 +382,10 @@ public:
void raise_truncated() { 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:
// Start and end of the allocated block.
char *buf_lo_;

View File

@@ -31,14 +31,13 @@
// void write_length(size_t 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>
//
// 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)
//
// raise_truncated()
//
///////////////////////////////////////////////////////////////
@@ -111,15 +110,16 @@ public:
// String read_string_limit(uint64_t size);
// 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>
//
// 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 raise_string_too_long();
// bool read_beyond_eof();
//
///////////////////////////////////////////////////////////////
@@ -129,7 +129,9 @@ protected:
template<class T>
T read_value_core() {
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;
}
@@ -159,9 +161,11 @@ public:
auto read_string_limit(uint64_t limit) {
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, ' ');
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;
}