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

View File

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

View File

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

View File

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

View File

@ -24,13 +24,13 @@ SuggestionsLookup::SuggestionsLookup(Manager &manager, const QJsonObject &reques
if(m_errors.isEmpty()) {
for(const auto &repoName : repos) {
if(auto *repo = manager.repositoryByName(repoName.toString())) {
QReadLocker locker(repo->lock());
if(const auto *reply = repo->requestSuggestions(searchTerm)) {
connect(reply, &SuggestionsReply::resultsAvailable, this, &SuggestionsLookup::addResults);
++m_remainingReplies;
} else {
m_results << repo->suggestions(searchTerm);
}
} else {
m_errors << QStringLiteral("The specified repository \"%1\" does not exist.").arg(repoName.toString());
}
@ -44,7 +44,10 @@ void SuggestionsLookup::addResults()
{
assert(m_remainingReplies);
auto *reply = static_cast<SuggestionsReply *>(sender());
m_results << reply->suggestions();
{
QReadLocker locker(reply->repository()->lock());
m_results << reply->suggestions();
}
reply->deleteLater();
if(!--m_remainingReplies) {
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.
* \remarks \a upgradeLookup and \a upgradeSource musted be locked by caller
*/
UpgradeLookupProcess::UpgradeLookupProcess(UpgradeLookup *upgradeLookup, Repository *upgradeSource) :
QObject(upgradeLookup),
@ -51,19 +52,21 @@ UpgradeLookupProcess::UpgradeLookupProcess(UpgradeLookup *upgradeLookup, Reposit
m_watcher(new QFutureWatcher<void>(this))
{
connect(this, &UpgradeLookupProcess::finished, upgradeLookup, &UpgradeLookup::processFinished);
switch(m_upgradeSource->requestsRequired()) {
case PackageDetailAvailability::Request:
m_reply = m_upgradeSource->requestPackageInfo(m_toCheck->packageNames());
break;
case PackageDetailAvailability::FullRequest:
m_reply = m_upgradeSource->requestFullPackageInfo(m_toCheck->packageNames());
break;
case PackageDetailAvailability::Never:
m_results.errors << QStringLiteral("Repository \"%1\" does not provide the required information.").arg(m_upgradeSource->name());
emit finished();
return;
case PackageDetailAvailability::Immediately:
break;
{
switch(m_upgradeSource->requestsRequired()) {
case PackageDetailAvailability::Request:
m_reply = m_upgradeSource->requestPackageInfo(m_toCheck->packageNames());
break;
case PackageDetailAvailability::FullRequest:
m_reply = m_upgradeSource->requestFullPackageInfo(m_toCheck->packageNames());
break;
case PackageDetailAvailability::Never:
m_results.errors << QStringLiteral("Repository \"%1\" does not provide the required information.").arg(m_upgradeSource->name());
emit finished();
return;
case PackageDetailAvailability::Immediately:
break;
}
}
if(m_reply) {
m_reply->setParent(this);
@ -76,7 +79,7 @@ UpgradeLookupProcess::UpgradeLookupProcess(UpgradeLookup *upgradeLookup, Reposit
/*!
* \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;
}
@ -101,6 +104,7 @@ void UpgradeLookupProcess::sourceReady()
*/
void UpgradeLookupProcess::checkUpgrades()
{
QReadLocker toCheckLocker(m_toCheck->lock()), srcLocker(m_upgradeSource->lock());
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();
if((m_toCheck = manager.repositoryByName(toCheckName))) {
QReadLocker toCheckLocker(m_toCheck->lock());
// construct upgrade lookup processes
const auto syncDbsArray = request.value(QStringLiteral("syncdbs")).toArray();
if(syncDbsArray.isEmpty()) {
for(auto *src : m_toCheck->upgradeSources()) {
QReadLocker srcLocker(src->lock());
new UpgradeLookupProcess(this, src);
++m_remainingProcesses;
}
@ -182,6 +188,7 @@ UpgradeLookupJson::UpgradeLookupJson(Manager &manager, const QJsonObject &reques
for(const auto &syncDbValue : syncDbsArray) {
const auto syncDbName = syncDbValue.toString();
if(auto *src = manager.repositoryByName(syncDbName)) {
QReadLocker srcLocker(src->lock());
new UpgradeLookupProcess(this, src);
++m_remainingProcesses;
} else {
@ -273,8 +280,10 @@ UpgradeLookupCli::UpgradeLookupCli(Manager &manager, const string &repo, QObject
cerr << shchar << "Checking upgrades for \"" << repo << "\" ..." << endl;
const auto toCheckName = qstr(repo);
if((m_toCheck = manager.repositoryByName(toCheckName))) {
QReadLocker toCheckLocker(m_toCheck->lock());
// construct upgrade lookup processes
for(auto *src : m_toCheck->upgradeSources()) {
QReadLocker srcLocker(src->lock());
new UpgradeLookupProcess(this, src);
++m_remainingProcesses;
}

View File

@ -49,12 +49,10 @@ void AurPackageReply::processData()
auto *reply = m_networkReplies.front();
if(reply->error() == QNetworkReply::NoError) {
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);
auto &packages = m_repo->packages();
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()) {
QJsonObject obj = result.toObject();
QString packageName = obj.value(QStringLiteral("Name")).toString();
@ -68,10 +66,10 @@ void AurPackageReply::processData()
}
}
} 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 {
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();
}
@ -112,6 +110,7 @@ void AurFullPackageReply::processData()
}
if(srcInfoEntry && srcInfoEntry->isFile()) {
const auto srcInfo = static_cast<const KArchiveFile *>(srcInfoEntry)->data();
QWriteLocker locker(m_userRepo->lock());
const auto packages = m_userRepo->addPackagesFromSrcInfo(srcInfo);
// TODO: error handling
for(const auto &entryName : baseDir->entries()) {
@ -129,13 +128,13 @@ void AurFullPackageReply::processData()
}
}
} else {
m_error = QStringLiteral("Error: Aur tarball does not contain \".SRCINFO\".");
m_error = QStringLiteral("Aur tarball does not contain \".SRCINFO\".");
}
} else {
m_error = QStringLiteral("Error: Unable to open tarball reply.");
m_error = QStringLiteral("Unable to open tarball reply.");
}
} 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()) {
qDebug() << m_error;
@ -157,6 +156,7 @@ void AurSuggestionsReply::processData()
//const QJsonDocument doc = QJsonDocument::fromJson(data, &error);
const auto doc = QJsonDocument::fromJson(reply->readAll(), &error);
if(error.error == QJsonParseError::NoError) {
QWriteLocker locker(m_repo->lock());
auto &packages = m_repo->packages();
if(doc.isObject()) {
for(const auto &result : doc.object().value(QStringLiteral("results")).toArray()) {
@ -183,10 +183,10 @@ void AurSuggestionsReply::processData()
}
}
} 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 {
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();
}