diff --git a/fdbrpc/CMakeLists.txt b/fdbrpc/CMakeLists.txt index b4fb20098d..41229dce47 100644 --- a/fdbrpc/CMakeLists.txt +++ b/fdbrpc/CMakeLists.txt @@ -22,6 +22,8 @@ set(FDBRPC_SRCS ReplicationPolicy.cpp ReplicationTypes.cpp ReplicationUtils.cpp + RoleLineage.h + RoleLineage.cpp Stats.actor.cpp Stats.h sim2.actor.cpp diff --git a/fdbrpc/Locality.h b/fdbrpc/Locality.h index 11c209071a..2129b7a3b7 100644 --- a/fdbrpc/Locality.h +++ b/fdbrpc/Locality.h @@ -63,6 +63,7 @@ struct ProcessClass { Ratekeeper, StorageCache, Backup, + Worker, // used for actor lineage tracking NoRole }; enum ClassSource { CommandLineSource, AutoSource, DBSource, InvalidSource = -1 }; diff --git a/fdbrpc/RoleLineage.cpp b/fdbrpc/RoleLineage.cpp new file mode 100644 index 0000000000..89a64bbe40 --- /dev/null +++ b/fdbrpc/RoleLineage.cpp @@ -0,0 +1,23 @@ +/* + * RoleLineage.cpp + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2013-2020 Apple Inc. and the FoundationDB project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fdbrpc/RoleLineage.h" + +StringRef RoleLineage::name = "RoleLineage"_sr; diff --git a/fdbrpc/RoleLineage.h b/fdbrpc/RoleLineage.h new file mode 100644 index 0000000000..30a2ea2650 --- /dev/null +++ b/fdbrpc/RoleLineage.h @@ -0,0 +1,31 @@ +/* + * RoleLineage.h + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2013-2020 Apple Inc. and the FoundationDB project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "fdbrpc/Locality.h" + +struct RoleLineage : LineageProperties { + static StringRef name; + ProcessClass::ClusterRole role = ProcessClass::NoRole; + + bool isSet(ProcessClass::ClusterRole RoleLineage::*member) { + return this->*member != ProcessClass::NoRole; + } +}; diff --git a/fdbserver/worker.actor.cpp b/fdbserver/worker.actor.cpp index ca34f903a2..98363ea247 100644 --- a/fdbserver/worker.actor.cpp +++ b/fdbserver/worker.actor.cpp @@ -22,6 +22,7 @@ #include #include "fdbrpc/Locality.h" +#include "fdbrpc/RoleLineage.h" #include "fdbclient/StorageServerInterface.h" #include "fdbserver/Knobs.h" #include "flow/ActorCollection.h" @@ -46,6 +47,7 @@ #include "flow/Profiler.h" #include "flow/ThreadHelper.actor.h" #include "flow/Trace.h" +#include "flow/flow.h" #ifdef __linux__ #include @@ -1810,6 +1812,7 @@ ACTOR Future fdbd( { state vector> actors; state Promise recoveredDiskFiles; + currentLineage->modify(&RoleLineage::role) = ProcessClass::Worker; try { ServerCoordinators coordinators( connFile ); diff --git a/flow/flow.cpp b/flow/flow.cpp index ed977141bd..5b354fe054 100644 --- a/flow/flow.cpp +++ b/flow/flow.cpp @@ -31,6 +31,12 @@ thread_local Reference currentLineage; ActorLineage::ActorLineage() : parent(currentLineage) { } +ActorLineage::~ActorLineage() { + for (auto ptr : properties) { + delete ptr.second; + } +} + #if (defined(__linux__) || defined(__FreeBSD__)) && defined(__AVX__) && !defined(MEMORY_SANITIZER) // For benchmarking; need a version of rte_memcpy that doesn't live in the same compilation unit as the test. void * rte_memcpy_noinline(void *__restrict __dest, const void *__restrict __src, size_t __n) { diff --git a/flow/flow.h b/flow/flow.h index a0c9793a7a..0ffc895a86 100644 --- a/flow/flow.h +++ b/flow/flow.h @@ -20,6 +20,7 @@ #ifndef FLOW_FLOW_H #define FLOW_FLOW_H +#include "flow/Arena.h" #include "flow/FastRef.h" #pragma once @@ -29,6 +30,7 @@ #include #include +#include #include #include #include @@ -409,21 +411,88 @@ struct SingleCallback { } }; -struct ActorLineagePropertyMap : ReferenceCounted { +struct LineagePropertiesBase { +}; + +// helper class to make implementation of LineageProperties easier +template +struct LineageProperties : LineagePropertiesBase { + // Contract: + // + // StringRef name = "SomeUniqueName"_str; + + + // this has to be implemented by subclasses + // but can't be made virtual. + // A user should implement this for any type + // within the properies class. + template + bool isSet(Value Derived::*member) { + return true; + } }; struct ActorLineage : ReferenceCounted { - Reference map; +private: + std::unordered_map properties; Reference parent; +public: ActorLineage(); + ~ActorLineage(); + bool isRoot() const { + return parent.getPtr() == nullptr; + } + void makeRoot() { + parent.clear(); + } + template + V& modify(V T::*member) { + auto& res = properties[T::name]; + if (!res) { + res = new T{}; + } + T* map = static_cast(res); + return map->*member; + } + template + std::optional get(V T::*member) const { + auto current = this; + while (current != nullptr) { + auto iter = current->properties.find(T::name); + if (iter != current->properties.end()) { + T const& map = static_cast(*iter->second); + if (map.isSet(member)) { + return map.*member; + } + } + current = current->parent.getPtr(); + } + return std::optional{}; + } + template + std::stack stack(V T::*member) const { + auto current = this; + std::stack res; + while (current != nullptr) { + auto iter = current->properties.find(T::name); + if (iter != current->properties.end()) { + T const& map = static_cast(*iter->second); + if (map.isSet(member)) { + res.push(map.*member); + } + } + current = current->parent.getPtr(); + } + return res; + } }; extern thread_local Reference currentLineage; struct restore_lineage { - Reference lineage; - restore_lineage() : lineage(currentLineage) {} - ~restore_lineage() { currentLineage = lineage; } + Reference prev; + restore_lineage() : prev(currentLineage) {} + ~restore_lineage() { currentLineage = prev; } }; // SAV is short for Single Assignment Variable: It can be assigned for only once! @@ -465,7 +534,6 @@ public: ASSERT(canBeSet()); new (&value_storage) T(std::forward(value)); this->error_state = Error::fromCode(SET_ERROR_CODE); - restore_lineage _; while (Callback::next != this) { Callback::next->fire(this->value()); } @@ -479,7 +547,6 @@ public: void sendError(Error err) { ASSERT(canBeSet() && int16_t(err.code()) > 0); this->error_state = err; - restore_lineage _; while (Callback::next != this) { Callback::next->error(err); } @@ -487,7 +554,6 @@ public: template void sendAndDelPromiseRef(U && value) { - restore_lineage _; ASSERT(canBeSet()); if (promises == 1 && !futures) { // No one is left to receive the value, so we can just die @@ -501,7 +567,6 @@ public: void finishSendAndDelPromiseRef() { // Call only after value_storage has already been initialized! - restore_lineage _; this->error_state = Error::fromCode(SET_ERROR_CODE); while (Callback::next != this) Callback::next->fire(this->value()); @@ -518,7 +583,6 @@ public: } void sendErrorAndDelPromiseRef(Error err) { - restore_lineage _; ASSERT(canBeSet() && int16_t(err.code()) > 0); if (promises == 1 && !futures) { // No one is left to receive the value, so we can just die @@ -622,7 +686,6 @@ struct NotifiedQueue : private SingleCallback, FastAllocated if (error.isValid()) return; if (SingleCallback::next != this) { - restore_lineage _; SingleCallback::next->fire(std::forward(value)); } else { @@ -635,7 +698,6 @@ struct NotifiedQueue : private SingleCallback, FastAllocated this->error = err; if (SingleCallback::next != this) { - restore_lineage _; SingleCallback::next->error(err); } } @@ -1025,13 +1087,13 @@ struct Actor : SAV { /*++actorCount;*/ currentLineage = lineage; } + //~Actor() { --actorCount; } Reference setLineage() { auto res = currentLineage; currentLineage = lineage; return res; } - //~Actor() { --actorCount; } }; template <> @@ -1045,13 +1107,13 @@ struct Actor { /*++actorCount;*/ currentLineage = lineage; } + //~Actor() { --actorCount; } Reference setLineage() { auto res = currentLineage; currentLineage = lineage; return res; } - //~Actor() { --actorCount; } }; template