Skip to content

Commit

Permalink
Open "lock" files for the same folder only once
Browse files Browse the repository at this point in the history
  • Loading branch information
glassez authored Feb 15, 2024
1 parent e31b553 commit f04edd5
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 18 deletions.
53 changes: 39 additions & 14 deletions src/base/asyncfilestorage.cpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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();
}

AsyncFileStorage::~AsyncFileStorage()
{
m_lockFile.close();
m_lockFile.remove();
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() = 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
Expand Down
15 changes: 11 additions & 4 deletions src/base/asyncfilestorage.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -60,5 +64,8 @@ class AsyncFileStorage : public QObject
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;
};

0 comments on commit f04edd5

Please sign in to comment.