pos/database/log.cpp

144 lines
3.5 KiB
C++

#include "log.h"
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <sstream>
Log::Log(const char * fn)
: log_name(fn), serial(0)
{
FILE * fh = fopen(fn, "r");
if(!fh) {
fprintf(stderr, "Log: Could not open log file '%s' for reading! Creating an empty log.\n", fn);
return;
}
LogEntry l;
while(1 == fread(&l, sizeof(LogEntry), 1, fh))
entries.push_back(l);
serial = l.serial;
fclose(fh);
}
uint64_t Log::writeEntry(LogEntry ent)
{
FILE * fh = fopen(log_name.c_str(), "a");
if(!fh) {
fprintf(stderr, "Log: FATAL: Could not open log file '%s' for append. Aborting.\n", log_name.c_str());
abort();
}
flockfile(fh);
fseek(fh, 0, SEEK_END);
ent.serial = ++serial;
if(1 != fwrite(&ent, sizeof(LogEntry), 1, fh)) {
fprintf(stderr, "Log: FATAL: Could not write entry to log file '%s'. Aborting.\n", log_name.c_str());
abort();
}
fflush(fh);
funlockfile(fh);
fclose(fh);
entries.push_back(ent);
return ent.serial;
}
std::list<LogEntry>::const_iterator Log::begin()
{
return entries.begin();
}
std::list<LogEntry>::const_iterator Log::end()
{
return entries.end();
}
uint64_t Log::nextSerial()
{
return serial + 1;
}
std::string logTypeToString (E_OBJ_TYPE type) {
switch(type) {
case ET_TRANS: return "TRANS";
case ET_HASH: return "HASH";
case ET_SALE: return "SALE";
case ET_PRICE: return "PRICE";
case ET_ADDUPC: return "ADDUPC";
case ET_REVERT: return "REVERT";
default: fprintf(stderr, "logTypeToString: unhandled case in switch.\n"); abort();
}
}
template<typename T>
std::string ThingToString (T num) {
std::stringstream ss;
ss << num;
return ss.str();
}
std::vector<std::string> Log::toString()
{
assert(sizeof(time_t) == sizeof(uint64_t));
std::vector<std::string> ans;
ans.reserve(entries.size());
std::list<LogEntry>::iterator it;
for(it = entries.begin(); it != entries.end(); it++) {
//char* time = new char[64];
//struct tm* tms = localtime((time_t*)&it->ts);
//strftime(time, 64, "%c", tms);
std::string out = ThingToString<uint64_t>(it->ts) + "\t"
//+ ThingToString<uint64_t> (it->serial) + "\t"
+ logTypeToString(it->type) + "\t";
//delete[] time;
switch(it->type) {
case ET_TRANS:
out += ns.get_name(it->Transaction.uid) + "\t"
+ ThingToString<int32_t>(it->Transaction.delta);
break;
case ET_HASH: {
SHA1Hash h;
h.set((unsigned char*)it->HashChange.hash);
out += h.toHex() + "\t"
+ ns.get_name(it->HashChange.uid) + "\t"
+ ThingToString<bool>(it->HashChange.add);
break;
}
case ET_SALE:
out += ThingToString<uint64_t>(it->StockChange.upc) + "\t"
+ ThingToString<int32_t>(it->StockChange.delta);
break;
case ET_PRICE:
out += ThingToString<uint64_t>(it->PriceChange.upc) + "\t"
+ ThingToString<int32_t>(it->PriceChange.price);
break;
case ET_ADDUPC:
out += ThingToString<uint64_t>(it->AddUPC.upc) + "\t"
+ it->AddUPC.name;
break;
case ET_REVERT:
out += ThingToString<uint64_t>(it->Revert.revert_serial);
break;
default: fprintf(stderr, "Log: unhandled toString case.\n"); abort();
}
ans.push_back(out);
}
return ans;
}
LogEntry Log::newLogEntry(E_OBJ_TYPE type) {
LogEntry l;
memset(&l, 0, sizeof(LogEntry));
l.ts = (uint64_t)time(NULL);
l.type = type;
l.serial = nextSerial();
return l;
}