Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement CopyableMutex and CopyableAtomic #1398

Merged
merged 4 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 3 additions & 11 deletions src/engine/Operation.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "parser/data/Variable.h"
#include "util/CancellationHandle.h"
#include "util/CompilerExtensions.h"
#include "util/CopyableSynchronization.h"

// forward declaration needed to break dependencies
class QueryExecutionTree;
Expand Down Expand Up @@ -337,17 +338,8 @@ class Operation {
// future.
LimitOffsetClause _limit;

// A mutex that can be "copied". The semantics are, that copying will create
// a new mutex. This is sufficient for applications like in
// `getInternallyVisibleVariableColumns()` where we just want to make a
// `const` member function that modifies a `mutable` member threadsafe.
struct CopyableMutex : std::mutex {
using std::mutex::mutex;
CopyableMutex(const CopyableMutex&) {}
};

// Mutex that protects the `variableToColumnMap_` below.
mutable CopyableMutex variableToColumnMapMutex_;
mutable ad_utility::CopyableMutex variableToColumnMapMutex_;
// Store the mapping from variables to column indices. `nullopt` means that
// this map has not yet been computed. This computation is typically performed
// in the const member function `getInternallyVisibleVariableColumns`, so we
Expand All @@ -361,7 +353,7 @@ class Operation {
externallyVisibleVariableToColumnMap_;

// Mutex that protects the `_resultSortedColumns` below.
mutable CopyableMutex _resultSortedColumnsMutex;
mutable ad_utility::CopyableMutex _resultSortedColumnsMutex;

// Store the list of columns by which the result is sorted.
mutable std::optional<vector<ColumnIndex>> _resultSortedColumns =
Expand Down
36 changes: 36 additions & 0 deletions src/util/CopyableSynchronization.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2024, University of Freiburg,
// Chair of Algorithms and Data Structures.
// Author:
// Johannes Kalmbach ([email protected])

#pragma once

namespace ad_utility {
// A mutex that can be "copied". The semantics are that copying will create
// a new mutex. This is useful when we just want to make a
// `const` member function that modifies a `mutable` member threadsafe.
// Note that a copy-constructed `CopyableMutex` will be unlocked, even if the
// source was locked, and that copy assignment is a noop.
struct CopyableMutex : std::mutex {
using std::mutex::mutex;
CopyableMutex(const CopyableMutex&) {}
CopyableMutex& operator=(const CopyableMutex&) { return *this; }
};

// A `std::atomic` that can be "copied". The semantics are, that copying will
// create a new atomic that is initialized with the value being copied. This is
// useful if we want to store an atomic as a class member, but still want the
// class to be copyable.
template <typename T>
class CopyableAtomic : public std::atomic<T> {
using Base = std::atomic<T>;

public:
using Base::Base;
CopyableAtomic(const CopyableAtomic& rhs) : Base{rhs.load()} {}
CopyableAtomic& operator=(const CopyableAtomic& rhs) {
static_cast<Base&>(*this) = rhs.load();
return *this;
}
};
} // namespace ad_utility
2 changes: 2 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -395,3 +395,5 @@ addLinkAndDiscoverTest(JThreadTest)
addLinkAndDiscoverTest(ChunkedForLoopTest)

addLinkAndDiscoverTest(FsstCompressorTest fsst)

addLinkAndDiscoverTest(CopyableSynchronizationTest)
37 changes: 37 additions & 0 deletions test/CopyableSynchronizationTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2024, University of Freiburg,
// Chair of Algorithms and Data Structures.
// Author:
// Johannes Kalmbach ([email protected])

#include <gmock/gmock.h>

#include "util/CopyableSynchronization.h"

using namespace ad_utility;

// _________________________________________________
TEST(CopyableSynchronization, CopyableMutex) {
// Not much to test here.
CopyableMutex m1;
m1.lock();
[[maybe_unused]] CopyableMutex m2{m1};
// m2 is still unlocked.
EXPECT_TRUE(m2.try_lock());
m2.unlock();
m1 = m2;
// m1 is still locked;
EXPECT_FALSE(m1.try_lock());
m1.unlock();
}

// _________________________________________________
TEST(CopyableSynchronization, CopyableAtomic) {
CopyableAtomic<int> i1 = 42;
CopyableAtomic<int> i2{i1};
EXPECT_EQ(i2, 42);
++i2;
EXPECT_EQ(i2, 43);
EXPECT_EQ(i1, 42);
i1 = i2;
EXPECT_EQ(i1, 43);
}
Loading