aboutsummaryrefslogtreecommitdiff
path: root/src/DatabaseStorage.cpp
blob: 0f75d1f63a3fdcbb5c0f90b2fa8401886b1c8220 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "../include/DatabaseStorage.hpp"
#include "../include/User.hpp"
#include "../include/Group.hpp"
#include <cstring>
#include <chrono>

using namespace std;

namespace odhtdb
{
    const u64 QUARANTINE_STORAGE_TIME_MICROSECONDS = 60 * 1.0e6;
    
    DatabaseStorageObject::DatabaseStorageObject(DataView &_data, u64 _timestamp, const Signature::PublicKey &_creatorPublicKey) : 
        data(_data), createdTimestamp(_timestamp), creatorPublicKey(_creatorPublicKey)
    {
        
    }
    
    DatabaseStorageQuarantineObject::DatabaseStorageQuarantineObject(DataView &_data, u64 _timestamp, const Signature::PublicKey &_creatorPublicKey) : 
        data(_data), createdTimestamp(_timestamp), creatorPublicKey(_creatorPublicKey)
    {
        auto time = chrono::high_resolution_clock::now().time_since_epoch();
        storedTimestamp = chrono::duration_cast<chrono::microseconds>(time).count();
    }
    
    void DatabaseStorage::createStorage(const Hash &hash, Group *creatorGroup, u64 timestamp, const u8 *data, usize dataSize)
    {
        if(storageMap.find(hash) != storageMap.end())
        {
            string errMsg = "Database storage with hash ";
            errMsg += hash.toString();
            errMsg += " already exists";
            throw DatabaseStorageAlreadyExists(errMsg);
        }
        
        DatabaseStorageObjectList *databaseStorageObjectList = new DatabaseStorageObjectList();
        databaseStorageObjectList->createdTimestamp = timestamp;
        databaseStorageObjectList->groups.push_back(creatorGroup);
        databaseStorageObjectList->data = DataView(new u8[dataSize], dataSize);
        memcpy(databaseStorageObjectList->data.data, data, dataSize);
        storageMap[hash] = databaseStorageObjectList;
        groupByIdMap[creatorGroup->getId()] = creatorGroup;
        
        for(auto user : creatorGroup->getUsers())
        {
            addUser((User*)user, hash);
        }
    }
    
    void DatabaseStorage::appendStorage(const Hash &nodeHash, const Hash &dataHash, const User *creatorUser, u64 timestamp, const u8 *data, usize dataSize)
    {
        auto it = storageMap.find(nodeHash);
        if(it == storageMap.end())
        {
            string errMsg = "Database storage with hash ";
            errMsg += nodeHash.toString();
            errMsg += " not found. Storage for a hash needs to be created before data can be appended to it";
            throw DatabaseStorageNotFound(errMsg);
        }
        
        auto storedDataIt = storedDataHash.find(dataHash);
        if(storedDataIt != storedDataHash.end())
        {
            string errMsg = "Database already contains data with hash: ";
            errMsg += dataHash.toString();
            throw DatabaseStorageAlreadyExists(errMsg);
        }
        
        DataView storageData { new u8[dataSize], dataSize };
        memcpy(storageData.data, data, dataSize);
        DatabaseStorageObject *databaseStorageObject = new DatabaseStorageObject(storageData, timestamp, creatorUser->getPublicKey());
        it->second->objects.push_back(databaseStorageObject);
        storedDataHash.insert(dataHash);
    }
    
    void DatabaseStorage::addToQuarantine(const Hash &dataHash, const Signature::PublicKey &creatorPublicKey, u64 timestamp, const u8 *data, usize dataSize)
    {
        auto storedDataIt = storedDataHash.find(dataHash);
        if(storedDataIt != storedDataHash.end())
        {
            string errMsg = "Database already contains data with hash: ";
            errMsg += dataHash.toString();
            throw DatabaseStorageAlreadyExists(errMsg);
        }
        
        DataView storageData { new u8[dataSize], dataSize };
        memcpy(storageData.data, data, dataSize);
        DatabaseStorageQuarantineObject *databaseQuarantineStorageObject = new DatabaseStorageQuarantineObject(storageData, timestamp, creatorPublicKey);
        quarantineStorageMap[creatorPublicKey].emplace_back(databaseQuarantineStorageObject);
        storedDataHash.insert(dataHash);
    }
    
    void DatabaseStorage::addUser(User *user, const Hash &hash)
    {
        userPublicKeyNodeMap[user->getPublicKey()] = new Hash(hash);
        publicKeyUserMap[user->getPublicKey()] = user;
    }
    
    const DatabaseStorageObjectList* DatabaseStorage::getStorage(const Hash &hash) const
    {
        auto it = storageMap.find(hash);
        if(it != storageMap.end())
            return it->second;
        return nullptr;
    }
    
    const Hash* DatabaseStorage::getNodeByUserPublicKey(const Signature::PublicKey &userPublicKey) const
    {
        auto it = userPublicKeyNodeMap.find(userPublicKey);
        if(it != userPublicKeyNodeMap.end())
            return it->second;
        return nullptr;
    }
    
    // Returns nullptr if no user with public key exists
    const User* DatabaseStorage::getUserByPublicKey(const Signature::PublicKey &userPublicKey) const
    {
        auto it = publicKeyUserMap.find(userPublicKey);
        if(it != publicKeyUserMap.end())
            return it->second;
        return nullptr;
    }
    
    Group* DatabaseStorage::getGroupById(uint8_t groupId[16])
    {
        auto it = groupByIdMap.find(DataView(groupId, 16));
        if(it != groupByIdMap.end())
            return it->second;
        return nullptr;
    }
    
    void DatabaseStorage::update()
    {
        auto time = chrono::high_resolution_clock::now().time_since_epoch();
        auto timeMicroseconds = chrono::duration_cast<chrono::microseconds>(time).count();
        for(auto mapIt = quarantineStorageMap.begin(); mapIt != quarantineStorageMap.end(); )
        {
            for(auto vecIt = mapIt->second.begin(); vecIt != mapIt->second.end(); )
            {
                if(timeMicroseconds - (*vecIt)->storedTimestamp > QUARANTINE_STORAGE_TIME_MICROSECONDS)
                    vecIt = mapIt->second.erase(vecIt);
                else
                    ++vecIt;
            }
            
            if(mapIt->second.empty())
                mapIt = quarantineStorageMap.erase(mapIt);
            else
                ++mapIt;
        }
    }
}