database: Implement updates to match my current design

- Force the primary key to be a string
- Throw error codes rather than 0

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This commit is contained in:
Anna Schumaker 2013-12-30 18:18:23 -05:00 committed by Anna Schumaker
parent ab8c15ecb7
commit acd8bd7b23
7 changed files with 162 additions and 135 deletions

View File

@ -240,9 +240,10 @@ Database: (lib/database.cpp)
- DatabaseEntry:
class DatabaseEntry { /* let database modify valid flag */
public:
const std::string primary_key;
bool valid;
virtual const std::string &primary_key() = 0;
DatabaseEntry(const std::string &);
virtual void write(File &) = 0;
virtual void read(File &) = 0;
virtual void print() = 0;
@ -253,13 +254,13 @@ Database: (lib/database.cpp)
- IndexEntry:
class IndexEntry : public DatabaseEntry {
public:
string key;
set<unsigned int> values;
const std::string &primary_key();
void write(File &);
void read(File &);
void print();
void insert(unsigned int);
void remove(unsigned int);
};
File << key << endl;
@ -283,7 +284,7 @@ Database: (lib/database.cpp)
void print_keys();
unsigned int insert(T);
void delete(unsigned int);
void remove(unsigned int);
unsigned int size();
unsigned int num_rows();
@ -332,7 +333,7 @@ Database: (lib/database.cpp)
mapping is also created into the keys map to map the primary
key back to the id of the newly added item.
void Database :: delete(unsigned int index);
void Database :: remove(unsigned int index);
Mark db[index] as invalid (quick deletion).
unsigned int Database :: size();
@ -342,14 +343,16 @@ Database: (lib/database.cpp)
Return db.size().
unsigned int Database :: first();
Return the id to the first valid row.
Return the id to the first valid row. Return db.size() if
there are no valid rows.
unsigned int Database :: last();
Return the id of the last valid row.
Return the id of the last valid row. Return db.size() if
there are no valid rows.
unsigned int Database :: next(unsigned int &id);
Return the id of the next valid row or throw -EINVAL if there
are no remaining valid rows.
Return the id of the next valid row or return db.size() if
there are no valid rows.
bool Database :: has_key(const std::string &key);
Return true if an item with primary key "key" exists in the
@ -363,13 +366,15 @@ Database: (lib/database.cpp)
template <class T>
T &Database :: find(const std::string &key);
Search for primary key "key" in the database. The reverse
mapping should be used to make this operation faster. Throw
-EEXIST if the key is not found in the mapping.
mapping should be used to make this operation faster.
Throw -EEXIST if the key is not found in the mapping.
Throw -EINVAL if the key points to an invalid entry.
template <class T>
T &Database :: operator[](unsigned int index);
Return a reference to db[index]. Throw -EEXIST if index is out
of range.
Return a reference to db[index].
Throw -EEXIST if index is out of range.
Throw -EINVAL if index is invalid.

View File

@ -32,9 +32,10 @@ Database: (lib/database.cpp)
- DatabaseEntry:
class DatabaseEntry { /* let database modify valid flag */
public:
const std::string primary_key;
bool valid;
virtual const std::string &primary_key() = 0;
DatabaseEntry(const std::string &);
virtual void write(File &) = 0;
virtual void read(File &) = 0;
virtual void print() = 0;
@ -45,13 +46,13 @@ Database: (lib/database.cpp)
- IndexEntry:
class IndexEntry : public DatabaseEntry {
public:
string key;
set<unsigned int> values;
const std::string &primary_key();
void write(File &);
void read(File &);
void print();
void insert(unsigned int);
void remove(unsigned int);
};
File << key << endl;
@ -75,7 +76,7 @@ Database: (lib/database.cpp)
void print_keys();
unsigned int insert(T);
void delete(unsigned int);
void remove(unsigned int);
unsigned int size();
unsigned int num_rows();
@ -124,7 +125,7 @@ Database: (lib/database.cpp)
mapping is also created into the keys map to map the primary
key back to the id of the newly added item.
void Database :: delete(unsigned int index);
void Database :: remove(unsigned int index);
Mark db[index] as invalid (quick deletion).
unsigned int Database :: size();
@ -134,14 +135,16 @@ Database: (lib/database.cpp)
Return db.size().
unsigned int Database :: first();
Return the id to the first valid row.
Return the id to the first valid row. Return db.size() if
there are no valid rows.
unsigned int Database :: last();
Return the id of the last valid row.
Return the id of the last valid row. Return db.size() if
there are no valid rows.
unsigned int Database :: next(unsigned int &id);
Return the id of the next valid row or throw -EINVAL if there
are no remaining valid rows.
Return the id of the next valid row or return db.size() if
there are no valid rows.
bool Database :: has_key(const std::string &key);
Return true if an item with primary key "key" exists in the
@ -155,10 +158,12 @@ Database: (lib/database.cpp)
template <class T>
T &Database :: find(const std::string &key);
Search for primary key "key" in the database. The reverse
mapping should be used to make this operation faster. Throw
-EEXIST if the key is not found in the mapping.
mapping should be used to make this operation faster.
Throw -EEXIST if the key is not found in the mapping.
Throw -EINVAL if the key points to an invalid entry.
template <class T>
T &Database :: operator[](unsigned int index);
Return a reference to db[index]. Throw -EEXIST if index is out
of range.
Return a reference to db[index].
Throw -EEXIST if index is out of range.
Throw -EINVAL if index is invalid.

View File

@ -12,43 +12,42 @@
#include <vector>
template <class T>
class DatabaseEntry {
public:
std::string primary_key;
bool valid;
DatabaseEntry();
virtual T &primary_key() = 0;
virtual void write(File &) = 0;
virtual void read(File &) = 0;
#ifdef CONFIG_DEBUG
#ifdef CONFIG_TEST
virtual void print() = 0;
#endif /* CONFIG_DEBUG */
#endif /* CONFIG_TEST */
};
class IndexEntry : public DatabaseEntry<const std::string> {
class IndexEntry : public DatabaseEntry {
public:
std::string key;
std::set<unsigned int> values;
IndexEntry();
IndexEntry(const std::string &, unsigned int);
~IndexEntry();
const std::string &primary_key();
void write(File &);
void read(File &);
#ifdef CONFIG_TEST
void print();
#endif /* CONFIG_TEST */
void insert(unsigned int);
void remove(unsigned int);
};
template <class T, class U>
template <class T>
class Database {
private:
std::vector<T> db;
std::map<U, unsigned int> keys;
std::map<const std::string, unsigned int> keys;
unsigned int _size;
File file;
@ -57,11 +56,11 @@ public:
~Database();
void save();
void load();
#ifdef CONFIG_DEBUG
#ifdef CONFIG_TEST
void clear();
void print();
void print_keys();
#endif /* CONFIG_DEBUG */
#endif /* CONFIG_TEST */
unsigned int insert(T);
void remove(unsigned int);
@ -71,13 +70,13 @@ public:
unsigned int first();
unsigned int last();
unsigned int next(unsigned int);
bool has_key(const std::string &);
unsigned int find_index(const std::string &);
T &find(const std::string &);
T &operator[](unsigned int);
};
template <class T>
static inline void index_insert(Database<IndexEntry, T> &db,
static inline void index_insert(Database<IndexEntry> &db,
const std::string &key,
unsigned int val)
{
@ -88,8 +87,7 @@ static inline void index_insert(Database<IndexEntry, T> &db,
}
}
template <class T>
static inline void index_remove(Database<IndexEntry, T> &db,
static inline void index_remove(Database<IndexEntry> &db,
const std::string &key,
unsigned int val)
{

View File

@ -7,30 +7,27 @@
#ifndef OCARINA_DATABASE_HPP
#define OCARINA_DATABASE_HPP
#include <error.h>
template <class T>
DatabaseEntry<T> :: DatabaseEntry()
: valid(false)
{
}
template <class T, class U>
Database<T, U> :: Database(std::string filepath)
Database<T> :: Database(std::string filepath)
: _size(0), file(filepath, FILE_TYPE_DATA)
{
}
template <class T, class U>
Database<T, U> :: ~Database()
template <class T>
Database<T> :: ~Database()
{
}
template <class T, class U>
void Database<T, U> :: save()
template <class T>
void Database<T> :: save()
{
if (file.open(OPEN_WRITE) == false)
try {
file.open(OPEN_WRITE);
} catch (int error) {
return;
}
file << db.size() << std::endl;
for (unsigned int i = 0; i < db.size(); i++) {
@ -43,12 +40,16 @@ void Database<T, U> :: save()
file.close();
}
template <class T, class U>
void Database<T, U> :: load()
template <class T>
void Database<T> :: load()
{
unsigned int db_size;
if (file.open(OPEN_READ) == false)
try {
file.open(OPEN_READ);
} catch (int error) {
return;
}
file >> db_size;
db.resize(db_size);
@ -56,7 +57,7 @@ void Database<T, U> :: load()
file >> db[i].valid;
if (db[i].valid == true) {
db[i].read(file);
keys.insert(std::pair<std::string, unsigned int>(db[i].primary_key(), i));
keys.insert(std::pair<std::string, unsigned int>(db[i].primary_key, i));
_size++;
}
}
@ -64,17 +65,17 @@ void Database<T, U> :: load()
file.close();
}
#ifdef CONFIG_DEBUG
template <class T, class U>
void Database<T, U> :: clear()
#ifdef CONFIG_TEST
template <class T>
void Database<T> :: clear()
{
db.clear();
keys.clear();
_size = 0;
}
template <class T, class U>
void Database<T, U> :: print()
template <class T>
void Database<T> :: print()
{
:: print("Allocated rows: %u\n", db.size());
:: print("Valid rows: %u\n", _size);
@ -87,8 +88,8 @@ void Database<T, U> :: print()
}
}
template <class T, class U>
void Database<T, U> :: print_keys()
template <class T>
void Database<T> :: print_keys()
{
std::map<const std::string, unsigned int>::iterator it;
:: print("Found keys:");
@ -96,15 +97,15 @@ void Database<T, U> :: print_keys()
:: print(" %s", it->first.c_str());
:: print("\n");
}
#endif /* CONFIG_DEBUG */
#endif /* CONFIG_TEST */
template <class T, class U>
unsigned int Database<T, U> :: insert(T val)
template <class T>
unsigned int Database<T> :: insert(T val)
{
unsigned int id;
typename std::map<U, unsigned int>::iterator it;
typename std::map<const std::string, unsigned int>::iterator it;
it = keys.find(val.primary_key());
it = keys.find(val.primary_key);
if (it != keys.end())
return it->second;
@ -113,34 +114,34 @@ unsigned int Database<T, U> :: insert(T val)
*/
id = db.size();
db.push_back(val);
keys.insert(std::pair<U, unsigned int>(val.primary_key(), id));
keys.insert(std::pair<const std::string, unsigned int>(val.primary_key, id));
db[id].valid = true;
_size++;
return id;
}
template <class T, class U>
void Database<T, U> :: remove(unsigned int id)
template <class T>
void Database<T> :: remove(unsigned int id)
{
keys.erase(db[id].primary_key());
keys.erase(db[id].primary_key);
db[id].valid = false;
_size--;
}
template <class T, class U>
unsigned int Database<T, U> :: size()
template <class T>
unsigned int Database<T> :: size()
{
return _size;
}
template <class T, class U>
unsigned int Database<T, U> :: num_rows()
template <class T>
unsigned int Database<T> :: num_rows()
{
return db.size();
}
template <class T, class U>
unsigned int Database<T, U> :: first()
template <class T>
unsigned int Database<T> :: first()
{
for (unsigned int i = 0; i < db.size(); i++) {
if (db[i].valid == true)
@ -150,8 +151,8 @@ unsigned int Database<T, U> :: first()
return db.size();
}
template <class T, class U>
unsigned int Database<T, U> :: last()
template <class T>
unsigned int Database<T> :: last()
{
if (_size == 0)
return db.size();
@ -164,8 +165,8 @@ unsigned int Database<T, U> :: last()
return db.size();
}
template <class T, class U>
unsigned int Database<T, U> :: next(unsigned int id)
template <class T>
unsigned int Database<T> :: next(unsigned int id)
{
for (unsigned int i = id + 1; i < db.size(); i++) {
if (db[i].valid == true)
@ -175,25 +176,40 @@ unsigned int Database<T, U> :: next(unsigned int id)
return db.size();
}
template <class T, class U>
unsigned int Database<T, U> :: find_index(const std::string &key)
template <class T>
bool Database<T> :: has_key(const std::string &key)
{
typename std::map<U, unsigned int>::iterator it;
std::map<const std::string, unsigned int>::iterator it;
it = keys.find(key);
return it != keys.end();
}
template <class T>
unsigned int Database<T> :: find_index(const std::string &key)
{
std::map<const std::string, unsigned int>::iterator it;
it = keys.find(key);
if (it == keys.end())
throw 0;
throw -EEXIST;
return it->second;
}
template <class T, class U>
T &Database<T, U> :: find(const std::string &key)
template <class T>
T &Database<T> :: find(const std::string &key)
{
return db[find_index(key)];
unsigned int index = find_index(key);
if (db[index].valid == false)
throw -EINVAL;
return db[index];
}
template <class T, class U>
T &Database<T, U> :: operator[](unsigned int id)
template <class T>
T &Database<T> :: operator[](unsigned int id)
{
if (id >= db.size())
throw -EEXIST;
else if (db[id].valid == false)
throw -EINVAL;
return db[id];
}

View File

@ -3,13 +3,21 @@
*/
#include <database.h>
DatabaseEntry :: DatabaseEntry()
: primary_key(""), valid(false)
{
}
IndexEntry :: IndexEntry()
{
}
IndexEntry :: IndexEntry(const std::string &k, unsigned int v)
: key(k)
IndexEntry :: IndexEntry(const std::string &key, unsigned int v)
{
primary_key = key;
insert(v);
}
@ -17,15 +25,10 @@ IndexEntry :: ~IndexEntry()
{
}
const std::string &IndexEntry :: primary_key()
{
return key;
}
void IndexEntry :: write(File &f)
{
std::set<unsigned int>::iterator it;
f << key << std::endl << values.size() << " ";
f << primary_key << std::endl << values.size() << " ";
for (it = values.begin(); it != values.end(); it++)
f << *it << " ";
}
@ -34,13 +37,14 @@ void IndexEntry :: read(File &f)
{
unsigned int num, val;
f >> key >> num;
f >> primary_key >> num;
for (unsigned int i = 0; i < num; i++) {
f >> val;
values.insert(val);
}
}
#ifdef CONFIG_TEST
void IndexEntry :: print()
{
std::set<unsigned int>::iterator it;
@ -52,6 +56,7 @@ void IndexEntry :: print()
}
:: print("}");
}
#endif /* CONFIG_TEST */
void IndexEntry :: insert(unsigned int val)
{

View File

@ -6,14 +6,12 @@
#include <sstream>
class DBTest : public DatabaseEntry<const std::string> {
class DBTest : public DatabaseEntry {
public:
unsigned int value;
std::string key;
DBTest();
DBTest(unsigned int);
const std::string &primary_key();
void write(File &);
void read(File &);
void print();
@ -29,7 +27,7 @@ DBTest :: DBTest(unsigned int val)
value = val;
ss << value;
key = ss.str();
primary_key = ss.str();
}
void DBTest :: write(File &file)
@ -47,14 +45,9 @@ void DBTest :: print()
:: print("%u", value);
}
const std::string &DBTest :: primary_key()
{
return key;
}
void print_db(Database<DBTest, const std::string> &db)
void print_db(Database<DBTest> &db)
{
print("Database size: %u\n", db.size());
print("Num rows: %u\n", db.num_rows());
@ -65,14 +58,14 @@ void print_db(Database<DBTest, const std::string> &db)
print("db[%u] = %u\n", i, db[i].value);
}
void test_insertion(Database<DBTest, const std::string> &db)
void test_insertion(Database<DBTest> &db)
{
for (unsigned int i = 1; i <= 100000; i++)
db.insert(DBTest(i));
print_db(db);
}
void test_deletion(Database<DBTest, const std::string> &db)
void test_deletion(Database<DBTest> &db)
{
for (unsigned int i = db.first(); i < db.num_rows(); i = db.next(i)) {
db.remove(i);
@ -87,7 +80,7 @@ void test_deletion(Database<DBTest, const std::string> &db)
void test_0()
{
print("Test 0\n");
Database<DBTest, const std::string> db("test.db");
Database<DBTest> db("test.db");
test_insertion(db);
test_deletion(db);
@ -102,7 +95,7 @@ void test_0()
void test_1()
{
print("\nTest 1\n");
Database<DBTest, const std::string> db("test.db");
Database<DBTest> db("test.db");
db.load();
print_db(db);
}
@ -113,7 +106,7 @@ void test_1()
void test_2()
{
print("\nTest 2\n");
Database<DBTest, const std::string> db("");
Database<DBTest> db("");
test_insertion(db);
db.save();
@ -125,7 +118,7 @@ void test_2()
void test_3()
{
print("\nTest 3\n");
Database<DBTest, const std::string> db("");
Database<DBTest> db("");
db.load();
}
@ -135,7 +128,7 @@ void test_3()
void test_4()
{
print("\nTest 4\n");
Database<DBTest, const std::string> db("");
Database<DBTest> db("");
for (unsigned int i = 0; i < 100; i++)
db.insert(DBTest(i % 5));
@ -149,7 +142,7 @@ void test_4()
void test_5()
{
print("\nTest 5\n");
Database<DBTest, const std::string> db("");
Database<DBTest> db("");
for (unsigned int i = 0; i < 10; i++)
db.insert(DBTest(i));
db.print();
@ -161,7 +154,7 @@ void test_5()
void test_6()
{
print("\nTest 6\n");
Database<DBTest, const std::string> db("");
Database<DBTest> db("");
for (unsigned int i = 0; i < 10; i++)
db.insert(DBTest(i));
print_db(db);
@ -175,7 +168,7 @@ void test_6()
void test_7()
{
print("\nTest 7\n");
Database<DBTest, const std::string> db("");
Database<DBTest> db("");
print_db(db);
for (unsigned int i = 0; i < 10; i++)

View File

@ -4,7 +4,7 @@
#include <database.h>
#include <print.h>
void print_index(Database<IndexEntry, const std::string> &index)
void print_index(Database<IndexEntry> &index)
{
std::set<std::string>::iterator s_it;
std::set<unsigned int>::iterator u_it;
@ -13,7 +13,7 @@ void print_index(Database<IndexEntry, const std::string> &index)
index.print_keys();
for (unsigned int i = index.first(); i != index.num_rows(); i = index.next(i)) {
print("index[%s] = ", index[i].key.c_str());
print("index[%s] = ", index[i].primary_key.c_str());
index[i].print();
print("\n");
}
@ -21,7 +21,7 @@ void print_index(Database<IndexEntry, const std::string> &index)
print("\n");
}
void populate_index(Database<IndexEntry, const std::string> &index)
void populate_index(Database<IndexEntry> &index)
{
std::string key_str;
@ -32,17 +32,19 @@ void populate_index(Database<IndexEntry, const std::string> &index)
}
}
void remove_keys(Database<IndexEntry, const std::string> &index)
void remove_keys(Database<IndexEntry> &index)
{
std::string key_str;
for (char key = 'a'; key <= 'z'; key+=2) {
key_str = key;
index.remove(index.find_index(key_str));
if (index.has_key(key_str))
print("Failed to remove key!\n");
}
}
void remove_values(Database<IndexEntry, const std::string> &index)
void remove_values(Database<IndexEntry> &index)
{
std::string key_str;
unsigned int limit = 0;
@ -52,8 +54,11 @@ void remove_values(Database<IndexEntry, const std::string> &index)
for (unsigned int i = 0; i < limit; i++)
index_remove(index, key_str, i);
limit++;
if (limit == 11)
if (limit == 11) {
limit = 0;
if (index.has_key(key_str))
print("Failed to remove key!\n");
}
}
}
@ -63,7 +68,7 @@ void remove_values(Database<IndexEntry, const std::string> &index)
void test_0()
{
print("Test 0\n");
Database<IndexEntry, const std::string> index("");
Database<IndexEntry> index("");
populate_index(index);
print_index(index);
@ -75,7 +80,7 @@ void test_0()
void test_1()
{
print("Test 1\n");
Database<IndexEntry, const std::string> index("");
Database<IndexEntry> index("");
populate_index(index);
remove_keys(index);
@ -88,7 +93,7 @@ void test_1()
void test_2()
{
print("Test 2\n");
Database<IndexEntry, const std::string> index("");
Database<IndexEntry> index("");
populate_index(index);
remove_values(index);
@ -101,7 +106,7 @@ void test_2()
void test_3()
{
print("Test 3\n");
Database<IndexEntry, const std::string> index("test.idx");
Database<IndexEntry> index("test.idx");
populate_index(index);
remove_values(index);
@ -114,7 +119,7 @@ void test_3()
void test_4()
{
print("Test 4\n");
Database<IndexEntry, const std::string> index("test.idx");
Database<IndexEntry> index("test.idx");
index.load();
print_index(index);
@ -126,7 +131,7 @@ void test_4()
void test_5()
{
print("Test 5\n");
Database<IndexEntry, const std::string> index("");
Database<IndexEntry> index("");
print("index[nokey].size() = ");
try {
print("%u\n", index.find("nokey").values.size());