Initial database, tested lightly.

This commit is contained in:
Marc Burns 2011-11-08 20:38:06 -05:00
parent 55a63f8cd9
commit 6868556ead
8 changed files with 257 additions and 59 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -57,3 +57,8 @@ std::list<LogEntry>::const_iterator Log::end()
return entries.end();
}
uint64_t Log::nextSerial()
{
return serial + 1;
}

View File

@ -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();

30
database/nameserver.cpp Normal file
View File

@ -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];
}

17
database/nameserver.h Normal file
View File

@ -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

View File

@ -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);

View File

@ -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;
}