mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-11-21 16:55:46 +03:00
Open "lock" files for the same folder only once
PR #20414. Closes #12203.
This commit is contained in:
parent
e31b553807
commit
f04edd555f
2 changed files with 50 additions and 18 deletions
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2017-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -34,31 +34,56 @@
|
|||
#include "base/utils/fs.h"
|
||||
#include "base/utils/io.h"
|
||||
|
||||
QHash<Path, std::weak_ptr<QFile>> AsyncFileStorage::m_reservedPaths;
|
||||
QReadWriteLock AsyncFileStorage::m_reservedPathsLock;
|
||||
|
||||
AsyncFileStorage::AsyncFileStorage(const Path &storageFolderPath, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_storageDir(storageFolderPath)
|
||||
, m_lockFile((m_storageDir / Path(u"storage.lock"_s)).data())
|
||||
{
|
||||
Q_ASSERT(m_storageDir.isAbsolute());
|
||||
|
||||
if (!Utils::Fs::mkpath(m_storageDir))
|
||||
throw AsyncFileStorageError(tr("Could not create directory '%1'.").arg(m_storageDir.toString()));
|
||||
const Path lockFilePath = m_storageDir / Path(u"storage.lock"_s);
|
||||
|
||||
// TODO: This folder locking approach does not work for UNIX systems. Implement it.
|
||||
if (!m_lockFile.open(QFile::WriteOnly))
|
||||
throw AsyncFileStorageError(m_lockFile.errorString());
|
||||
{
|
||||
const QReadLocker readLocker {&m_reservedPathsLock};
|
||||
m_lockFile = m_reservedPaths.value(lockFilePath).lock();
|
||||
}
|
||||
|
||||
if (!m_lockFile)
|
||||
{
|
||||
const QWriteLocker writeLocker {&m_reservedPathsLock};
|
||||
if (std::weak_ptr<QFile> &lockFile = m_reservedPaths[lockFilePath]; lockFile.expired()) [[likely]]
|
||||
{
|
||||
if (!Utils::Fs::mkpath(m_storageDir))
|
||||
throw AsyncFileStorageError(tr("Could not create directory '%1'.").arg(m_storageDir.toString()));
|
||||
|
||||
auto lockFileDeleter = [](QFile *file)
|
||||
{
|
||||
file->close();
|
||||
file->remove();
|
||||
delete file;
|
||||
};
|
||||
m_lockFile = std::shared_ptr<QFile>(new QFile(lockFilePath.data()), std::move(lockFileDeleter));
|
||||
|
||||
// TODO: This folder locking approach does not work for UNIX systems. Implement it.
|
||||
if (!m_lockFile->open(QFile::WriteOnly))
|
||||
throw AsyncFileStorageError(m_lockFile->errorString());
|
||||
|
||||
lockFile = m_lockFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_lockFile = lockFile.lock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AsyncFileStorage::~AsyncFileStorage()
|
||||
{
|
||||
m_lockFile.close();
|
||||
m_lockFile.remove();
|
||||
}
|
||||
AsyncFileStorage::~AsyncFileStorage() = default;
|
||||
|
||||
void AsyncFileStorage::store(const Path &filePath, const QByteArray &data)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, [this, data, filePath]() { store_impl(filePath, data); }
|
||||
, Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(this, [this, data, filePath] { store_impl(filePath, data); }, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
Path AsyncFileStorage::storageDir() const
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2017-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -28,19 +28,23 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QFile>
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QReadWriteLock>
|
||||
|
||||
#include "base/exceptions.h"
|
||||
#include "base/path.h"
|
||||
|
||||
class AsyncFileStorageError : public RuntimeError
|
||||
class AsyncFileStorageError final : public RuntimeError
|
||||
{
|
||||
public:
|
||||
using RuntimeError::RuntimeError;
|
||||
};
|
||||
|
||||
class AsyncFileStorage : public QObject
|
||||
class AsyncFileStorage final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(AsyncFileStorage)
|
||||
|
@ -60,5 +64,8 @@ private:
|
|||
Q_INVOKABLE void store_impl(const Path &fileName, const QByteArray &data);
|
||||
|
||||
Path m_storageDir;
|
||||
QFile m_lockFile;
|
||||
std::shared_ptr<QFile> m_lockFile;
|
||||
|
||||
static QHash<Path, std::weak_ptr<QFile>> m_reservedPaths;
|
||||
static QReadWriteLock m_reservedPathsLock;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue