Initial database, tested lightly.
This commit is contained in:
parent
55a63f8cd9
commit
6868556ead
207
database/db.cpp
207
database/db.cpp
|
@ -1,9 +1,11 @@
|
|||
#include "db.h"
|
||||
#include "log.h"
|
||||
#include "sha1.h"
|
||||
#include "nameserver.h"
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
PosDb::PosDb(const char * fn)
|
||||
|
@ -15,6 +17,7 @@ PosDb::PosDb(const char * fn)
|
|||
}
|
||||
|
||||
void PosDb::acceptLogEntry(const LogEntry & l) {
|
||||
serial_to_object[l.serial] = l;
|
||||
switch(l.type) {
|
||||
case ET_HASH: {
|
||||
SHA1Hash h;
|
||||
|
@ -22,46 +25,58 @@ void PosDb::acceptLogEntry(const LogEntry & l) {
|
|||
|
||||
if(l.HashChange.add) {
|
||||
// verify hash not associated with anything
|
||||
if(hash_to_account.find(h) != hash_to_account.end()) {
|
||||
fprintf(stderr, "PosDb: Log associates a hash"
|
||||
" with more than one account! Aborting.");
|
||||
abort();
|
||||
} else {
|
||||
hash_to_account[h] = l.HashChange.uid;
|
||||
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
|
||||
std::map<SHA1Hash, uint32_t, SHA1Less>::iterator it
|
||||
= hash_to_account.find(h);
|
||||
if(it == hash_to_account.end()) {
|
||||
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 {
|
||||
hash_to_account.erase(it);
|
||||
account_to_hash.erase(p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ET_TRANS: {
|
||||
SHA1Hash h;
|
||||
h.set((unsigned char *)l.Transaction.hash);
|
||||
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;
|
||||
}
|
||||
|
||||
std::map<SHA1Hash, uint32_t, SHA1Less>::iterator it
|
||||
= hash_to_account.find(h);
|
||||
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;
|
||||
}
|
||||
|
||||
if(it == hash_to_account.end()) {
|
||||
fprintf(stderr, "PosDb: Log transacts on"
|
||||
" unassociated hash! Aborting.");
|
||||
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 {
|
||||
std::map<uint32_t, int32_t>::iterator q =
|
||||
account_to_balance.find(it->second);
|
||||
if(q == account_to_balance.end())
|
||||
account_to_balance[it->second] = l.Transaction.delta;
|
||||
else
|
||||
q->second += l.Transaction.delta;
|
||||
account_to_balance[q->second.Transaction.uid] -= q->second.Transaction.delta;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -70,40 +85,42 @@ void PosDb::acceptLogEntry(const LogEntry & l) {
|
|||
}
|
||||
|
||||
uint32_t PosDb::getAccountFromHash(const SHA1Hash & hash) {
|
||||
std::map<SHA1Hash, uint32_t, SHA1Less>::iterator it
|
||||
= hash_to_account.find(hash);
|
||||
if(it == hash_to_account.end())
|
||||
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;
|
||||
return it->second;
|
||||
else
|
||||
return p->first;
|
||||
}
|
||||
|
||||
std::list<std::string> PosDb::getHashesFromAccount(uint32_t account) {
|
||||
std::list<std::string> result;
|
||||
char bfr[20];
|
||||
|
||||
for(std::map<SHA1Hash, uint32_t, SHA1Less>::iterator p
|
||||
= hash_to_account.begin();
|
||||
p != hash_to_account.end(); ++p)
|
||||
ath_it_r range = account_to_hash.equal_range(account);
|
||||
for(ath_it p = range.first; p != range.second; ++p)
|
||||
{
|
||||
if(p->second == account)
|
||||
{
|
||||
p->first.get((unsigned char *)bfr);
|
||||
result.push_back(bfr);
|
||||
}
|
||||
p->second.get((unsigned char *)bfr);
|
||||
result.push_back(bfr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t PosDb::getAccountBalance(const SHA1Hash & hash) {
|
||||
std::map<SHA1Hash, uint32_t, SHA1Less>::iterator it
|
||||
= hash_to_account.find(hash);
|
||||
std::list<std::string> PosDb::getHashesFromAccount(std::string account) {
|
||||
return getHashesFromAccount(ns.get_id(account));
|
||||
}
|
||||
|
||||
if(it == hash_to_account.end())
|
||||
int32_t PosDb::getAccountBalance(const SHA1Hash & hash) {
|
||||
uint32_t acct = getAccountFromHash(hash);
|
||||
|
||||
if(!acct)
|
||||
return 0;
|
||||
else {
|
||||
std::map<uint32_t, int32_t>::iterator p
|
||||
= account_to_balance.find(it->second);
|
||||
atb_it p = account_to_balance.find(acct);
|
||||
if(p == account_to_balance.end())
|
||||
return 0;
|
||||
else
|
||||
|
@ -112,47 +129,141 @@ int32_t PosDb::getAccountBalance(const SHA1Hash & hash) {
|
|||
}
|
||||
|
||||
int32_t PosDb::getAccountBalance(uint32_t account) {
|
||||
std::map<uint32_t, int32_t>::iterator p
|
||||
= account_to_balance.find(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(hash_to_account.find(hash) != hash_to_account.end()) {
|
||||
if(getAccountFromHash(hash)) {
|
||||
return 0;
|
||||
} else {
|
||||
LogEntry l;
|
||||
memset(&l, 0, sizeof(LogEntry));
|
||||
l.ts = (uint64_t)time(NULL);
|
||||
l.type = ET_HASH;
|
||||
l.HashChange.uid = account;
|
||||
l.HashChange.add = true;
|
||||
hash.get((unsigned char *)l.HashChange.hash);
|
||||
|
||||
l.serial = log.nextSerial();
|
||||
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
|
||||
std::map<SHA1Hash, uint32_t, SHA1Less>::iterator p
|
||||
= hash_to_account.find(hash);
|
||||
if(p == hash_to_account.end()) {
|
||||
uint32_t acct = getAccountFromHash(hash);
|
||||
|
||||
if(!acct) {
|
||||
return 0;
|
||||
} else {
|
||||
LogEntry l;
|
||||
memset(&l, 0, sizeof(LogEntry));
|
||||
l.ts = (uint64_t)time(NULL);
|
||||
l.type = ET_HASH;
|
||||
l.HashChange.uid = p->second;
|
||||
l.HashChange.uid = acct;
|
||||
l.HashChange.add = false;
|
||||
hash.get((unsigned char *)l.HashChange.hash);
|
||||
|
||||
l.serial = log.nextSerial();
|
||||
acceptLogEntry(l);
|
||||
return log.writeEntry(l);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
memset(&l, 0, sizeof(LogEntry));
|
||||
l.ts = (uint64_t)time(NULL);
|
||||
l.type = ET_TRANS;
|
||||
l.Transaction.delta = delta;
|
||||
l.Transaction.uid = acct;
|
||||
|
||||
l.serial = log.nextSerial();
|
||||
acceptLogEntry(l);
|
||||
return log.writeEntry(l);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t PosDb::doTransaction(const uint32_t account, int32_t delta) {
|
||||
LogEntry l;
|
||||
memset(&l, 0, sizeof(LogEntry));
|
||||
l.ts = (uint64_t)time(NULL);
|
||||
l.type = ET_TRANS;
|
||||
l.Transaction.delta = delta;
|
||||
l.Transaction.uid = account;
|
||||
|
||||
l.serial = log.nextSerial();
|
||||
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;
|
||||
memset(&l, 0, sizeof(LogEntry));
|
||||
l.ts = (uint64_t)time(NULL);
|
||||
l.type = ET_REVERT;
|
||||
l.Revert.revert_serial = serial;
|
||||
|
||||
l.serial = log.nextSerial();
|
||||
acceptLogEntry(l);
|
||||
return log.writeEntry(l);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t PosDb::getStock(UPC 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(UPC upc, int32_t delta) {
|
||||
LogEntry l;
|
||||
memset(&l, 0, sizeof(LogEntry));
|
||||
l.ts = (uint64_t)time(NULL);
|
||||
l.type = ET_SALE;
|
||||
l.StockChange.delta = delta;
|
||||
l.StockChange.upc = upc;
|
||||
|
||||
l.serial = log.nextSerial();
|
||||
acceptLogEntry(l);
|
||||
return log.writeEntry(l);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _POS_DB_H_
|
||||
#include "sha1.h"
|
||||
#include "log.h"
|
||||
#include "nameserver.h"
|
||||
#include <stdint.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
@ -12,14 +13,19 @@ public:
|
|||
PosDb(const char * fn);
|
||||
uint32_t getAccountFromHash(const SHA1Hash & hash);
|
||||
std::list<std::string> getHashesFromAccount(uint32_t account);
|
||||
std::list<std::string> getHashesFromAccount(std::string account);
|
||||
|
||||
int32_t getAccountBalance(const SHA1Hash & hash);
|
||||
int32_t getAccountBalance(uint32_t account);
|
||||
int32_t getAccountBalance(std::string account);
|
||||
|
||||
uint64_t associateHash(const SHA1Hash & hash, uint32_t account);
|
||||
uint64_t associateHash(const SHA1Hash & hash, std::string account);
|
||||
uint64_t deassociateHash(const SHA1Hash & hash);
|
||||
|
||||
uint64_t doTransaction(const SHA1Hash & hash, int32_t delta);
|
||||
uint64_t doTransaction(const uint32_t account, int32_t delta);
|
||||
uint64_t doTransaction(std::string account, int32_t delta);
|
||||
uint64_t revertTransaction(uint64_t serial);
|
||||
|
||||
int32_t getStock(UPC upc);
|
||||
|
@ -28,15 +34,22 @@ public:
|
|||
private:
|
||||
void acceptLogEntry(const LogEntry & l);
|
||||
|
||||
std::map<SHA1Hash, uint32_t, SHA1Less> hash_to_account;
|
||||
std::multimap<uint32_t, SHA1Hash> account_to_hash;
|
||||
std::map<uint32_t, int32_t> account_to_balance;
|
||||
|
||||
std::map<UPC, int32_t, UPCLess> upc_to_stock;
|
||||
|
||||
std::map<uint64_t, std::list<LogEntry>::const_iterator> serial_to_object;
|
||||
std::map<uint64_t, LogEntry> serial_to_object;
|
||||
|
||||
Log log;
|
||||
NameServer ns;
|
||||
};
|
||||
|
||||
typedef std::multimap<uint32_t, SHA1Hash>::iterator ath_it;
|
||||
typedef std::map<uint32_t, int32_t>::iterator atb_it;
|
||||
typedef std::map<UPC, int32_t, UPCLess>::iterator uts_it;
|
||||
typedef std::map<uint64_t, LogEntry>::iterator sto_it;
|
||||
typedef std::pair<ath_it, ath_it> ath_it_r;
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -57,3 +57,8 @@ std::list<LogEntry>::const_iterator Log::end()
|
|||
return entries.end();
|
||||
}
|
||||
|
||||
uint64_t Log::nextSerial()
|
||||
{
|
||||
return serial + 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ struct __attribute__ ((aligned (64), packed)) LogEntry
|
|||
E_OBJ_TYPE type;
|
||||
union {
|
||||
struct __attribute__ ((packed)) {
|
||||
char hash[20];
|
||||
uint32_t uid;
|
||||
int32_t delta;
|
||||
} Transaction;
|
||||
|
||||
|
@ -53,6 +53,7 @@ class Log {
|
|||
public:
|
||||
Log(const char * fn);
|
||||
uint64_t writeEntry(LogEntry ent);
|
||||
uint64_t nextSerial();
|
||||
std::list<LogEntry>::const_iterator begin();
|
||||
std::list<LogEntry>::const_iterator end();
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#include "nameserver.h"
|
||||
#include <iostream>
|
||||
#include <pwd.h>
|
||||
|
||||
std::string NameServer::get_name (uint32_t id) {
|
||||
std::map<std::string, uint32_t>::iterator it;
|
||||
for (it = cache.begin(); it != cache.end(); it++) {
|
||||
if (it->second == id) return it->first;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
uint32_t NameServer::get_id (std::string name) {
|
||||
std::map<std::string, uint32_t>::iterator it = cache.find(name);
|
||||
|
||||
if (it != cache.end())
|
||||
return it->second;
|
||||
|
||||
std::cerr << "Doing LDAP lookup for \"" << name << "\".\n";
|
||||
struct passwd* pwd = getpwnam(name.c_str());
|
||||
if (!pwd) {
|
||||
std::cerr << "Username " << name << " lookup fail!\n";
|
||||
// TODO: oh fuck???
|
||||
return 0;
|
||||
}
|
||||
|
||||
cache[name] = pwd->pw_uid;
|
||||
return cache[name];
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef _POS_NAMESERVER_H_
|
||||
#define _POS_NAMESERVER_H_
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
|
||||
class NameServer {
|
||||
public:
|
||||
std::string get_name (uint32_t id);
|
||||
uint32_t get_id (std::string name);
|
||||
|
||||
private:
|
||||
std::map<std::string, uint32_t> cache;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
struct __attribute__ ((packed)) SHA1Hash {
|
||||
SHA1Hash();
|
||||
SHA1Hash(const char * str);
|
||||
SHA1Hash(const std::string str);
|
||||
explicit SHA1Hash(const char * str);
|
||||
explicit SHA1Hash(const std::string str);
|
||||
SHA1Hash(const SHA1Hash & other);
|
||||
bool operator==(const SHA1Hash & other) const;
|
||||
void set(const unsigned char * from);
|
||||
|
|
|
@ -1,13 +1,34 @@
|
|||
#include "db.h"
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
PosDb db("db");
|
||||
printf("%lu\n", db.associateHash(SHA1Hash("dongs"), 1));
|
||||
printf("%lu\n", db.associateHash(SHA1Hash("cocks"), 1));
|
||||
printf("%lu\n", db.deassociateHash(SHA1Hash("dongs")));
|
||||
|
||||
printf("%d\n", db.getAccountBalance(SHA1Hash("cocks")));
|
||||
uint64_t d = 0;
|
||||
cout << db.associateHash(SHA1Hash("asdfasdf"), "m4burns") << "\n";
|
||||
cout << db.getAccountFromHash(SHA1Hash("asdfasdf")) << "\n";
|
||||
cout << db.doTransaction("m4burns", 12300) << "\n";
|
||||
cout << db.doTransaction("j3parker", 23400) << "\n";
|
||||
cout << "F" << db.associateHash(SHA1Hash("asdfasdf"), "j3parker") << "\n";
|
||||
cout << db.associateHash(SHA1Hash("foobar"), "j3parker") << "\n";
|
||||
cout << db.doTransaction("m4burns", -100) << "\n";
|
||||
cout << (d = db.doTransaction("m4burns", -200)) << "\n";
|
||||
cout << db.doTransaction("m4burns", 50) << "\n";
|
||||
cout << db.doTransaction("j3parker", -23450) << "\n";
|
||||
cout << "F" << db.deassociateHash(SHA1Hash("notme")) << "\n";
|
||||
cout << db.deassociateHash(SHA1Hash("asdfasdf")) << "\n";
|
||||
cout << db.revertTransaction(d) << "\n";
|
||||
cout << "F" << db.revertTransaction(d) << "\n";
|
||||
cout << "12250? " << db.getAccountBalance("m4burns") << "\n";
|
||||
cout << "-50? " << db.getAccountBalance(SHA1Hash("foobar")) << "\n";
|
||||
UPC foo;
|
||||
foo.l = 12345;
|
||||
foo.h = 67890;
|
||||
cout << db.doStockChange(foo, 100) << "\n";
|
||||
cout << db.getStock(foo) << "\n";
|
||||
foo.l = 123;
|
||||
cout << db.getStock(foo) << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue