Limit results returned by the API for better scalability

This commit is contained in:
Martchus 2022-02-25 00:29:43 +01:00
parent ff7f039519
commit 90ff9678fe
9 changed files with 117 additions and 48 deletions

2
3rdparty/lmdb-safe vendored

@ -1 +1 @@
Subproject commit bf6dbf0e42c081c7b75bea9bb59ffbd0c0d6b529 Subproject commit f6fd78155b0a4fd229b1b352fe87efed2460d982

View File

@ -97,7 +97,8 @@ Database *Config::findOrCreateDatabaseFromDenotation(std::string_view databaseDe
/*! /*!
* \brief Returns all packages with the specified database name, database architecture and package name. * \brief Returns all packages with the specified database name, database architecture and package name.
*/ */
std::vector<PackageSearchResult> Config::findPackages(std::tuple<std::string_view, std::string_view, std::string_view> dbAndPackageName) std::vector<PackageSearchResult> Config::findPackages(
std::tuple<std::string_view, std::string_view, std::string_view> dbAndPackageName, std::size_t limit)
{ {
auto pkgs = std::vector<PackageSearchResult>(); auto pkgs = std::vector<PackageSearchResult>();
const auto &[dbName, dbArch, packageName] = dbAndPackageName; const auto &[dbName, dbArch, packageName] = dbAndPackageName;
@ -115,6 +116,9 @@ std::vector<PackageSearchResult> Config::findPackages(std::tuple<std::string_vie
if (const auto [id, package] = db.findPackageWithID(name); package) { if (const auto [id, package] = db.findPackageWithID(name); package) {
pkgs.emplace_back(db, package, id); pkgs.emplace_back(db, package, id);
} }
if (pkgs.size() >= limit) {
return pkgs;
}
} }
return pkgs; return pkgs;
} }
@ -146,7 +150,7 @@ PackageSearchResult Config::findPackage(const Dependency &dependency)
/*! /*!
* \brief Returns all packages satisfying \a dependency or - if \a reverse is true - all packages requiring \a dependency. * \brief Returns all packages satisfying \a dependency or - if \a reverse is true - all packages requiring \a dependency.
*/ */
std::vector<PackageSearchResult> Config::findPackages(const Dependency &dependency, bool reverse) std::vector<PackageSearchResult> Config::findPackages(const Dependency &dependency, bool reverse, std::size_t limit)
{ {
auto results = std::vector<PackageSearchResult>(); auto results = std::vector<PackageSearchResult>();
for (auto &db : databases) { for (auto &db : databases) {
@ -155,7 +159,7 @@ std::vector<PackageSearchResult> Config::findPackages(const Dependency &dependen
if (visited.emplace(packageID).second) { if (visited.emplace(packageID).second) {
results.emplace_back(db, package, packageID); results.emplace_back(db, package, packageID);
} }
return false; return results.size() >= limit;
}); });
} }
return results; return results;
@ -164,7 +168,7 @@ std::vector<PackageSearchResult> Config::findPackages(const Dependency &dependen
/*! /*!
* \brief Returns all packages providing \a library or - if \a reverse is true - all packages requiring \a library. * \brief Returns all packages providing \a library or - if \a reverse is true - all packages requiring \a library.
*/ */
std::vector<PackageSearchResult> Config::findPackagesProvidingLibrary(const std::string &library, bool reverse) std::vector<PackageSearchResult> Config::findPackagesProvidingLibrary(const std::string &library, bool reverse, std::size_t limit)
{ {
auto results = std::vector<PackageSearchResult>(); auto results = std::vector<PackageSearchResult>();
auto visited = std::unordered_set<StorageID>(); auto visited = std::unordered_set<StorageID>();
@ -173,7 +177,7 @@ std::vector<PackageSearchResult> Config::findPackagesProvidingLibrary(const std:
if (visited.emplace(packageID).second) { if (visited.emplace(packageID).second) {
results.emplace_back(db, package, packageID); results.emplace_back(db, package, packageID);
} }
return false; return results.size() >= limit;
}); });
} }
return results; return results;
@ -182,7 +186,7 @@ std::vector<PackageSearchResult> Config::findPackagesProvidingLibrary(const std:
/*! /*!
* \brief Returns all packages which names matches \a regex. * \brief Returns all packages which names matches \a regex.
*/ */
std::vector<PackageSearchResult> Config::findPackages(const std::regex &regex) std::vector<PackageSearchResult> Config::findPackages(const std::regex &regex, std::size_t limit)
{ {
auto pkgs = std::vector<PackageSearchResult>(); auto pkgs = std::vector<PackageSearchResult>();
for (auto &db : databases) { for (auto &db : databases) {
@ -191,13 +195,14 @@ std::vector<PackageSearchResult> Config::findPackages(const std::regex &regex)
auto [packageID, package] = getPackage(); auto [packageID, package] = getPackage();
pkgs.emplace_back(db, package, packageID); pkgs.emplace_back(db, package, packageID);
} }
return false; return pkgs.size() >= limit;
}); });
} }
return pkgs; return pkgs;
} }
std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(const Database &)> &databasePred, std::string_view term) std::vector<PackageSearchResult> Config::findPackages(
const std::function<bool(const Database &)> &databasePred, std::string_view term, std::size_t limit)
{ {
auto pkgs = std::vector<PackageSearchResult>(); auto pkgs = std::vector<PackageSearchResult>();
for (auto &db : databases) { for (auto &db : databases) {
@ -209,7 +214,7 @@ std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(c
const auto [packageID, package] = getPackage(); const auto [packageID, package] = getPackage();
pkgs.emplace_back(db, package, packageID); pkgs.emplace_back(db, package, packageID);
} }
return false; return pkgs.size() >= limit;
}); });
} }
return pkgs; return pkgs;
@ -219,13 +224,16 @@ std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(c
* \brief Returns all packages considered "the same" as \a package. * \brief Returns all packages considered "the same" as \a package.
* \remarks See Package::isSame(). * \remarks See Package::isSame().
*/ */
std::vector<PackageSearchResult> Config::findPackages(const Package &package) std::vector<PackageSearchResult> Config::findPackages(const Package &package, std::size_t limit)
{ {
auto pkgs = std::vector<PackageSearchResult>(); auto pkgs = std::vector<PackageSearchResult>();
for (auto &db : databases) { for (auto &db : databases) {
if (const auto [id, pkg] = db.findPackageWithID(package.name); pkg && pkg->isSame(package)) { if (const auto [id, pkg] = db.findPackageWithID(package.name); pkg && pkg->isSame(package)) {
pkgs.emplace_back(db, pkg, id); pkgs.emplace_back(db, pkg, id);
} }
if (pkgs.size() >= limit) {
return pkgs;
}
} }
return pkgs; return pkgs;
} }
@ -233,8 +241,8 @@ std::vector<PackageSearchResult> Config::findPackages(const Package &package)
/*! /*!
* \brief Returns all packages \a packagePred returns true for from all databases \a databasePred returns true for. * \brief Returns all packages \a packagePred returns true for from all databases \a databasePred returns true for.
*/ */
std::vector<PackageSearchResult> Config::findPackages( std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(const Database &)> &databasePred,
const std::function<bool(const Database &)> &databasePred, const std::function<bool(const Database &, const Package &)> &packagePred) const std::function<bool(const Database &, const Package &)> &packagePred, std::size_t limit)
{ {
auto pkgs = std::vector<PackageSearchResult>(); auto pkgs = std::vector<PackageSearchResult>();
for (auto &db : databases) { for (auto &db : databases) {
@ -245,7 +253,7 @@ std::vector<PackageSearchResult> Config::findPackages(
if (packagePred(db, *package)) { if (packagePred(db, *package)) {
pkgs.emplace_back(db, std::move(package), packageID); pkgs.emplace_back(db, std::move(package), packageID);
} }
return false; return pkgs.size() >= limit;
}); });
} }
return pkgs; return pkgs;
@ -254,7 +262,7 @@ std::vector<PackageSearchResult> Config::findPackages(
/*! /*!
* \brief Returns all packages \a pred returns true for. * \brief Returns all packages \a pred returns true for.
*/ */
std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(const Database &, const Package &)> &pred) std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(const Database &, const Package &)> &pred, std::size_t limit)
{ {
auto pkgs = std::vector<PackageSearchResult>(); auto pkgs = std::vector<PackageSearchResult>();
for (auto &db : databases) { for (auto &db : databases) {
@ -262,7 +270,7 @@ std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(c
if (pred(db, *package)) { if (pred(db, *package)) {
pkgs.emplace_back(db, std::move(package), packageID); pkgs.emplace_back(db, std::move(package), packageID);
} }
return false; return pkgs.size() >= limit;
}); });
} }
return pkgs; return pkgs;

View File

@ -140,18 +140,24 @@ struct LIBPKG_EXPORT Config : public Lockable, public ReflectiveRapidJSON::Binar
Database *findOrCreateDatabase(std::string_view name, std::string_view architecture); Database *findOrCreateDatabase(std::string_view name, std::string_view architecture);
Database *findOrCreateDatabaseFromDenotation(std::string_view databaseDenotation); Database *findOrCreateDatabaseFromDenotation(std::string_view databaseDenotation);
static std::tuple<std::string_view, std::string_view, std::string_view> parsePackageDenotation(std::string_view packageDenotation); static std::tuple<std::string_view, std::string_view, std::string_view> parsePackageDenotation(std::string_view packageDenotation);
std::vector<PackageSearchResult> findPackages(std::string_view packageDenotation); std::vector<PackageSearchResult> findPackages(std::string_view packageDenotation, std::size_t limit = std::numeric_limits<std::size_t>::max());
std::vector<PackageSearchResult> findPackages(std::string_view dbName, std::string_view dbArch, std::string_view packageName);
std::vector<PackageSearchResult> findPackages(std::tuple<std::string_view, std::string_view, std::string_view> dbAndPackageName);
PackageSearchResult findPackage(const Dependency &dependency);
std::vector<PackageSearchResult> findPackages(const Dependency &dependency, bool reverse = false);
std::vector<PackageSearchResult> findPackagesProvidingLibrary(const std::string &library, bool reverse = false);
std::vector<PackageSearchResult> findPackages(const std::regex &regex);
std::vector<PackageSearchResult> findPackages(const std::function<bool(const Database &)> &databasePred, std::string_view term);
std::vector<PackageSearchResult> findPackages(const Package &package);
std::vector<PackageSearchResult> findPackages( std::vector<PackageSearchResult> findPackages(
const std::function<bool(const Database &)> &databasePred, const std::function<bool(const Database &, const Package &)> &packagePred); std::string_view dbName, std::string_view dbArch, std::string_view packageName, std::size_t limit = std::numeric_limits<std::size_t>::max());
std::vector<PackageSearchResult> findPackages(const std::function<bool(const Database &, const Package &)> &pred); std::vector<PackageSearchResult> findPackages(std::tuple<std::string_view, std::string_view, std::string_view> dbAndPackageName,
std::size_t limit = std::numeric_limits<std::size_t>::max());
PackageSearchResult findPackage(const Dependency &dependency);
std::vector<PackageSearchResult> findPackages(
const Dependency &dependency, bool reverse = false, std::size_t limit = std::numeric_limits<std::size_t>::max());
std::vector<PackageSearchResult> findPackagesProvidingLibrary(
const std::string &library, bool reverse = false, std::size_t limit = std::numeric_limits<std::size_t>::max());
std::vector<PackageSearchResult> findPackages(const std::regex &regex, std::size_t limit = std::numeric_limits<std::size_t>::max());
std::vector<PackageSearchResult> findPackages(const std::function<bool(const Database &)> &databasePred, std::string_view term,
std::size_t limit = std::numeric_limits<std::size_t>::max());
std::vector<PackageSearchResult> findPackages(const Package &package, std::size_t limit = std::numeric_limits<std::size_t>::max());
std::vector<PackageSearchResult> findPackages(const std::function<bool(const Database &)> &databasePred,
const std::function<bool(const Database &, const Package &)> &packagePred, std::size_t limit = std::numeric_limits<std::size_t>::max());
std::vector<PackageSearchResult> findPackages(
const std::function<bool(const Database &, const Package &)> &pred, std::size_t limit = std::numeric_limits<std::size_t>::max());
std::vector<Database> databases; std::vector<Database> databases;
Database aur = Database("aur"); Database aur = Database("aur");
@ -181,14 +187,15 @@ inline Status Config::computeStatus() const
return Status(*this); return Status(*this);
} }
inline std::vector<PackageSearchResult> Config::findPackages(std::string_view dbName, std::string_view dbArch, std::string_view packageName) inline std::vector<PackageSearchResult> Config::findPackages(
std::string_view dbName, std::string_view dbArch, std::string_view packageName, std::size_t limit)
{ {
return findPackages(std::make_tuple(dbName, dbArch, packageName)); return findPackages(std::make_tuple(dbName, dbArch, packageName), limit);
} }
inline std::vector<PackageSearchResult> Config::findPackages(std::string_view packageDenotation) inline std::vector<PackageSearchResult> Config::findPackages(std::string_view packageDenotation, std::size_t limit)
{ {
return findPackages(parsePackageDenotation(packageDenotation)); return findPackages(parsePackageDenotation(packageDenotation), limit);
} }
} // namespace LibPkg } // namespace LibPkg

View File

@ -39,7 +39,7 @@ inline std::optional<std::string_view> getLastValueSv(const std::multimap<std::s
return std::nullopt; return std::nullopt;
} }
template <typename TargetType, Traits::DisableIf<std::is_integral<TargetType>> * = nullptr> template <typename TargetType, Traits::DisableIfAny<std::is_integral<TargetType>, Traits::IsSpecializationOf<TargetType, std::atomic>> * = nullptr>
void convertValue(const std::multimap<std::string, std::string> &multimap, const std::string &key, TargetType &result); void convertValue(const std::multimap<std::string, std::string> &multimap, const std::string &key, TargetType &result);
template <> template <>
@ -60,7 +60,7 @@ inline void convertValue(const std::multimap<std::string, std::string> &multimap
} }
} }
template <typename TargetType, Traits::EnableIf<std::is_integral<TargetType>> * = nullptr> template <typename TargetType, Traits::EnableIfAny<std::is_integral<TargetType>, Traits::IsSpecializationOf<TargetType, std::atomic>> * = nullptr>
inline void convertValue(const std::multimap<std::string, std::string> &multimap, const std::string &key, TargetType &result) inline void convertValue(const std::multimap<std::string, std::string> &multimap, const std::string &key, TargetType &result)
{ {
using namespace std; using namespace std;
@ -69,7 +69,11 @@ inline void convertValue(const std::multimap<std::string, std::string> &multimap
if (const char *const value = getLastValue(multimap, key)) { if (const char *const value = getLastValue(multimap, key)) {
try { try {
result = stringToNumber<TargetType>(value); if constexpr (Traits::IsSpecializationOf<TargetType, std::atomic>::value) {
result = stringToNumber<typename TargetType::value_type>(value);
} else {
result = stringToNumber<TargetType>(value);
}
} catch (const ConversionException &) { } catch (const ConversionException &) {
cerr << Phrases::ErrorMessage << "Specified number \"" << value << "\" for key \"" << key << "\" is invalid." << Phrases::End; cerr << Phrases::ErrorMessage << "Specified number \"" << value << "\" for key \"" << key << "\" is invalid." << Phrases::End;
return; return;

View File

@ -90,6 +90,8 @@ void ServiceSetup::WebServerSetup::applyConfig(const std::multimap<std::string,
convertValue(multimap, "port", port); convertValue(multimap, "port", port);
convertValue(multimap, "threads", threadCount); convertValue(multimap, "threads", threadCount);
convertValue(multimap, "static_files", staticFilesPath); convertValue(multimap, "static_files", staticFilesPath);
convertValue(multimap, "package_search_response_limit", packageSearchResponseLimit);
convertValue(multimap, "build_actions_response_limit", buildActionsResponseLimit);
convertValue(multimap, "verify_ssl_certificates", verifySslCertificates); convertValue(multimap, "verify_ssl_certificates", verifySslCertificates);
convertValue(multimap, "log_ssl_certificate_validation", logSslCertificateValidation); convertValue(multimap, "log_ssl_certificate_validation", logSslCertificateValidation);
@ -338,11 +340,16 @@ std::size_t ServiceSetup::BuildSetup::buildActionCount()
} }
void ServiceSetup::BuildSetup::forEachBuildAction( void ServiceSetup::BuildSetup::forEachBuildAction(
std::function<void(std::size_t)> count, std::function<bool(LibPkg::StorageID, BuildAction &&)> &&func) std::function<void(std::size_t)> count, std::function<bool(LibPkg::StorageID, BuildAction &&)> &&func, std::size_t limit, std::size_t start)
{ {
auto txn = m_storage->buildActions.getROTransaction(); auto txn = m_storage->buildActions.getROTransaction();
count(txn.size()); const auto total = txn.size();
for (auto i = txn.begin(); i != txn.end(); ++i) { count(std::min(limit, total));
const auto reverse = start == std::numeric_limits<std::size_t>::max();
for (auto i = reverse ? txn.rbegin()
: txn.lower_bound(static_cast<LibPkg::StorageID>(
start > std::numeric_limits<LibPkg::StorageID>::max() ? std::numeric_limits<LibPkg::StorageID>::max() : start));
i != txn.end() && limit; reverse ? --i : ++i, --limit) {
if (func(i.getID(), std::move(i.value()))) { if (func(i.getID(), std::move(i.value()))) {
return; return;
} }

View File

@ -68,6 +68,8 @@ struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable {
unsigned short threadCount = 1; unsigned short threadCount = 1;
boost::asio::io_context ioContext; boost::asio::io_context ioContext;
boost::asio::ssl::context sslContext{ boost::asio::ssl::context::sslv23_client }; boost::asio::ssl::context sslContext{ boost::asio::ssl::context::sslv23_client };
std::atomic_size_t packageSearchResponseLimit = 20000; // sufficient to return a "full architecture"
std::atomic_size_t buildActionsResponseLimit = 200;
bool verifySslCertificates = true; bool verifySslCertificates = true;
bool logSslCertificateValidation = false; bool logSslCertificateValidation = false;
@ -138,7 +140,8 @@ struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable {
void deleteBuildAction(const std::vector<std::shared_ptr<BuildAction>> &actions); void deleteBuildAction(const std::vector<std::shared_ptr<BuildAction>> &actions);
std::size_t buildActionCount(); std::size_t buildActionCount();
std::size_t runningBuildActionCount(); std::size_t runningBuildActionCount();
void forEachBuildAction(std::function<void(std::size_t)> count, std::function<bool(LibPkg::StorageID, BuildAction &&)> &&func); void forEachBuildAction(std::function<void(std::size_t)> count, std::function<bool(LibPkg::StorageID, BuildAction &&)> &&func,
std::size_t limit, std::size_t start);
void forEachBuildAction(std::function<bool(LibPkg::StorageID, BuildAction &, bool &)> &&func); void forEachBuildAction(std::function<bool(LibPkg::StorageID, BuildAction &, bool &)> &&func);
std::vector<std::shared_ptr<BuildAction>> followUpBuildActions(BuildActionIdType forId); std::vector<std::shared_ptr<BuildAction>> followUpBuildActions(BuildActionIdType forId);

View File

@ -6,6 +6,9 @@
#include "./session.h" #include "./session.h"
#include "./typedefs.h" #include "./typedefs.h"
#include <c++utilities/conversion/stringbuilder.h>
#include <c++utilities/conversion/stringconversion.h>
#include <unordered_map> #include <unordered_map>
namespace std { namespace std {
@ -51,10 +54,28 @@ struct LIBREPOMGR_EXPORT Url {
bool hasPrettyFlag() const; bool hasPrettyFlag() const;
std::string_view value(std::string_view paramName) const; std::string_view value(std::string_view paramName) const;
std::vector<std::string> decodeValues(std::string_view paramName) const; std::vector<std::string> decodeValues(std::string_view paramName) const;
template <typename Number> Number asNumber(std::string_view paramName, Number def = Number()) const;
static std::string decodeValue(std::string_view value); static std::string decodeValue(std::string_view value);
static std::string encodeValue(std::string_view value); static std::string encodeValue(std::string_view value);
}; };
template <typename Number> Number Url::asNumber(std::string_view paramName, Number def) const
{
using namespace CppUtilities;
const auto values = decodeValues(paramName);
if (values.size() > 1) {
throw BadRequest("more than one " % paramName + " specified");
}
if (!values.empty()) {
try {
return stringToNumber<Number>(values.front());
} catch (const ConversionException &) {
throw BadRequest(argsToString(paramName, " must be an integer"));
}
}
return def;
}
inline bool Url::hasPrettyFlag() const inline bool Url::hasPrettyFlag() const
{ {
return hasFlag("pretty"); return hasFlag("pretty");

View File

@ -150,7 +150,7 @@ void getUnresolved(const Params &params, ResponseHandler &&handler)
void getPackages(const Params &params, ResponseHandler &&handler) void getPackages(const Params &params, ResponseHandler &&handler)
{ {
// read mode // read mode
const auto modes(params.target.decodeValues("mode")); const auto modes = params.target.decodeValues("mode");
if (modes.size() > 1) { if (modes.size() > 1) {
throw BadRequest("more than one mode specified"); throw BadRequest("more than one mode specified");
} }
@ -181,6 +181,13 @@ void getPackages(const Params &params, ResponseHandler &&handler)
mode = modeIterator->second; mode = modeIterator->second;
} }
// limit
auto limit = params.target.asNumber<std::size_t>("limit");
const auto serverLimit = params.setup.webServer.packageSearchResponseLimit.load();
if (!limit || limit > serverLimit) {
limit = serverLimit;
}
// check for details flag // check for details flag
const auto details = params.target.hasFlag("details"); const auto details = params.target.hasFlag("details");
if (details && mode != Mode::Name) { if (details && mode != Mode::Name) {
@ -214,7 +221,8 @@ void getPackages(const Params &params, ResponseHandler &&handler)
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kArrayType); RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kArrayType);
RAPIDJSON_NAMESPACE::Document::Array array(document.GetArray()); RAPIDJSON_NAMESPACE::Document::Array array(document.GetArray());
const auto pushPackages = [&dbs, &document, &array](auto &&packages) { const auto pushPackages = [&dbs, &document, &array, &limit](auto &&packages) {
limit -= packages.size();
for (const auto &package : packages) { for (const auto &package : packages) {
if (!dbs.empty()) { if (!dbs.empty()) {
const auto *const db = std::get<Database *>(package.db); const auto *const db = std::get<Database *>(package.db);
@ -248,15 +256,17 @@ void getPackages(const Params &params, ResponseHandler &&handler)
} else { } else {
neededAurPackages.emplace_back(std::move(packageNameStr)); neededAurPackages.emplace_back(std::move(packageNameStr));
} }
--limit;
} }
if (!isDbAur && (!dbs.empty() || !onlyFromAur)) { if (!isDbAur && (!dbs.empty() || !onlyFromAur)) {
auto packages = params.setup.config.findPackages(packageDenotation); auto packages = params.setup.config.findPackages(packageDenotation, limit);
if (details) { if (details) {
for (const auto &package : packages) { for (const auto &package : packages) {
if (dbs.empty() || dbs.find(std::get<LibPkg::Database *>(package.db)->name) != dbs.end()) { if (dbs.empty() || dbs.find(std::get<LibPkg::Database *>(package.db)->name) != dbs.end()) {
ReflectiveRapidJSON::JsonReflector::push(package.pkg, array, document.GetAllocator()); ReflectiveRapidJSON::JsonReflector::push(package.pkg, array, document.GetAllocator());
} }
} }
limit -= packages.size();
} else { } else {
pushPackages(std::move(packages)); pushPackages(std::move(packages));
} }
@ -265,7 +275,8 @@ void getPackages(const Params &params, ResponseHandler &&handler)
} }
case Mode::NameContains: case Mode::NameContains:
pushPackages(params.setup.config.findPackages( pushPackages(params.setup.config.findPackages(
[&dbs, onlyFromAur](const LibPkg::Database &db) { return (dbs.empty() && !onlyFromAur) || dbs.find(db.name) != dbs.end(); }, name)); [&dbs, onlyFromAur](const LibPkg::Database &db) { return (dbs.empty() && !onlyFromAur) || dbs.find(db.name) != dbs.end(); }, name,
limit));
if (fromAur && !name.empty()) { if (fromAur && !name.empty()) {
neededAurPackages.emplace_back(std::move(name)); neededAurPackages.emplace_back(std::move(name));
} }
@ -273,7 +284,7 @@ void getPackages(const Params &params, ResponseHandler &&handler)
case Mode::Regex: case Mode::Regex:
// assume names are regexes // assume names are regexes
try { try {
pushPackages(params.setup.config.findPackages(std::regex(name.data(), name.size()))); pushPackages(params.setup.config.findPackages(std::regex(name.data(), name.size()), limit));
} catch (const std::regex_error &e) { } catch (const std::regex_error &e) {
throw BadRequest(argsToString("regex is invalid: ", e.what())); throw BadRequest(argsToString("regex is invalid: ", e.what()));
} }
@ -281,12 +292,12 @@ void getPackages(const Params &params, ResponseHandler &&handler)
case Mode::Provides: case Mode::Provides:
case Mode::Depends: case Mode::Depends:
// assume names are dependency notation // assume names are dependency notation
pushPackages(params.setup.config.findPackages(Dependency::fromString(name), mode == Mode::Depends)); pushPackages(params.setup.config.findPackages(Dependency::fromString(name), mode == Mode::Depends, limit));
break; break;
case Mode::LibProvides: case Mode::LibProvides:
case Mode::LibDepends: case Mode::LibDepends:
// assume names are "normalized" library names with platform prefix // assume names are "normalized" library names with platform prefix
pushPackages(params.setup.config.findPackagesProvidingLibrary(name, mode == Mode::LibDepends)); pushPackages(params.setup.config.findPackagesProvidingLibrary(name, mode == Mode::LibDepends, limit));
break; break;
default:; default:;
} }

View File

@ -23,13 +23,21 @@ void getBuildActions(const Params &params, ResponseHandler &&handler)
RAPIDJSON_NAMESPACE::Document jsonDoc(RAPIDJSON_NAMESPACE::kArrayType); RAPIDJSON_NAMESPACE::Document jsonDoc(RAPIDJSON_NAMESPACE::kArrayType);
RAPIDJSON_NAMESPACE::Value::Array array(jsonDoc.GetArray()); RAPIDJSON_NAMESPACE::Value::Array array(jsonDoc.GetArray());
const auto start = params.target.asNumber<std::size_t>("start", std::numeric_limits<std::size_t>::max());
const auto serverLimit = params.setup.webServer.buildActionsResponseLimit.load();
auto limit = params.target.asNumber<std::size_t>("limit");
if (!limit || limit > serverLimit) {
limit = serverLimit;
}
auto buildActionLock = params.setup.building.lockToRead(); auto buildActionLock = params.setup.building.lockToRead();
params.setup.building.forEachBuildAction( params.setup.building.forEachBuildAction(
[&array, &jsonDoc](std::size_t count) { array.Reserve(ReflectiveRapidJSON::JsonReflector::rapidJsonSize(count), jsonDoc.GetAllocator()); }, [&array, &jsonDoc](std::size_t count) { array.Reserve(ReflectiveRapidJSON::JsonReflector::rapidJsonSize(count), jsonDoc.GetAllocator()); },
[&array, &jsonDoc](LibPkg::StorageID, BuildAction &&buildAction) { [&array, &jsonDoc, limit](LibPkg::StorageID, BuildAction &&buildAction) {
ReflectiveRapidJSON::JsonReflector::push(BuildActionBasicInfo(buildAction), array, jsonDoc.GetAllocator()); ReflectiveRapidJSON::JsonReflector::push(BuildActionBasicInfo(buildAction), array, jsonDoc.GetAllocator());
return false; return array.Size() >= limit;
}); },
limit, start);
buildActionLock.unlock(); buildActionLock.unlock();
handler(makeJson(params.request(), jsonDoc, params.target.hasPrettyFlag())); handler(makeJson(params.request(), jsonDoc, params.target.hasPrettyFlag()));