Skip to content

Commit 501c71d

Browse files
Clean up lease management (#17)
* Cleaned up lock tracking and destruction * Update src/AVEVA/RocksDB/Plugin/Azure/BlobFilesystem.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Make sure to delete the lock file in UnlockFile * Delete lockFile --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 052aab7 commit 501c71d

File tree

9 files changed

+42
-54
lines changed

9 files changed

+42
-54
lines changed

include/AVEVA/RocksDB/Plugin/Azure/BlobFilesystem.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ namespace AVEVA::RocksDB::Plugin::Azure
1919
{
2020
std::unique_ptr<Impl::BlobFilesystemImpl> m_filesystem;
2121
std::shared_ptr<boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level>> m_logger;
22-
boost::intrusive::list<Azure::LockFile, boost::intrusive::constant_time_size<false>> m_lockFiles;
23-
22+
std::vector<Azure::LockFile*> m_lockFiles;
2423
public:
2524
BlobFilesystem(std::shared_ptr<rocksdb::FileSystem> rocksdbFs,
2625
std::unique_ptr<Impl::BlobFilesystemImpl> filesystem,

include/AVEVA/RocksDB/Plugin/Azure/Impl/BlobFilesystemImpl.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ namespace AVEVA::RocksDB::Plugin::Azure::Impl
4747
std::unordered_map<std::string, ServiceContainer, Core::StringHash, Core::StringEqual> m_clients;
4848
std::unordered_map<std::string, std::shared_ptr<Core::FileCache>, Core::StringHash, Core::StringEqual> m_fileCaches;
4949
std::mutex m_lockFilesMutex;
50-
std::vector<std::shared_ptr<LockFileImpl>> m_locks;
50+
boost::intrusive::list<LockFileImpl, boost::intrusive::constant_time_size<false>> m_locks;
5151
std::stop_source m_filesystemStopSource;
5252
std::jthread m_lockRenewalThread;
5353

@@ -103,7 +103,7 @@ namespace AVEVA::RocksDB::Plugin::Azure::Impl
103103
[[nodiscard]] WriteableFileImpl ReuseWritableFile(const std::string& filePath);
104104
LoggerImpl CreateLogger(const std::string& filePath, int logLevel);
105105
std::shared_ptr<LockFileImpl> LockFile(const std::string& filePath);
106-
bool UnlockFile(const LockFileImpl& lock);
106+
void UnlockFile(LockFileImpl& lock);
107107
DirectoryImpl CreateDirectory(const std::string& directoryPath);
108108

109109
[[nodiscard]] bool FileExists(const std::string& name);

include/AVEVA/RocksDB/Plugin/Azure/Impl/LockFileImpl.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
// SPDX-FileCopyrightText: Copyright 2025 AVEVA
33

44
#pragma once
5+
#include <boost/intrusive/list.hpp>
56
#include <azure/storage/blobs/page_blob_client.hpp>
67
#include <azure/storage/blobs/blob_lease_client.hpp>
78
#include <memory>
89
#include <chrono>
910
namespace AVEVA::RocksDB::Plugin::Azure::Impl
1011
{
11-
class LockFileImpl
12+
class LockFileImpl : public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>
1213
{
1314
std::unique_ptr<::Azure::Storage::Blobs::PageBlobClient> m_file;
1415
std::unique_ptr<::Azure::Storage::Blobs::BlobLeaseClient> m_lease = nullptr;
@@ -23,5 +24,8 @@ namespace AVEVA::RocksDB::Plugin::Azure::Impl
2324

2425
[[nodiscard]] std::chrono::seconds TimeSinceLastRenewal() const;
2526
[[nodiscard]] bool HasExceededLeaseLength() const;
27+
28+
void unlink();
29+
bool is_linked();
2630
};
2731
}

include/AVEVA/RocksDB/Plugin/Azure/LockFile.hpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@
44
#pragma once
55
#include "AVEVA/RocksDB/Plugin/Azure/Impl/LockFileImpl.hpp"
66

7-
#include <boost/intrusive/list.hpp>
87
#include <rocksdb/db.h>
98

109
#include <memory>
1110
namespace AVEVA::RocksDB::Plugin::Azure
1211
{
13-
class LockFile : public rocksdb::FileLock, public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>
12+
class LockFile : public rocksdb::FileLock
1413
{
1514
std::shared_ptr<Impl::LockFileImpl> m_lock;
1615
public:
@@ -19,7 +18,6 @@ namespace AVEVA::RocksDB::Plugin::Azure
1918
void Renew() const;
2019
void Unlock();
2120

22-
void unlink();
23-
bool is_linked();
21+
Impl::LockFileImpl& GetImpl() const;
2422
};
2523
}

src/AVEVA/RocksDB/Plugin/Azure/BlobFilesystem.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ namespace AVEVA::RocksDB::Plugin::Azure
2323

2424
BlobFilesystem::~BlobFilesystem()
2525
{
26-
m_lockFiles.clear_and_dispose([](Azure::LockFile* lock) static
26+
for (auto lock : m_lockFiles)
2727
{
28+
m_filesystem->UnlockFile(lock->GetImpl());
2829
delete lock;
29-
});
30+
}
3031
}
3132

3233
const char* BlobFilesystem::Name() const
@@ -544,8 +545,8 @@ namespace AVEVA::RocksDB::Plugin::Azure
544545
*l = nullptr;
545546
auto lock = m_filesystem->LockFile(f);
546547
auto lockFileWrapper = new Plugin::Azure::LockFile(lock);
548+
m_lockFiles.push_back(lockFileWrapper);
547549
*l = lockFileWrapper;
548-
m_lockFiles.push_back(*lockFileWrapper);
549550
return rocksdb::IOStatus::OK();
550551
}
551552
catch (const ::Azure::Core::RequestFailedException& ex)
@@ -571,17 +572,16 @@ namespace AVEVA::RocksDB::Plugin::Azure
571572
try
572573
{
573574
auto lockFile = dynamic_cast<Plugin::Azure::LockFile*>(l);
574-
if (lockFile != nullptr)
575+
if (lockFile == nullptr)
575576
{
576-
lockFile->Unlock();
577-
delete lockFile;
578-
return rocksdb::IOStatus::OK();
579-
}
580-
else
581-
{
582-
BOOST_LOG_SEV(*m_logger, error) << "Unable to case file lock to Azure::LockFile";
577+
BOOST_LOG_SEV(*m_logger, error) << "Unable to cast file lock to Azure::LockFile";
583578
return rocksdb::IOStatus::InvalidArgument();
584579
}
580+
581+
m_filesystem->UnlockFile(lockFile->GetImpl());
582+
std::erase_if(m_lockFiles, [lockFile](const auto& l) { return l == lockFile; });
583+
delete lockFile;
584+
return rocksdb::IOStatus::OK();
585585
}
586586
catch (const ::Azure::Core::RequestFailedException& ex)
587587
{

src/AVEVA/RocksDB/Plugin/Azure/Impl/BlobFilesystemImpl.cpp

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,8 @@ namespace AVEVA::RocksDB::Plugin::Azure::Impl
356356
auto lockFile = std::make_shared<LockFileImpl>(std::move(client), Configuration::LeaseLength);
357357
if (lockFile->Lock())
358358
{
359-
m_locks.push_back(lockFile);
359+
m_locks.push_back(*lockFile);
360+
assert(lockFile->is_linked());
360361
return lockFile;
361362
}
362363
else
@@ -365,28 +366,13 @@ namespace AVEVA::RocksDB::Plugin::Azure::Impl
365366
}
366367
}
367368

368-
bool BlobFilesystemImpl::UnlockFile(const LockFileImpl& lock)
369+
void BlobFilesystemImpl::UnlockFile(LockFileImpl& lock)
369370
{
370371
EnsureLiveness();
371372

372373
std::scoped_lock _(m_lockFilesMutex);
373-
const auto it = std::find_if(m_locks.cbegin(),
374-
m_locks.cend(),
375-
[&lock](const auto& f)
376-
{
377-
return f.get() == &lock;
378-
});
379-
380-
if (it != m_locks.cend())
381-
{
382-
(*it)->Unlock();
383-
m_locks.erase(it);
384-
return true;
385-
}
386-
else
387-
{
388-
return false;
389-
}
374+
lock.Unlock();
375+
lock.unlink();
390376
}
391377

392378
DirectoryImpl BlobFilesystemImpl::CreateDirectory(const std::string& directoryPath)
@@ -775,11 +761,11 @@ namespace AVEVA::RocksDB::Plugin::Azure::Impl
775761

776762
{
777763
std::scoped_lock lock(m_lockFilesMutex);
778-
std::vector<LockFileImpl*> needsRetry;
764+
std::vector<const LockFileImpl*> needsRetry;
779765
needsRetry.reserve(m_locks.size());
780766
for (const auto& l : m_locks)
781767
{
782-
needsRetry.push_back(l.get());
768+
needsRetry.push_back(&l);
783769
}
784770

785771
// Attempt to renew all locks with retries

src/AVEVA/RocksDB/Plugin/Azure/Impl/LockFileImpl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,14 @@ namespace AVEVA::RocksDB::Plugin::Azure::Impl
109109
{
110110
return TimeSinceLastRenewal() >= m_leaseLength;
111111
}
112+
113+
void LockFileImpl::unlink()
114+
{
115+
boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>::unlink();
116+
}
117+
118+
bool LockFileImpl::is_linked()
119+
{
120+
return boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>::is_linked();
121+
}
112122
}

src/AVEVA/RocksDB/Plugin/Azure/LockFile.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,8 @@ namespace AVEVA::RocksDB::Plugin::Azure
2424
m_lock->Unlock();
2525
}
2626

27-
void LockFile::unlink()
27+
Impl::LockFileImpl& LockFile::GetImpl() const
2828
{
29-
boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>::unlink();
30-
}
31-
32-
bool LockFile::is_linked()
33-
{
34-
return boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>::is_linked();
29+
return *m_lock;
3530
}
3631
}

tests/AVEVA/RocksDB/Plugin/Azure/Impl/BlobFilesystemIntegrationTests.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -638,10 +638,9 @@ TEST_F(BlobFilesystemIntegrationTests, UnlockFile_ReleasesLock)
638638
EXPECT_EQ(1, m_filesystem->GetLeaseClientCount());
639639

640640
// Act
641-
bool unlocked = m_filesystem->UnlockFile(*lock);
641+
m_filesystem->UnlockFile(*lock);
642642

643643
// Assert
644-
EXPECT_TRUE(unlocked);
645644
EXPECT_EQ(0, m_filesystem->GetLeaseClientCount());
646645

647646
// Cleanup
@@ -661,10 +660,7 @@ TEST_F(BlobFilesystemIntegrationTests, UnlockFile_InvalidLock_ReturnsFalse)
661660
m_filesystem->UnlockFile(*lock1);
662661

663662
// Act - try to unlock lock1 again
664-
bool unlocked = m_filesystem->UnlockFile(*lock1);
665-
666-
// Assert
667-
EXPECT_FALSE(unlocked);
663+
EXPECT_THROW(m_filesystem->UnlockFile(*lock1), std::runtime_error);
668664

669665
// Cleanup
670666
m_filesystem->UnlockFile(*lock2);

0 commit comments

Comments
 (0)