File indexing completed on 2024-11-24 04:54:54
0001 /* 0002 * SPDX-FileCopyrightText: 2013 Aleix Pol Gonzalez <aleixpol@blue-systems.com> 0003 * SPDX-FileCopyrightText: 2017 Jan Grulich <jgrulich@redhat.com> 0004 * SPDX-FileCopyrightText: 2023 Harald Sitter <sitter@kde.org> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0007 */ 0008 0009 #include "FlatpakJobTransaction.h" 0010 #include "FlatpakBackend.h" 0011 #include "FlatpakResource.h" 0012 #include "FlatpakTransactionThread.h" 0013 0014 #include <thread> 0015 0016 #include <QDebug> 0017 #include <QScopeGuard> 0018 #include <QTimer> 0019 0020 namespace 0021 { 0022 class ThreadPool : public QThreadPool 0023 { 0024 public: 0025 ThreadPool() 0026 { 0027 // Cap the amount of concurrency to prevent too many in-flight transactions. This in particular 0028 // prevents running out of file descriptors or other limited resources. 0029 // https://bugs.kde.org/show_bug.cgi?id=474231 0030 constexpr auto arbitraryMaxConcurrency = 4U; 0031 const auto concurrency = std::min(std::thread::hardware_concurrency(), arbitraryMaxConcurrency); 0032 setMaxThreadCount(static_cast<int>(concurrency)); 0033 } 0034 }; 0035 } // namespace 0036 0037 Q_GLOBAL_STATIC(ThreadPool, s_pool); 0038 0039 FlatpakJobTransaction::FlatpakJobTransaction(FlatpakResource *app, Role role, bool delayStart) 0040 : Transaction(app->backend(), app, role, {}) 0041 , m_app(app) 0042 { 0043 setCancellable(true); 0044 setStatus(QueuedStatus); 0045 0046 if (!delayStart) { 0047 QTimer::singleShot(0, this, &FlatpakJobTransaction::start); 0048 } 0049 } 0050 0051 FlatpakJobTransaction::~FlatpakJobTransaction() 0052 { 0053 cancel(); 0054 if (s_pool->tryTake(m_appJob)) { // immediately delete if the runnable hasn't started yet 0055 delete m_appJob; 0056 } else { // otherwise defer cleanup to the pool 0057 m_appJob->setAutoDelete(true); 0058 } 0059 } 0060 0061 void FlatpakJobTransaction::cancel() 0062 { 0063 m_appJob->cancel(); 0064 } 0065 0066 void FlatpakJobTransaction::start() 0067 { 0068 setStatus(CommittingStatus); 0069 0070 // App job will be added every time 0071 m_appJob = new FlatpakTransactionThread(m_app, role()); 0072 m_appJob->setAutoDelete(false); 0073 connect(m_appJob, &FlatpakTransactionThread::finished, this, &FlatpakJobTransaction::finishTransaction); 0074 connect(m_appJob, &FlatpakTransactionThread::progressChanged, this, &FlatpakJobTransaction::setProgress); 0075 connect(m_appJob, &FlatpakTransactionThread::speedChanged, this, &FlatpakJobTransaction::setDownloadSpeed); 0076 connect(m_appJob, &FlatpakTransactionThread::passiveMessage, this, &FlatpakJobTransaction::passiveMessage); 0077 connect(m_appJob, &FlatpakTransactionThread::webflowStarted, this, &FlatpakJobTransaction::webflowStarted); 0078 connect(m_appJob, &FlatpakTransactionThread::webflowDone, this, &FlatpakJobTransaction::webflowDone); 0079 0080 s_pool->start(m_appJob); 0081 } 0082 0083 void FlatpakJobTransaction::finishTransaction() 0084 { 0085 if (static_cast<FlatpakBackend *>(m_app->backend())->getInstalledRefForApp(m_app)) { 0086 m_app->setState(AbstractResource::Installed); 0087 } else { 0088 m_app->setState(AbstractResource::None); 0089 } 0090 0091 if (!m_appJob->addedRepositories().isEmpty()) { 0092 Q_EMIT repositoriesAdded(m_appJob->addedRepositories()); 0093 } 0094 0095 if (!m_appJob->cancelled() && !m_appJob->errorMessage().isEmpty()) { 0096 Q_EMIT passiveMessage(m_appJob->errorMessage()); 0097 } 0098 0099 if (m_appJob->result()) { 0100 setStatus(DoneStatus); 0101 } else { 0102 setStatus(m_appJob->cancelled() ? CancelledStatus : DoneWithErrorStatus); 0103 } 0104 }