summaryrefslogtreecommitdiffstats
path: root/src/common/item_history.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 18:24:20 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 18:24:20 +0000
commit483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch)
treee5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/common/item_history.h
parentInitial commit. (diff)
downloadceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz
ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.zip
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/common/item_history.h')
-rw-r--r--src/common/item_history.h103
1 files changed, 103 insertions, 0 deletions
diff --git a/src/common/item_history.h b/src/common/item_history.h
new file mode 100644
index 00000000..351d5ba7
--- /dev/null
+++ b/src/common/item_history.h
@@ -0,0 +1,103 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#pragma once
+
+#include <list>
+#include <mutex>
+
+/*
+
+Keep a history of item values so that readers can dereference the pointer to
+the latest value and continue using it as long as they want. This container
+is only appropriate for values that are updated a handful of times over their
+total lifetime.
+
+There is a prune() method to throw out old values, but it should only be used
+if the caller has some way of knowing all readers are done.
+
+*/
+
+template<class T>
+class mutable_item_history {
+private:
+ std::mutex lock;
+ std::list<T> history;
+ T *current = nullptr;
+
+public:
+ mutable_item_history() {
+ history.emplace_back(T());
+ current = &history.back();
+ }
+
+ // readers are lock-free
+ const T& operator*() const {
+ return *current;
+ }
+ const T *operator->() const {
+ return current;
+ }
+
+ // non-const variants (be careful!)
+ T& operator*() {
+ return *current;
+ }
+ T *operator->() {
+ return current;
+ }
+
+ // writes are serialized
+ const T& operator=(const T& other) {
+ std::lock_guard l(lock);
+ history.push_back(other);
+ current = &history.back();
+ return *current;
+ }
+
+ void prune() {
+ // note: this is not necessarily thread-safe wrt readers
+ std::lock_guard l(lock);
+ while (history.size() > 1) {
+ history.pop_front();
+ }
+ }
+};
+
+template<class T>
+class safe_item_history {
+private:
+ std::mutex lock;
+ std::list<T> history;
+ T *current = nullptr;
+
+public:
+ safe_item_history() {
+ history.emplace_back(T());
+ current = &history.back();
+ }
+
+ // readers are lock-free
+ const T& operator*() const {
+ return *current;
+ }
+ const T *operator->() const {
+ return current;
+ }
+
+ // writes are serialized
+ const T& operator=(const T& other) {
+ std::lock_guard l(lock);
+ history.push_back(other);
+ current = &history.back();
+ return *current;
+ }
+
+ void prune() {
+ // note: this is not necessarily thread-safe wrt readers
+ std::lock_guard l(lock);
+ while (history.size() > 1) {
+ history.pop_front();
+ }
+ }
+};