mirror of https://github.com/grpc/grpc.git
[GCP auth filter] add "blackboard" mechanism for retaining global state, and use it for cache in GCP auth filter (#37646)
This is the last piece of gRFC A83 (https://github.com/grpc/proposal/pull/438).
Note that although this is the first use-case for this "blackboard" mechanism, we will also use it in the future for the xDS rate-limiting filter on the gRPC server side.
Closes #37646
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/37646 from markdroth:gcp_auth_filter_state 72d0d96c79
PiperOrigin-RevId: 679707134
pull/37584/head
parent
6dbc0bdb10
commit
e56d766a45
37 changed files with 675 additions and 59 deletions
@ -0,0 +1,33 @@ |
|||||||
|
//
|
||||||
|
// Copyright 2024 gRPC 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 "src/core/filter/blackboard.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
RefCountedPtr<Blackboard::Entry> Blackboard::Get(UniqueTypeName type, |
||||||
|
const std::string& key) const { |
||||||
|
auto it = map_.find(std::make_pair(type, key)); |
||||||
|
if (it == map_.end()) return nullptr; |
||||||
|
return it->second; |
||||||
|
} |
||||||
|
|
||||||
|
void Blackboard::Set(UniqueTypeName type, const std::string& key, |
||||||
|
RefCountedPtr<Entry> entry) { |
||||||
|
map_[std::make_pair(type, key)] = std::move(entry); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_core
|
@ -0,0 +1,71 @@ |
|||||||
|
//
|
||||||
|
// Copyright 2024 gRPC 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GRPC_SRC_CORE_FILTER_BLACKBOARD_H |
||||||
|
#define GRPC_SRC_CORE_FILTER_BLACKBOARD_H |
||||||
|
|
||||||
|
#include <string> |
||||||
|
#include <utility> |
||||||
|
|
||||||
|
#include "absl/container/flat_hash_map.h" |
||||||
|
#include "absl/strings/string_view.h" |
||||||
|
|
||||||
|
#include "src/core/resolver/endpoint_addresses.h" |
||||||
|
#include "src/core/util/debug_location.h" |
||||||
|
#include "src/core/util/ref_counted.h" |
||||||
|
#include "src/core/util/ref_counted_ptr.h" |
||||||
|
#include "src/core/util/unique_type_name.h" |
||||||
|
#include "src/core/util/useful.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
// A blackboard is a place where dynamic filters can stash global state
|
||||||
|
// that they may want to retain across resolver updates. Entries are
|
||||||
|
// identified by by the unique type and a name that identifies the instance,
|
||||||
|
// which means that it's possible for two filter instances to use the same
|
||||||
|
// type (e.g., if there are two instantiations of the same filter).
|
||||||
|
class Blackboard : public RefCounted<Blackboard> { |
||||||
|
public: |
||||||
|
// All entries must derive from this type.
|
||||||
|
// They must also have a static method with the following signature:
|
||||||
|
// static UniqueTypeName Type();
|
||||||
|
class Entry : public RefCounted<Entry> {}; |
||||||
|
|
||||||
|
// Returns an entry for a particular type and name, or null if not present.
|
||||||
|
template <typename T> |
||||||
|
RefCountedPtr<T> Get(const std::string& key) const { |
||||||
|
return Get(T::Type(), key).template TakeAsSubclass<T>(); |
||||||
|
} |
||||||
|
|
||||||
|
// Sets an entry for a particular type and name.
|
||||||
|
template <typename T> |
||||||
|
void Set(const std::string& key, RefCountedPtr<T> entry) { |
||||||
|
Set(T::Type(), key, std::move(entry)); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
RefCountedPtr<Entry> Get(UniqueTypeName type, const std::string& key) const; |
||||||
|
void Set(UniqueTypeName type, const std::string& key, |
||||||
|
RefCountedPtr<Entry> entry); |
||||||
|
|
||||||
|
absl::flat_hash_map<std::pair<UniqueTypeName, std::string>, |
||||||
|
RefCountedPtr<Entry>> |
||||||
|
map_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif // GRPC_SRC_CORE_FILTER_BLACKBOARD_H
|
@ -0,0 +1,66 @@ |
|||||||
|
// Copyright 2024 gRPC 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 "src/core/filter/blackboard.h" |
||||||
|
|
||||||
|
#include "gmock/gmock.h" |
||||||
|
#include "gtest/gtest.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
namespace { |
||||||
|
|
||||||
|
class FooEntry : public Blackboard::Entry { |
||||||
|
public: |
||||||
|
static UniqueTypeName Type() { |
||||||
|
static UniqueTypeName::Factory kFactory("FooEntry"); |
||||||
|
return kFactory.Create(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
class BarEntry : public Blackboard::Entry { |
||||||
|
public: |
||||||
|
static UniqueTypeName Type() { |
||||||
|
static UniqueTypeName::Factory kFactory("BarEntry"); |
||||||
|
return kFactory.Create(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
TEST(Blackboard, Basic) { |
||||||
|
Blackboard blackboard; |
||||||
|
// No entry for type FooEntry key "foo".
|
||||||
|
EXPECT_EQ(blackboard.Get<FooEntry>("a"), nullptr); |
||||||
|
// Set entry for type FooEntry key "foo".
|
||||||
|
auto foo_entry = MakeRefCounted<FooEntry>(); |
||||||
|
blackboard.Set("a", foo_entry); |
||||||
|
// Get the entry we just added.
|
||||||
|
EXPECT_EQ(blackboard.Get<FooEntry>("a"), foo_entry); |
||||||
|
// A different key for the same type is still unset.
|
||||||
|
EXPECT_EQ(blackboard.Get<FooEntry>("b"), nullptr); |
||||||
|
// The same key for a different type is still unset.
|
||||||
|
EXPECT_EQ(blackboard.Get<BarEntry>("a"), nullptr); |
||||||
|
// Set entry for type BarEntry key "foo".
|
||||||
|
auto bar_entry = MakeRefCounted<BarEntry>(); |
||||||
|
blackboard.Set("a", bar_entry); |
||||||
|
EXPECT_EQ(blackboard.Get<BarEntry>("a"), bar_entry); |
||||||
|
// This should not have replaced the same key for FooEntry.
|
||||||
|
EXPECT_EQ(blackboard.Get<FooEntry>("a"), foo_entry); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
::testing::InitGoogleTest(&argc, argv); |
||||||
|
return RUN_ALL_TESTS(); |
||||||
|
} |
Loading…
Reference in new issue