pos/database/posdb.cpp

292 lines
6.7 KiB
C++

#include "common.h"
#include "posdb.h"
#include "log.h"
#include "sha1.h"
#include <cassert>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <ctime>
PosDb::PosDb(const char * fn)
: log(fn)
{
// read in the log
for(std::list<LogEntry>::const_iterator p = log.begin(); p != log.end(); ++p)
acceptLogEntry(*p);
}
void PosDb::acceptLogEntry(const LogEntry & l) {
serial_to_object[l.serial] = l;
switch(l.type) {
case ET_HASH: {
SHA1Hash h;
h.set((unsigned char *)l.HashChange.hash);
if(l.HashChange.add) {
// verify hash not associated with anything
for(ath_it p = account_to_hash.begin(); p != account_to_hash.end(); ++p) {
if(p->second == h) {
fprintf(stderr, "PosDb: Log associates a hash"
" with more than one account! Aborting.");
abort();
}
}
account_to_hash.insert(std::pair<uint32_t, SHA1Hash>(l.HashChange.uid, h));
} else {
// verify hash associated with something
ath_it p;
for(p = account_to_hash.begin(); p != account_to_hash.end(); ++p) {
if(p->second == h)
break;
}
if(p == account_to_hash.end()) {
fprintf(stderr, "PosDb: Log deassociates an"
"unassociated hash! Aborting.");
abort();
} else {
account_to_hash.erase(p);
}
}
break;
}
case ET_TRANS: {
atb_it q = account_to_balance.find(l.Transaction.uid);
if(q == account_to_balance.end())
account_to_balance[l.Transaction.uid] = l.Transaction.delta;
else
q->second += l.Transaction.delta;
break;
}
case ET_SALE: {
uts_it q = upc_to_stock.find(l.StockChange.upc);
if(q == upc_to_stock.end())
upc_to_stock[l.StockChange.upc] = l.StockChange.delta;
else
q->second += l.StockChange.delta;
break;
}
case ET_PRICE: {
upc_to_price[l.PriceChange.upc] = l.PriceChange.price;
break;
}
case ET_ADDUPC: {
upc_to_name[l.AddUPC.upc] = l.AddUPC.name;
break;
}
case ET_REVERT: {
sto_it q = serial_to_object.find(l.Revert.revert_serial);
if((q == serial_to_object.end()) || (q->second.type != ET_TRANS)) {
fprintf(stderr, "PosDb: Log reverts an invalid object! Aborting.");
abort();
} else {
account_to_balance[q->second.Transaction.uid] -= q->second.Transaction.delta;
}
break;
}
}
}
uint32_t PosDb::getAccountFromHash(const SHA1Hash & hash) {
ath_it p;
for(p = account_to_hash.begin(); p != account_to_hash.end(); ++p) {
if(p->second == hash)
break;
}
if(p == account_to_hash.end())
return 0;
else
return p->first;
}
std::list<std::string> PosDb::getHashesFromAccount(uint32_t account) {
std::list<std::string> result;
ath_it_r range = account_to_hash.equal_range(account);
for(ath_it p = range.first; p != range.second; ++p)
result.push_back(p->second.toHex());
return result;
}
std::list<std::string> PosDb::getHashesFromAccount(std::string account) {
return getHashesFromAccount(ns.get_id(account));
}
int32_t PosDb::getAccountBalance(const SHA1Hash & hash) {
uint32_t acct = getAccountFromHash(hash);
if(!acct)
return 0;
else {
atb_it p = account_to_balance.find(acct);
if(p == account_to_balance.end())
return 0;
else
return p->second;
}
}
int32_t PosDb::getAccountBalance(uint32_t account) {
atb_it p = account_to_balance.find(account);
if(p == account_to_balance.end())
return 0;
else
return p->second;
}
int32_t PosDb::getAccountBalance(std::string account) {
return getAccountBalance(ns.get_id(account));
}
uint64_t PosDb::associateHash(const SHA1Hash & hash, uint32_t account) {
// verify hash not associated with anything
if(getAccountFromHash(hash)) {
return 0;
} else {
LogEntry l = log.newLogEntry(ET_HASH);
l.HashChange.uid = account;
l.HashChange.add = true;
hash.get((unsigned char *)l.HashChange.hash);
acceptLogEntry(l);
return log.writeEntry(l);
}
}
uint64_t PosDb::associateHash(const SHA1Hash & hash, std::string account) {
return associateHash(hash, ns.get_id(account));
}
uint64_t PosDb::deassociateHash(const SHA1Hash & hash) {
// verify hash associated with something
uint32_t acct = getAccountFromHash(hash);
if(!acct) {
return 0;
} else {
LogEntry l = log.newLogEntry(ET_HASH);
l.HashChange.uid = acct;
l.HashChange.add = false;
hash.get((unsigned char *)l.HashChange.hash);
acceptLogEntry(l);
return log.writeEntry(l);
}
}
int32_t PosDb::getUPCPrice(uint64_t upc) {
uts_it it = upc_to_price.find(upc);
if (it == upc_to_price.end()) {
return 0;
}
return it->second;
}
uint64_t PosDb::setUPCPrice(uint64_t upc, int32_t price) {
LogEntry l = log.newLogEntry(ET_PRICE);
l.PriceChange.upc = upc;
l.PriceChange.price = price;
acceptLogEntry(l);
return log.writeEntry(l);
}
// NOTE: this in theory could be deprecated. The client should
// probably get the uid from the hash before doing a transaction.
uint64_t PosDb::doTransaction(const SHA1Hash & hash, int32_t delta) {
// verify hash associated with something
uint32_t acct = getAccountFromHash(hash);
if(!acct) {
return 0;
} else {
LogEntry l = log.newLogEntry(ET_TRANS);
l.Transaction.delta = delta;
l.Transaction.uid = acct;
acceptLogEntry(l);
return log.writeEntry(l);
}
}
uint64_t PosDb::doTransaction(const uint32_t account, int32_t delta) {
LogEntry l = log.newLogEntry(ET_TRANS);
l.Transaction.delta = delta;
l.Transaction.uid = account;
acceptLogEntry(l);
return log.writeEntry(l);
}
uint64_t PosDb::doTransaction(std::string account, int32_t delta) {
return doTransaction(ns.get_id(account), delta);
}
uint64_t PosDb::revertTransaction(uint64_t serial) {
if(serial_to_object.find(serial) == serial_to_object.end()) {
return 0;
} else {
// do not double-revert transactions
sto_it p;
for(p = serial_to_object.begin(); p != serial_to_object.end(); ++p) {
if((p->second.type == ET_REVERT) && (p->second.Revert.revert_serial == serial))
break;
}
if(p != serial_to_object.end())
return 0;
LogEntry l = log.newLogEntry(ET_REVERT);
l.Revert.revert_serial = serial;
acceptLogEntry(l);
return log.writeEntry(l);
}
}
int32_t PosDb::getStock(uint64_t upc) {
uts_it p = upc_to_stock.find(upc);
if(p == upc_to_stock.end())
return 0;
else
return p->second;
}
uint64_t PosDb::doStockChange(uint64_t upc, int32_t delta) {
LogEntry l = log.newLogEntry(ET_SALE);
l.StockChange.delta = delta;
l.StockChange.upc = upc;
acceptLogEntry(l);
return log.writeEntry(l);
}
std::string PosDb::getUPCName(uint64_t upc) {
std::map<uint64_t, std::string>::iterator it = upc_to_name.find(upc);
if(it == upc_to_name.end()) return "UNKNOWN UPC";
return upc_to_name[upc];
}
uint64_t PosDb::setUPCName (uint64_t upc, std::string name) {
LogEntry l = log.newLogEntry(ET_ADDUPC);
l.AddUPC.upc = upc;
strncpy(l.AddUPC.name, name.c_str(), 32);
l.AddUPC.name[32] = 0;
acceptLogEntry(l);
return log.writeEntry(l);
}
std::vector<std::string> PosDb::toString() {
return log.toString();
}