diff --git a/services/backup/docker-server/contents/server/dev/DatabaseSimulator.h b/services/backup/docker-server/contents/server/dev/DatabaseSimulator.h new file mode 100644 --- /dev/null +++ b/services/backup/docker-server/contents/server/dev/DatabaseSimulator.h @@ -0,0 +1,33 @@ +#pragma once + +#include "DatabaseEntitiesTools.h" + +#include + +#include +#include +#include +#include +#include + +namespace comm { +namespace network { +namespace database { + +// thread-safe in-memory database +struct DatabaseSimulator { + // userID -> map(created -> item) + folly::ConcurrentHashMap< + std::string, + std::unique_ptr>> + backup; + // backup id -> list of logs + folly::ConcurrentHashMap< + std::string, + std::unique_ptr>>> + log; +}; + +} // namespace database +} // namespace network +} // namespace comm diff --git a/services/backup/docker-server/contents/server/src/DatabaseManager.dev.cpp b/services/backup/docker-server/contents/server/src/DatabaseManager.dev.cpp new file mode 100644 --- /dev/null +++ b/services/backup/docker-server/contents/server/src/DatabaseManager.dev.cpp @@ -0,0 +1,94 @@ +#include "DatabaseManager.h" +#include "Tools.h" + +#include +#include + +namespace comm { +namespace network { +namespace database { + +DatabaseManager &DatabaseManager::getInstance() { + static DatabaseManager instance; + return instance; +} + +void DatabaseManager::putBackupItem(const BackupItem &item) { + std::shared_ptr backupItem = std::make_shared( + item.getUserID(), + item.getBackupID(), + item.getCreated(), + item.getRecoveryData(), + item.getCompactionHolder(), + item.getAttachmentHolders()); + if (this->dbSimulator.backup.find(item.getUserID()) == + this->dbSimulator.backup.end()) { + this->dbSimulator.backup.insert( + item.getUserID(), std::make_unique>()); + } + this->dbSimulator.backup.find(item.getUserID()) + ->second->insert({backupItem->getCreated(), *backupItem}); +} + +std::shared_ptr +DatabaseManager::findLastBackupItem(const std::string &userID) { + auto it = this->dbSimulator.backup.find(userID); + if (it == this->dbSimulator.backup.end()) { + return nullptr; + } + if (it->second->empty()) { + return nullptr; + } + return std::make_shared((--it->second->end())->second); +} + +void DatabaseManager::removeBackupItem(std::shared_ptr item) { + auto it = this->dbSimulator.backup.find(item->getUserID()); + if (it == this->dbSimulator.backup.end()) { + return; + } + it->second->erase(item->getCreated()); +} + +void DatabaseManager::putLogItem(const LogItem &item) { + if (this->dbSimulator.log.find(item.getBackupID()) == + this->dbSimulator.log.end()) { + this->dbSimulator.log.insert( + item.getBackupID(), + std::make_unique>>()); + } + this->dbSimulator.log.find(item.getBackupID()) + ->second->push_back(std::make_shared( + item.getBackupID(), + item.getLogID(), + item.getPersistedInBlob(), + item.getValue(), + item.getAttachmentHolders())); +} + +std::vector> +DatabaseManager::findLogItemsForBackup(const std::string &backupID) { + auto it = this->dbSimulator.log.find(backupID); + if (it == this->dbSimulator.log.end()) { + return {}; + } + return *it->second; +} + +void DatabaseManager::removeLogItem(std::shared_ptr item) { + auto foundIt = this->dbSimulator.log.find(item->getBackupID()); + if (foundIt == this->dbSimulator.log.end()) { + return; + } + for (auto it = foundIt->second->begin(); it != foundIt->second->end();) { + if (it->get()->getLogID() == item->getLogID()) { + it = foundIt->second->erase(it); + } else { + ++it; + } + } +} + +} // namespace database +} // namespace network +} // namespace comm diff --git a/services/backup/docker-server/contents/server/test/DatabaseManagerTest.cpp b/services/backup/docker-server/contents/server/test/DatabaseManagerTest.cpp --- a/services/backup/docker-server/contents/server/test/DatabaseManagerTest.cpp +++ b/services/backup/docker-server/contents/server/test/DatabaseManagerTest.cpp @@ -28,13 +28,13 @@ BackupItem generateBackupItem(const std::string &userID, const std::string &backupID) { - return BackupItem( - userID, - backupID, - comm::network::getCurrentTimestamp(), - "xxx", - "xxx", - {""}); + // this simulates operations that are going to occur one after another on the + // timeline. For the dev mode this was failing when reading the current time + // because operations on collections were fast and occuring at the same + // exact millisecond. In practice, this should never happen (grpc connection + // should cause the delay) + static uint64_t operationID = comm::network::getCurrentTimestamp(); + return BackupItem(userID, backupID, operationID++, "xxx", "xxx", {""}); } LogItem generateLogItem(const std::string &backupID, const std::string &logID) { @@ -86,7 +86,9 @@ EXPECT_EQ(items2.size(), 2); for (size_t i = 0; i < items1.size(); ++i) { - EXPECT_EQ(logIDs1.at(i), items1.at(i)->getLogID()); + EXPECT_NE( + std::find(logIDs1.begin(), logIDs1.end(), items1.at(i)->getLogID()), + logIDs1.end()); DatabaseManager::getInstance().removeLogItem(items1.at(i)); } EXPECT_EQ( @@ -94,7 +96,9 @@ 0); for (size_t i = 0; i < items2.size(); ++i) { - EXPECT_EQ(logIDs2.at(i), items2.at(i)->getLogID()); + EXPECT_NE( + std::find(logIDs2.begin(), logIDs2.end(), items2.at(i)->getLogID()), + logIDs2.end()); DatabaseManager::getInstance().removeLogItem(items2.at(i)); } EXPECT_EQ(