diff --git a/libpkg/data/database.cpp b/libpkg/data/database.cpp index 78b34ce..c304f25 100644 --- a/libpkg/data/database.cpp +++ b/libpkg/data/database.cpp @@ -404,21 +404,6 @@ StorageID Database::forceUpdatePackage(const std::shared_ptr &package) return res.id; } -void Database::replacePackages(const std::vector> &newPackages, DateTime lastModified) -{ - for (const auto &package : newPackages) { - if (const auto existingPackage = findPackage(package->name)) { - package->addDepsAndProvidesFromOtherPackage(*existingPackage); - } - } - auto updater = PackageUpdater(*this, true); - for (const auto &package : newPackages) { - updater.update(package); - } - updater.commit(); - lastUpdate = lastModified; -} - /*! * \brief Determines which packages are unresolvable assuming new packages are added to the database and certain provides are removed. * \param config The configuration supposed to contain database dependencies. @@ -799,6 +784,18 @@ StorageID PackageUpdater::update(const std::shared_ptr &package) return res.id; } +bool PackageUpdater::insertFromDatabaseFile(const std::string &databaseFilePath) +{ + LibPkg::Package::fromDatabaseFile(databaseFilePath, [this](const std::shared_ptr &package) { + if (const auto [id, existingPackage] = findPackageWithID(package->name); existingPackage) { + package->addDepsAndProvidesFromOtherPackage(*existingPackage); + } + update(package); + return false; + }); + return false; +} + void PackageUpdater::commit() { const auto &storage = m_database.m_storage; diff --git a/libpkg/data/database.h b/libpkg/data/database.h index e92264a..82c4254 100644 --- a/libpkg/data/database.h +++ b/libpkg/data/database.h @@ -106,6 +106,7 @@ struct LIBPKG_EXPORT PackageUpdater { PackageSpec findPackageWithID(const std::string &packageName); StorageID update(const std::shared_ptr &package); + bool insertFromDatabaseFile(const std::string &databaseFilePath); void commit(); private: @@ -147,8 +148,7 @@ struct LIBPKG_EXPORT Database : public ReflectiveRapidJSON::JsonSerializable> findPackages(const std::function &pred); void allPackages(const PackageVisitorMove &visitor); @@ -164,7 +164,6 @@ struct LIBPKG_EXPORT Database : public ReflectiveRapidJSON::JsonSerializable &package); StorageID forceUpdatePackage(const std::shared_ptr &package); - void replacePackages(const std::vector> &newPackages, CppUtilities::DateTime lastModified); std::unordered_map detectUnresolvedPackages(Config &config, const std::vector> &newPackages, const DependencySet &removedPackages, const std::unordered_set &depsToIgnore = std::unordered_set(), diff --git a/libpkg/data/package.h b/libpkg/data/package.h index 031f22a..e072d7f 100644 --- a/libpkg/data/package.h +++ b/libpkg/data/package.h @@ -384,9 +384,9 @@ struct LIBPKG_EXPORT Package : public ReflectiveRapidJSON::JsonSerializable &dllsReferencedByImportLibs); + std::string_view directoryPath, const ArchiveFile &file, std::set &dllsReferencedByImportLibs); void addDepsAndProvidesFromContents(const FileMap &contents); std::vector processDllsReferencedByImportLibs(std::set &&dllsReferencedByImportLibs); bool addDepsAndProvidesFromOtherPackage(const Package &otherPackage, bool force = false); @@ -397,8 +397,7 @@ struct LIBPKG_EXPORT Package : public ReflectiveRapidJSON::JsonSerializable fromInfo(const std::string &info, bool isPackageInfo = false); static std::shared_ptr fromDescription(const std::vector &descriptionParts); - static std::vector> fromDatabaseFile(FileMap &&databaseFile); - static void fromDatabaseFile(FileMap &&databaseFile, const std::function)> &visitor); + static void fromDatabaseFile(const std::string &archivePath, const std::function)> &visitor); static std::shared_ptr fromPkgFile(const std::string &path); static std::tuple fileNameComponents(std::string_view fileName); static std::shared_ptr fromPkgFileName(std::string_view fileName); diff --git a/libpkg/parser/binary.cpp b/libpkg/parser/binary.cpp index 678dbb1..f66800b 100644 --- a/libpkg/parser/binary.cpp +++ b/libpkg/parser/binary.cpp @@ -11,6 +11,7 @@ #include #include #include +#include using namespace std; using namespace CppUtilities; @@ -199,7 +200,7 @@ void Binary::load(std::string_view filePath) } } -void Binary::load(const string &fileContent, const string &fileName, const string &directoryPath, bool isRegularFile) +void Binary::load(std::string_view fileContent, std::string_view fileName, std::string_view directoryPath, bool isRegularFile) { stringstream fileStream(ios_base::in | ios_base::out | ios_base::binary); fileStream.exceptions(ios_base::failbit | ios_base::badbit); @@ -239,17 +240,17 @@ static std::string toLower(std::string str) return str; } -std::string Binary::addPrefix(const std::string &dependencyName) const +std::string Binary::addPrefix(std::string_view dependencyName) const { switch (type) { case BinaryType::Elf: return argsToString(extraPrefix, "elf-", architecture, ':', ':', dependencyName); case BinaryType::Pe: - return argsToString(extraPrefix, "pe-", architecture, ':', ':', toLower(dependencyName)); + return argsToString(extraPrefix, "pe-", architecture, ':', ':', toLower(std::string(dependencyName))); case BinaryType::Ar: switch (subType) { case BinarySubType::WindowsImportLibrary: - return argsToString(extraPrefix, "pe-", architecture, ':', ':', toLower(dependencyName)); + return argsToString(extraPrefix, "pe-", architecture, ':', ':', toLower(std::string(dependencyName))); default:; } default: @@ -257,7 +258,7 @@ std::string Binary::addPrefix(const std::string &dependencyName) const } } -void Binary::parse(istream &stream, const string *fileContent) +void Binary::parse(std::istream &stream, const std::string_view *fileContent) { type = BinaryType::Invalid; @@ -285,7 +286,7 @@ void Binary::parse(istream &stream, const string *fileContent) } } -void Binary::parseElf(BinaryReader &reader, const string *fileContent) +void Binary::parseElf(BinaryReader &reader, const std::string_view *fileContent) { istream &stream = *reader.stream(); @@ -731,8 +732,8 @@ std::uint16_t Binary::readElfInt16(BinaryReader &reader) return isBigEndian ? reader.readUInt16BE() : reader.readUInt16LE(); } -string Binary::readElfString( - istream &stream, const string *fileContent, std::uint64_t stringTableAddress, std::uint64_t stringTableSize, std::uint64_t relativeStringAddress) +std::string Binary::readElfString(std::istream &stream, const std::string_view *fileContent, std::uint64_t stringTableAddress, + std::uint64_t stringTableSize, std::uint64_t relativeStringAddress) { // check bounds if (relativeStringAddress >= stringTableSize) { diff --git a/libpkg/parser/binary.h b/libpkg/parser/binary.h index 5564c9e..3f5e682 100644 --- a/libpkg/parser/binary.h +++ b/libpkg/parser/binary.h @@ -83,8 +83,8 @@ inline VirtualAddressMapping::VirtualAddressMapping() struct LIBPKG_EXPORT Binary { void load(std::string_view filePath); - void load(const std::string &fileContent, const std::string &fileName, const std::string &directoryPath, bool isRegularFile = false); - std::string addPrefix(const std::string &dependencyName) const; + void load(std::string_view fileContent, std::string_view fileName, std::string_view directoryPath, bool isRegularFile = false); + std::string addPrefix(std::string_view dependencyName) const; BinaryType type = BinaryType::Invalid; BinarySubType subType = BinarySubType::None; @@ -99,8 +99,8 @@ struct LIBPKG_EXPORT Binary { VirtualAddressMapping virtualAddressMapping; private: - void parse(std::istream &stream, const std::string *fileContent = nullptr); - void parseElf(CppUtilities::BinaryReader &reader, const std::string *fileContent = nullptr); + void parse(std::istream &stream, const std::string_view *fileContent = nullptr); + void parseElf(CppUtilities::BinaryReader &reader, const std::string_view *fileContent = nullptr); void parsePe(CppUtilities::BinaryReader &reader, typename std::iostream::off_type baseFileOffset = 0); void parseAr(CppUtilities::BinaryReader &reader); void parseCoff(CppUtilities::BinaryReader &reader); @@ -108,8 +108,8 @@ private: std::uint64_t readElfAddress(CppUtilities::BinaryReader &reader); std::uint32_t readElfInt32(CppUtilities::BinaryReader &reader); std::uint16_t readElfInt16(CppUtilities::BinaryReader &reader); - std::string readElfString(std::istream &stream, const std::string *fileContent, std::uint64_t stringTableOffset, std::uint64_t stringTableSize, - std::uint64_t stringOffset); + std::string readElfString(std::istream &stream, const std::string_view *fileContent, std::uint64_t stringTableOffset, + std::uint64_t stringTableSize, std::uint64_t stringOffset); }; } // namespace LibPkg diff --git a/libpkg/parser/database.cpp b/libpkg/parser/database.cpp index ed821ed..138bf41 100644 --- a/libpkg/parser/database.cpp +++ b/libpkg/parser/database.cpp @@ -29,32 +29,16 @@ void Database::loadPackagesFromConfiguredPaths(bool withFiles, bool force) } const auto lastFileUpdate = lastModified(dbPath); if (force || lastFileUpdate > lastUpdate) { - loadPackages(extractFiles(dbPath, &isFileRelevant), lastFileUpdate); + loadPackages(dbPath, lastFileUpdate); } } -void LibPkg::Database::loadPackages(const string &databaseData, DateTime lastModified) +void Database::loadPackages(const std::string &databaseFilePath, DateTime lastModified) { - loadPackages(extractFilesFromBuffer(databaseData, name + " db file", &isFileRelevant), lastModified); -} - -void Database::loadPackages(FileMap &&databaseFiles, DateTime lastModified) -{ - lastUpdate = lastModified; - auto updater = PackageUpdater(*this); - for (auto &dir : databaseFiles) { - if (dir.first.find('/') != std::string::npos) { - cerr << Phrases::WarningMessage << "Database \"" << name << "\" contains unexpected sub directory: " << dir.first << Phrases::EndFlush; - continue; - } - auto descriptionParts = std::vector(); - descriptionParts.reserve(dir.second.size()); - for (auto &file : dir.second) { - descriptionParts.emplace_back(std::move(file.content)); - } - updater.update(Package::fromDescription(descriptionParts)); - } + auto updater = PackageUpdater(*this, true); + updater.insertFromDatabaseFile(databaseFilePath); updater.commit(); + lastUpdate = lastModified; } } // namespace LibPkg diff --git a/libpkg/parser/package.cpp b/libpkg/parser/package.cpp index e1a7680..8e3b83e 100644 --- a/libpkg/parser/package.cpp +++ b/libpkg/parser/package.cpp @@ -716,33 +716,40 @@ std::shared_ptr Package::fromDescription(const std::vector return package; } -std::vector> Package::fromDatabaseFile(FileMap &&databaseFile) +void Package::fromDatabaseFile(const std::string &archivePath, const std::function)> &visitor) { - std::vector> packages; - packages.reserve(databaseFile.size()); - std::vector descriptionParts; - for (auto &dir : databaseFile) { - descriptionParts.clear(); - descriptionParts.reserve(dir.second.size()); - for (auto &file : dir.second) { - descriptionParts.emplace_back(std::move(file.content)); - } - packages.emplace_back(Package::fromDescription(descriptionParts)); - } - return packages; -} + // walk though archive, file-by-file; parse files as soon as desc/files available and return via visitor + auto packages = std::unordered_map>(); + walkThroughArchive( + archivePath, &Database::isFileRelevant, + [&packages, &visitor](std::string_view path, ArchiveFile &&file) { + auto i = packages.find(std::string(path)); // FIXME: this should actually accept std::string_view in C++20 + if (i == packages.end()) { + i = packages.emplace(std::string(path), 2).first; + } + auto &parts = i->second; + if (file.name == "desc") { + parts[0] = std::move(file.content); + } else if (file.name == "files") { + parts[1] = std::move(file.content); + } + if (!parts[0].empty() && !parts[1].empty()) { + if (visitor(Package::fromDescription(parts))) { + return true; + } + // remove buffered data immediately to avoid using too much memory + packages.erase(i); + } + return false; + }, + [](std::string_view) { return false; }); -void Package::fromDatabaseFile(FileMap &&databaseFile, const std::function)> &visitor) -{ - std::vector descriptionParts; - for (auto &dir : databaseFile) { - descriptionParts.clear(); - descriptionParts.reserve(dir.second.size()); - for (auto &file : dir.second) { - descriptionParts.emplace_back(std::move(file.content)); - } - if (visitor(Package::fromDescription(descriptionParts))) { - return; + // take care of packages without "files" file + for (auto &[packageName, parts] : packages) { + if (!parts[0].empty()) { + if (visitor(Package::fromDescription(parts))) { + return; + } } } } @@ -768,11 +775,11 @@ void Package::addInfoFromPkgInfoFile(const string &info) static const regex pythonVersionRegex("usr/lib/python(2|3)\\.([0-9]*)(\\..*)?/site-packages"); static const regex perlVersionRegex("usr/lib/perl5/5\\.([0-9]*)(\\..*)?/vendor_perl"); -void Package::addDepsAndProvidesFromContainedDirectory(const std::string &directoryPath) +void Package::addDepsAndProvidesFromContainedDirectory(std::string_view directoryPath) { // check for Python modules - thread_local smatch match; - if (regex_match(directoryPath, match, pythonVersionRegex)) { + thread_local auto match = std::match_results(); + if (std::regex_match(directoryPath.begin(), directoryPath.end(), match, pythonVersionRegex)) { const auto majorVersion = match[1].str(); const auto minorVersion = match[2].str(); const char *const pythonPackage(majorVersion == "3" ? "python" : "python2"); @@ -783,7 +790,7 @@ void Package::addDepsAndProvidesFromContainedDirectory(const std::string &direct } // check for Perl modules - if (regex_match(directoryPath, match, perlVersionRegex)) { + if (std::regex_match(directoryPath.begin(), directoryPath.end(), match, perlVersionRegex)) { const auto minorVersion = match[1].str(); auto currentVersion = "5." + minorVersion; auto nextVersion = "5." + numberToString(stringToNumber(minorVersion) + 1); @@ -793,7 +800,7 @@ void Package::addDepsAndProvidesFromContainedDirectory(const std::string &direct } void Package::addDepsAndProvidesFromContainedFile( - const std::string &directoryPath, const ArchiveFile &file, std::set &dllsReferencedByImportLibs) + std::string_view directoryPath, const ArchiveFile &file, std::set &dllsReferencedByImportLibs) { try { Binary binary; @@ -858,24 +865,26 @@ std::shared_ptr Package::fromPkgFile(const string &path) shared_ptr package; LibPkg::walkThroughArchive( path, &LibPkg::Package::isPkgInfoFileOrBinary, - [&package, &tmpPackageForLibraryDeps, &dllsReferencedByImportLibs](std::string &&directoryPath, LibPkg::ArchiveFile &&file) { + [&package, &tmpPackageForLibraryDeps, &dllsReferencedByImportLibs](std::string_view directoryPath, LibPkg::ArchiveFile &&file) { if (directoryPath.empty() && file.name == ".PKGINFO") { if (package) { - return; // only consider one .PKGINFO file (multiple ones are likely not possible in any supported archive formats anyways) + return false; // only consider one .PKGINFO file (multiple ones are likely not possible in any supported archive formats anyways) } auto packages = fromInfo(file.content, true); if (!packages.empty()) { package = std::move(packages.front().pkg); } - return; + return false; } tmpPackageForLibraryDeps.addDepsAndProvidesFromContainedFile(directoryPath, file, dllsReferencedByImportLibs); + return false; }, - [&tmpPackageForLibraryDeps](std::string &&directoryPath) { + [&tmpPackageForLibraryDeps](std::string_view directoryPath) { if (directoryPath.empty()) { - return; + return false; } tmpPackageForLibraryDeps.addDepsAndProvidesFromContainedDirectory(directoryPath); + return false; }); if (!package) { throw runtime_error("Package " % path + " does not contain a valid .PKGINFO"); diff --git a/libpkg/parser/utils.cpp b/libpkg/parser/utils.cpp index 525ae2f..d5df616 100644 --- a/libpkg/parser/utils.cpp +++ b/libpkg/parser/utils.cpp @@ -21,17 +21,19 @@ using namespace CppUtilities; namespace LibPkg { struct AddDirectoryToFileMap { - void operator()(std::string &&path) + bool operator()(std::string_view path) { - fileMap[std::move(path)]; + fileMap[std::string(path)]; + return false; } FileMap &fileMap; }; struct AddFileToFileMap { - void operator()(std::string &&directoryPath, ArchiveFile &&file) + bool operator()(std::string_view directoryPath, ArchiveFile &&file) { - fileMap[std::move(directoryPath)].emplace_back(std::move(file)); + fileMap[std::string(directoryPath)].emplace_back(std::move(file)); + return false; } FileMap &fileMap; }; @@ -40,8 +42,8 @@ void walkThroughArchiveInternal(struct archive *ar, const string &archiveName, c DirectoryHandler &&directoryHandler) { // iterate through all archive entries - struct archive_entry *entry; - while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) { + struct archive_entry *const entry = archive_entry_new(); + while (archive_read_next_header2(ar, entry) == ARCHIVE_OK) { // check entry type (only dirs, files and symlinks relevant here) const auto entryType(archive_entry_filetype(entry)); if (entryType != AE_IFDIR && entryType != AE_IFREG && entryType != AE_IFLNK) { @@ -70,7 +72,9 @@ void walkThroughArchiveInternal(struct archive *ar, const string &archiveName, c } } - directoryHandler(string(filePath, dirEnd)); + if (directoryHandler(std::string_view(filePath, dirEnd))) { + return; + } continue; } @@ -94,21 +98,23 @@ void walkThroughArchiveInternal(struct archive *ar, const string &archiveName, c // read symlink if (entryType == AE_IFLNK) { - fileHandler(string(filePath, static_cast(dirEnd - filePath)), - ArchiveFile(fileName, string(archive_entry_symlink_utf8(entry)), ArchiveFileType::Link, creationTime, modificationTime)); + if (fileHandler(std::string_view(filePath, static_cast(dirEnd - filePath)), + ArchiveFile(fileName, std::string(archive_entry_symlink_utf8(entry)), ArchiveFileType::Link, creationTime, modificationTime))) { + return; + } continue; } // determine file size to pre-allocate buffer for file content const la_int64_t fileSize = archive_entry_size(entry); - string fileContent; + std::string fileContent; if (fileSize > 0) { fileContent.reserve(static_cast(fileSize)); } // read file content const char *buff; - size_t size; + std::size_t size; la_int64_t offset; for (;;) { int returnCode = archive_read_data_block(ar, reinterpret_cast(&buff), &size, &offset); @@ -119,11 +125,14 @@ void walkThroughArchiveInternal(struct archive *ar, const string &archiveName, c } // move it to results - fileHandler(string(filePath, static_cast(dirEnd - filePath)), - ArchiveFile(fileName, move(fileContent), ArchiveFileType::Regular, creationTime, modificationTime)); + if (fileHandler(std::string_view(filePath, static_cast(dirEnd - filePath)), + ArchiveFile(fileName, std::move(fileContent), ArchiveFileType::Regular, creationTime, modificationTime))) { + return; + } } // free resources used by libarchive + archive_entry_free(entry); int returnCode = archive_read_free(ar); if (returnCode != ARCHIVE_OK) { throw runtime_error("Unable to free archive: " + archiveName); diff --git a/libpkg/parser/utils.h b/libpkg/parser/utils.h index b3b4fbb..2a9478a 100644 --- a/libpkg/parser/utils.h +++ b/libpkg/parser/utils.h @@ -37,8 +37,8 @@ struct LIBPKG_EXPORT ArchiveFile { using FileMap = std::map>; using FilePredicate = std::function; -using DirectoryHandler = std::function; -using FileHandler = std::function; +using DirectoryHandler = std::function; +using FileHandler = std::function; LIBPKG_EXPORT FileMap extractFiles(const std::string &archivePath, const FilePredicate &isFileRelevant = FilePredicate()); LIBPKG_EXPORT void walkThroughArchive(const std::string &archivePath, const FilePredicate &isFileRelevant = FilePredicate(), diff --git a/librepomgr/buildactions/reloaddatabase.cpp b/librepomgr/buildactions/reloaddatabase.cpp index b153032..4485383 100644 --- a/librepomgr/buildactions/reloaddatabase.cpp +++ b/librepomgr/buildactions/reloaddatabase.cpp @@ -80,6 +80,7 @@ void ReloadDatabase::run() boost::asio::post( m_setup.building.ioContext.get_executor(), [this, force, session, dbName = db->name, dbArch = db->arch, dbPath = move(dbPath)]() mutable { try { + auto configLock = m_setup.config.lockToRead(); auto dbFileLock = m_setup.locks.acquireToRead(m_buildAction->log(), ServiceSetup::Locks::forDatabase(dbName, dbArch)); const auto lastModified = LibPkg::lastModified(dbPath); if (!force) { @@ -93,13 +94,10 @@ void ReloadDatabase::run() return; } } - auto dbFile = LibPkg::extractFiles(dbPath, &LibPkg::Database::isFileRelevant); - dbFileLock.lock().unlock(); m_buildAction->appendOutput( Phrases::InfoMessage, "Loading database \"", dbName, '@', dbArch, "\" from local file \"", dbPath, "\"\n"); - auto configLock = m_setup.config.lockToRead(); auto *const destinationDb = m_setup.config.findDatabase(dbName, dbArch); if (!destinationDb) { configLock.unlock(); @@ -110,13 +108,8 @@ void ReloadDatabase::run() } auto updater = LibPkg::PackageUpdater(*destinationDb, true); - LibPkg::Package::fromDatabaseFile(std::move(dbFile), [&updater](std::shared_ptr package) { - if (const auto [id, existingPackage] = updater.findPackageWithID(package->name); existingPackage) { - package->addDepsAndProvidesFromOtherPackage(*existingPackage); - } - updater.update(package); - return false; - }); + updater.insertFromDatabaseFile(dbPath); + dbFileLock.lock().unlock(); updater.commit(); destinationDb->lastUpdate = lastModified; } catch (const std::runtime_error &e) { diff --git a/librepomgr/buildactions/reloadlibrarydependencies.cpp b/librepomgr/buildactions/reloadlibrarydependencies.cpp index 56cfb9c..bb9f925 100644 --- a/librepomgr/buildactions/reloadlibrarydependencies.cpp +++ b/librepomgr/buildactions/reloadlibrarydependencies.cpp @@ -320,21 +320,23 @@ void ReloadLibraryDependencies::loadPackageInfoFromContents() // extract the binary package's files try { - std::set dllsReferencedByImportLibs; + auto dllsReferencedByImportLibs = std::set(); LibPkg::walkThroughArchive( currentPkg.path, &LibPkg::Package::isPkgInfoFileOrBinary, - [¤tPkg, &dllsReferencedByImportLibs](std::string &&directoryPath, LibPkg::ArchiveFile &&file) { + [¤tPkg, &dllsReferencedByImportLibs](std::string_view directoryPath, LibPkg::ArchiveFile &&file) { if (directoryPath.empty() && file.name == ".PKGINFO") { currentPkg.info.addInfoFromPkgInfoFile(file.content); - return; + return false; } currentPkg.info.addDepsAndProvidesFromContainedFile(directoryPath, file, dllsReferencedByImportLibs); + return false; }, - [¤tPkg](std::string &&directoryPath) { + [¤tPkg](std::string_view directoryPath) { if (directoryPath.empty()) { - return; + return false; } currentPkg.info.addDepsAndProvidesFromContainedDirectory(directoryPath); + return false; }); if (auto dllIssues = currentPkg.info.processDllsReferencedByImportLibs(std::move(dllsReferencedByImportLibs)); !dllIssues.empty()) { std::unique_lock submitWarningLock(submitWarningMutex); diff --git a/librepomgr/webclient/database.cpp b/librepomgr/webclient/database.cpp index d4da03f..a8bc1ce 100644 --- a/librepomgr/webclient/database.cpp +++ b/librepomgr/webclient/database.cpp @@ -153,10 +153,6 @@ void queryDatabases(LogContext &log, ServiceSetup &setup, std::vectorreplacePackages(packages, lastModified); + auto updater = LibPkg::PackageUpdater(*db, true); + updater.insertFromDatabaseFile(session2.destinationFilePath); + updater.commit(); + db->lastUpdate = lastModified; } catch (const std::runtime_error &e) { log(Phrases::ErrorMessage, "Unable to parse retrieved database file for \"", dbName, '@', dbArch, "\": ", e.what(), '\n'); dbQuerySession->addResponse(std::move(dbName));