added mutex/locker for repositories

This commit is contained in:
Martchus 2015-11-03 18:19:24 +01:00
parent d341229f41
commit 5f95fd790a
8 changed files with 80 additions and 40 deletions

View File

@ -572,10 +572,14 @@ const QJsonObject &Manager::basicRepoInfo() const
QMutexLocker locker(&m_basicRepoInfoMutex); QMutexLocker locker(&m_basicRepoInfoMutex);
if(m_basicRepoInfo.isEmpty()) { if(m_basicRepoInfo.isEmpty()) {
// add local data base // add local data base
{
QReadLocker locker(localDataBase()->lock());
m_basicRepoInfo.insert(localDataBase()->name(), localDataBase()->basicInfo()); m_basicRepoInfo.insert(localDataBase()->name(), localDataBase()->basicInfo());
}
// add sync data bases // add sync data bases
for(const auto &syncDb : syncDatabases()) { for(const auto &syncDb : syncDatabases()) {
// check if the "sync" database is actually used for syncing // check if the "sync" database is actually used for syncing
QReadLocker locker(syncDb.second->lock());
auto usage = syncDb.second->usage(); auto usage = syncDb.second->usage();
if((usage & ALPM_DB_USAGE_SYNC) || (usage & ALPM_DB_USAGE_INSTALL) || (usage & ALPM_DB_USAGE_UPGRADE)) { if((usage & ALPM_DB_USAGE_SYNC) || (usage & ALPM_DB_USAGE_INSTALL) || (usage & ALPM_DB_USAGE_UPGRADE)) {
m_basicRepoInfo.insert(syncDb.first, syncDb.second->basicInfo()); m_basicRepoInfo.insert(syncDb.first, syncDb.second->basicInfo());
@ -585,6 +589,7 @@ const QJsonObject &Manager::basicRepoInfo() const
} }
// add AUR // add AUR
if(userRepository()) { if(userRepository()) {
QReadLocker locker(userRepository()->lock());
m_basicRepoInfo.insert(userRepository()->name(), userRepository()->basicInfo()); m_basicRepoInfo.insert(userRepository()->name(), userRepository()->basicInfo());
} }
} }

View File

@ -37,6 +37,7 @@ PackageInfoLookup::PackageInfoLookup(Manager &manager, const QJsonObject &reques
} }
} }
if(!packagesToBeRequested.isEmpty()) { if(!packagesToBeRequested.isEmpty()) {
QReadLocker locker(repo->lock());
if(const auto *reply = (m_part & Manager::Details ? repo->requestFullPackageInfo(packagesToBeRequested) : repo->requestPackageInfo(packagesToBeRequested))) { if(const auto *reply = (m_part & Manager::Details ? repo->requestFullPackageInfo(packagesToBeRequested) : repo->requestPackageInfo(packagesToBeRequested))) {
connect(reply, &PackageReply::resultsAvailable, this, &PackageInfoLookup::addResultsFromReply); connect(reply, &PackageReply::resultsAvailable, this, &PackageInfoLookup::addResultsFromReply);
++m_remainingReplies; ++m_remainingReplies;
@ -69,7 +70,7 @@ void PackageInfoLookup::addResultsDirectly(const QStringList &packageNames, cons
} }
bool avail = false; bool avail = false;
try { try {
if(const auto &pkg = packages.at(packageName)) { if(const auto *pkg = packages.at(packageName)) {
avail = true; avail = true;
if(m_part & Manager::Basics) { if(m_part & Manager::Basics) {
res.insert(QStringLiteral("basics"), pkg->basicInfo()); res.insert(QStringLiteral("basics"), pkg->basicInfo());
@ -93,22 +94,22 @@ void PackageInfoLookup::addResultsFromReply()
auto *reply = static_cast<PackageReply *>(sender()); auto *reply = static_cast<PackageReply *>(sender());
reply->deleteLater(); reply->deleteLater();
if(reply->error().isEmpty()) { if(reply->error().isEmpty()) {
QReadLocker lock(reply->repository()->lock());
addResultsDirectly(reply->requestedPackages(), reply->repository()); addResultsDirectly(reply->requestedPackages(), reply->repository());
if(!--m_remainingReplies) {
emit resultsAvailable(m_what, m_id, m_results);
deleteLater();
}
} else { } else {
// TODO: report error // TODO: bunch error messages together
/*
for(const auto &packageName : packageNames) { for(const auto &packageName : packageNames) {
QJsonObject res; QJsonObject res;
res.insert(QStringLiteral("name"), packageName); res.insert(QStringLiteral("name"), packageName);
res.insert(QStringLiteral("repo"), repo->name()); res.insert(QStringLiteral("repo"), repo->name());
res.insert(QStringLiteral("error"), reply->error());
m_results << res;
} }
*/
} }
if(!--m_remainingReplies) {
emit resultsAvailable(m_what, m_id, m_results);
deleteLater();
}
} }
} // namespace RepoIndex } // namespace RepoIndex

View File

@ -78,7 +78,8 @@ Repository::Repository(const QString &name, uint32 index, QObject *parent) :
m_index(index), m_index(index),
m_name(name), m_name(name),
m_usage(static_cast<alpm_db_usage_t>(0)), m_usage(static_cast<alpm_db_usage_t>(0)),
m_sigLevel(static_cast<alpm_siglevel_t>(ALPM_SIGSTATUS_INVALID)) m_sigLevel(static_cast<alpm_siglevel_t>(ALPM_SIGSTATUS_INVALID)),
m_lock(QReadWriteLock::Recursive)
{} {}
/*! /*!

View File

@ -7,6 +7,7 @@
#include <QObject> #include <QObject>
#include <QFuture> #include <QFuture>
#include <QJsonObject> #include <QJsonObject>
#include <QReadWriteLock>
#include <memory> #include <memory>
#include <functional> #include <functional>
@ -82,6 +83,7 @@ class SuggestionsReply : public Reply
Q_OBJECT Q_OBJECT
public: public:
SuggestionsReply(QNetworkReply *networkReply, const QString &term, Repository *repo); SuggestionsReply(QNetworkReply *networkReply, const QString &term, Repository *repo);
const Repository *repository() const;
QJsonObject suggestions() const; QJsonObject suggestions() const;
protected: protected:
@ -95,6 +97,11 @@ inline SuggestionsReply::SuggestionsReply(QNetworkReply *networkReply, const QSt
m_repo(repo) m_repo(repo)
{} {}
inline const Repository *SuggestionsReply::repository() const
{
return m_repo;
}
/*! /*!
* \brief The RepositoryType enum specifies the type of a repository object. * \brief The RepositoryType enum specifies the type of a repository object.
*/ */
@ -198,6 +205,9 @@ public:
// parsing src/pkg info // parsing src/pkg info
QList<Package *> addPackagesFromSrcInfo(const QByteArray &srcInfo); QList<Package *> addPackagesFromSrcInfo(const QByteArray &srcInfo);
// thread synchronization
QReadWriteLock *lock() const;
static const uint32 invalidIndex = static_cast<uint32>(-1); static const uint32 invalidIndex = static_cast<uint32>(-1);
protected: protected:
@ -215,6 +225,9 @@ protected:
QList<Repository *> m_upgradeSources; QList<Repository *> m_upgradeSources;
QString m_srcDir; QString m_srcDir;
QString m_pkgDir; QString m_pkgDir;
private:
QReadWriteLock m_lock;
}; };
/*! /*!
@ -401,6 +414,11 @@ inline bool Repository::isCachingUseful() const
} }
} }
inline QReadWriteLock *Repository::lock() const
{
return const_cast<QReadWriteLock *>(&m_lock);
}
} // namespace PackageManagement } // namespace PackageManagement
#endif // PACKAGEMANAGEMENT_PACKAGESOURCE_H #endif // PACKAGEMANAGEMENT_PACKAGESOURCE_H

View File

@ -154,8 +154,11 @@ QStringList BuildOrderResolver::resolve(const StringVector &packages) const
tasks << new TaskInfo(QString::fromLocal8Bit(pkgName.data())); tasks << new TaskInfo(QString::fromLocal8Bit(pkgName.data()));
} }
// find specified packages and their dependencies // find specified packages and their dependencies
for(int i = 0, size = tasks.size(); i != size; ++i) { //for(int i = 0, size = tasks.size(); i != size; ++i) {
addDeps(tasks, tasks.at(i)); // addDeps(tasks, tasks.at(i));
//}
for(auto *task : tasks) {
addDeps(tasks, task);
} }
if(m_manager.config().isVerbose()) { if(m_manager.config().isVerbose()) {
cerr << shchar << "Relevant packages: "; cerr << shchar << "Relevant packages: ";

View File

@ -24,13 +24,13 @@ SuggestionsLookup::SuggestionsLookup(Manager &manager, const QJsonObject &reques
if(m_errors.isEmpty()) { if(m_errors.isEmpty()) {
for(const auto &repoName : repos) { for(const auto &repoName : repos) {
if(auto *repo = manager.repositoryByName(repoName.toString())) { if(auto *repo = manager.repositoryByName(repoName.toString())) {
QReadLocker locker(repo->lock());
if(const auto *reply = repo->requestSuggestions(searchTerm)) { if(const auto *reply = repo->requestSuggestions(searchTerm)) {
connect(reply, &SuggestionsReply::resultsAvailable, this, &SuggestionsLookup::addResults); connect(reply, &SuggestionsReply::resultsAvailable, this, &SuggestionsLookup::addResults);
++m_remainingReplies; ++m_remainingReplies;
} else { } else {
m_results << repo->suggestions(searchTerm); m_results << repo->suggestions(searchTerm);
} }
} else { } else {
m_errors << QStringLiteral("The specified repository \"%1\" does not exist.").arg(repoName.toString()); m_errors << QStringLiteral("The specified repository \"%1\" does not exist.").arg(repoName.toString());
} }
@ -44,7 +44,10 @@ void SuggestionsLookup::addResults()
{ {
assert(m_remainingReplies); assert(m_remainingReplies);
auto *reply = static_cast<SuggestionsReply *>(sender()); auto *reply = static_cast<SuggestionsReply *>(sender());
{
QReadLocker locker(reply->repository()->lock());
m_results << reply->suggestions(); m_results << reply->suggestions();
}
reply->deleteLater(); reply->deleteLater();
if(!--m_remainingReplies) { if(!--m_remainingReplies) {
emit resultsAvailable(QStringLiteral("suggestions"), m_id, m_results); emit resultsAvailable(QStringLiteral("suggestions"), m_id, m_results);

View File

@ -42,6 +42,7 @@ QJsonObject UpgradeResult::toJson() const
/*! /*!
* \brief Constructs a new upgrade lookup process. The upgrade lookup process is started immediately. * \brief Constructs a new upgrade lookup process. The upgrade lookup process is started immediately.
* \remarks \a upgradeLookup and \a upgradeSource musted be locked by caller
*/ */
UpgradeLookupProcess::UpgradeLookupProcess(UpgradeLookup *upgradeLookup, Repository *upgradeSource) : UpgradeLookupProcess::UpgradeLookupProcess(UpgradeLookup *upgradeLookup, Repository *upgradeSource) :
QObject(upgradeLookup), QObject(upgradeLookup),
@ -51,6 +52,7 @@ UpgradeLookupProcess::UpgradeLookupProcess(UpgradeLookup *upgradeLookup, Reposit
m_watcher(new QFutureWatcher<void>(this)) m_watcher(new QFutureWatcher<void>(this))
{ {
connect(this, &UpgradeLookupProcess::finished, upgradeLookup, &UpgradeLookup::processFinished); connect(this, &UpgradeLookupProcess::finished, upgradeLookup, &UpgradeLookup::processFinished);
{
switch(m_upgradeSource->requestsRequired()) { switch(m_upgradeSource->requestsRequired()) {
case PackageDetailAvailability::Request: case PackageDetailAvailability::Request:
m_reply = m_upgradeSource->requestPackageInfo(m_toCheck->packageNames()); m_reply = m_upgradeSource->requestPackageInfo(m_toCheck->packageNames());
@ -65,6 +67,7 @@ UpgradeLookupProcess::UpgradeLookupProcess(UpgradeLookup *upgradeLookup, Reposit
case PackageDetailAvailability::Immediately: case PackageDetailAvailability::Immediately:
break; break;
} }
}
if(m_reply) { if(m_reply) {
m_reply->setParent(this); m_reply->setParent(this);
connect(m_reply, &PackageReply::resultsAvailable, this, &UpgradeLookupProcess::sourceReady); connect(m_reply, &PackageReply::resultsAvailable, this, &UpgradeLookupProcess::sourceReady);
@ -76,7 +79,7 @@ UpgradeLookupProcess::UpgradeLookupProcess(UpgradeLookup *upgradeLookup, Reposit
/*! /*!
* \brief Returns the results. Results are available, after the finished() signal has been emitted. * \brief Returns the results. Results are available, after the finished() signal has been emitted.
*/ */
const UpgradeLookupResults &UpgradeLookupProcess::results() const inline const UpgradeLookupResults &UpgradeLookupProcess::results() const
{ {
return m_results; return m_results;
} }
@ -101,6 +104,7 @@ void UpgradeLookupProcess::sourceReady()
*/ */
void UpgradeLookupProcess::checkUpgrades() void UpgradeLookupProcess::checkUpgrades()
{ {
QReadLocker toCheckLocker(m_toCheck->lock()), srcLocker(m_upgradeSource->lock());
m_toCheck->checkForUpgrades(m_results, QList<Repository *>() << m_upgradeSource); m_toCheck->checkForUpgrades(m_results, QList<Repository *>() << m_upgradeSource);
} }
@ -171,10 +175,12 @@ UpgradeLookupJson::UpgradeLookupJson(Manager &manager, const QJsonObject &reques
{ {
const auto toCheckName = request.value(QStringLiteral("db")).toString(); const auto toCheckName = request.value(QStringLiteral("db")).toString();
if((m_toCheck = manager.repositoryByName(toCheckName))) { if((m_toCheck = manager.repositoryByName(toCheckName))) {
QReadLocker toCheckLocker(m_toCheck->lock());
// construct upgrade lookup processes // construct upgrade lookup processes
const auto syncDbsArray = request.value(QStringLiteral("syncdbs")).toArray(); const auto syncDbsArray = request.value(QStringLiteral("syncdbs")).toArray();
if(syncDbsArray.isEmpty()) { if(syncDbsArray.isEmpty()) {
for(auto *src : m_toCheck->upgradeSources()) { for(auto *src : m_toCheck->upgradeSources()) {
QReadLocker srcLocker(src->lock());
new UpgradeLookupProcess(this, src); new UpgradeLookupProcess(this, src);
++m_remainingProcesses; ++m_remainingProcesses;
} }
@ -182,6 +188,7 @@ UpgradeLookupJson::UpgradeLookupJson(Manager &manager, const QJsonObject &reques
for(const auto &syncDbValue : syncDbsArray) { for(const auto &syncDbValue : syncDbsArray) {
const auto syncDbName = syncDbValue.toString(); const auto syncDbName = syncDbValue.toString();
if(auto *src = manager.repositoryByName(syncDbName)) { if(auto *src = manager.repositoryByName(syncDbName)) {
QReadLocker srcLocker(src->lock());
new UpgradeLookupProcess(this, src); new UpgradeLookupProcess(this, src);
++m_remainingProcesses; ++m_remainingProcesses;
} else { } else {
@ -273,8 +280,10 @@ UpgradeLookupCli::UpgradeLookupCli(Manager &manager, const string &repo, QObject
cerr << shchar << "Checking upgrades for \"" << repo << "\" ..." << endl; cerr << shchar << "Checking upgrades for \"" << repo << "\" ..." << endl;
const auto toCheckName = qstr(repo); const auto toCheckName = qstr(repo);
if((m_toCheck = manager.repositoryByName(toCheckName))) { if((m_toCheck = manager.repositoryByName(toCheckName))) {
QReadLocker toCheckLocker(m_toCheck->lock());
// construct upgrade lookup processes // construct upgrade lookup processes
for(auto *src : m_toCheck->upgradeSources()) { for(auto *src : m_toCheck->upgradeSources()) {
QReadLocker srcLocker(src->lock());
new UpgradeLookupProcess(this, src); new UpgradeLookupProcess(this, src);
++m_remainingProcesses; ++m_remainingProcesses;
} }

View File

@ -49,12 +49,10 @@ void AurPackageReply::processData()
auto *reply = m_networkReplies.front(); auto *reply = m_networkReplies.front();
if(reply->error() == QNetworkReply::NoError) { if(reply->error() == QNetworkReply::NoError) {
QJsonParseError error; QJsonParseError error;
//QByteArray data = m_networkReply->readAll();
//cerr << shchar << "AUR reply: " << data.data() << endl;
//const QJsonDocument doc = QJsonDocument::fromJson(data, &error);
const auto doc = QJsonDocument::fromJson(reply->readAll(), &error); const auto doc = QJsonDocument::fromJson(reply->readAll(), &error);
auto &packages = m_repo->packages();
if(error.error == QJsonParseError::NoError) { if(error.error == QJsonParseError::NoError) {
QWriteLocker locker(m_repo->lock());
auto &packages = m_repo->packages();
for(const auto &result : doc.object().value(QStringLiteral("results")).toArray()) { for(const auto &result : doc.object().value(QStringLiteral("results")).toArray()) {
QJsonObject obj = result.toObject(); QJsonObject obj = result.toObject();
QString packageName = obj.value(QStringLiteral("Name")).toString(); QString packageName = obj.value(QStringLiteral("Name")).toString();
@ -68,10 +66,10 @@ void AurPackageReply::processData()
} }
} }
} else { } else {
m_error = QStringLiteral("Error: Unable to parse JSON received from AUR: ") % error.errorString() % QStringLiteral(" at character ") % QString::number(error.offset); m_error = QStringLiteral("Unable to parse JSON received from AUR: ") % error.errorString() % QStringLiteral(" at character ") % QString::number(error.offset);
} }
} else { } else {
m_error = QStringLiteral("Error: Unable to request data from AUR via AurJson: ") + reply->errorString(); m_error = QStringLiteral("Unable to request data from AUR via AurJson: ") + reply->errorString();
} }
emit resultsAvailable(); emit resultsAvailable();
} }
@ -112,6 +110,7 @@ void AurFullPackageReply::processData()
} }
if(srcInfoEntry && srcInfoEntry->isFile()) { if(srcInfoEntry && srcInfoEntry->isFile()) {
const auto srcInfo = static_cast<const KArchiveFile *>(srcInfoEntry)->data(); const auto srcInfo = static_cast<const KArchiveFile *>(srcInfoEntry)->data();
QWriteLocker locker(m_userRepo->lock());
const auto packages = m_userRepo->addPackagesFromSrcInfo(srcInfo); const auto packages = m_userRepo->addPackagesFromSrcInfo(srcInfo);
// TODO: error handling // TODO: error handling
for(const auto &entryName : baseDir->entries()) { for(const auto &entryName : baseDir->entries()) {
@ -129,13 +128,13 @@ void AurFullPackageReply::processData()
} }
} }
} else { } else {
m_error = QStringLiteral("Error: Aur tarball does not contain \".SRCINFO\"."); m_error = QStringLiteral("Aur tarball does not contain \".SRCINFO\".");
} }
} else { } else {
m_error = QStringLiteral("Error: Unable to open tarball reply."); m_error = QStringLiteral("Unable to open tarball reply.");
} }
} else { } else {
m_error = QStringLiteral("Error: Unable to request tarball from AUR: ") + reply->errorString(); m_error = QStringLiteral("Unable to request tarball from AUR: ") + reply->errorString();
} }
if(!m_error.isEmpty()) { if(!m_error.isEmpty()) {
qDebug() << m_error; qDebug() << m_error;
@ -157,6 +156,7 @@ void AurSuggestionsReply::processData()
//const QJsonDocument doc = QJsonDocument::fromJson(data, &error); //const QJsonDocument doc = QJsonDocument::fromJson(data, &error);
const auto doc = QJsonDocument::fromJson(reply->readAll(), &error); const auto doc = QJsonDocument::fromJson(reply->readAll(), &error);
if(error.error == QJsonParseError::NoError) { if(error.error == QJsonParseError::NoError) {
QWriteLocker locker(m_repo->lock());
auto &packages = m_repo->packages(); auto &packages = m_repo->packages();
if(doc.isObject()) { if(doc.isObject()) {
for(const auto &result : doc.object().value(QStringLiteral("results")).toArray()) { for(const auto &result : doc.object().value(QStringLiteral("results")).toArray()) {
@ -183,10 +183,10 @@ void AurSuggestionsReply::processData()
} }
} }
} else { } else {
m_error = QStringLiteral("Error: Unable to parse JSON received from AUR: ") % error.errorString() % QStringLiteral(" at character ") % QString::number(error.offset); m_error = QStringLiteral("Unable to parse JSON received from AUR: ") % error.errorString() % QStringLiteral(" at character ") % QString::number(error.offset);
} }
} else { } else {
m_error = QStringLiteral("Error: Unable to request data from AUR: ") + reply->errorString(); m_error = QStringLiteral("Unable to request data from AUR: ") + reply->errorString();
} }
emit resultsAvailable(); emit resultsAvailable();
} }