mirror of https://github.com/grpc/grpc.git
parent
089d90933a
commit
c35a37d6c2
38 changed files with 120 additions and 1182 deletions
@ -1,75 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 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 <grpc/support/port_platform.h> |
||||
|
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/channel/channel_args.h" |
||||
#include "src/core/lib/security/transport/target_authority_table.h" |
||||
|
||||
// Channel arg key for the mapping of target addresses to their authorities.
|
||||
#define GRPC_ARG_TARGET_AUTHORITY_TABLE "grpc.target_authority_table" |
||||
|
||||
namespace grpc_core { |
||||
namespace { |
||||
|
||||
void* target_authority_table_copy(void* p) { |
||||
TargetAuthorityTable* table = static_cast<TargetAuthorityTable*>(p); |
||||
// TODO(roth): When channel_args are converted to C++, pass the
|
||||
// RefCountedPtr<> directly instead of managing the ref manually.
|
||||
table->Ref().release(); |
||||
return p; |
||||
} |
||||
void target_authority_table_destroy(void* p) { |
||||
TargetAuthorityTable* table = static_cast<TargetAuthorityTable*>(p); |
||||
table->Unref(); |
||||
} |
||||
int target_authority_table_cmp(void* a, void* b) { |
||||
return TargetAuthorityTable::Cmp( |
||||
*static_cast<const TargetAuthorityTable*>(a), |
||||
*static_cast<const TargetAuthorityTable*>(b)); |
||||
} |
||||
const grpc_arg_pointer_vtable target_authority_table_arg_vtable = { |
||||
target_authority_table_copy, target_authority_table_destroy, |
||||
target_authority_table_cmp}; |
||||
|
||||
} // namespace
|
||||
|
||||
grpc_arg CreateTargetAuthorityTableChannelArg(TargetAuthorityTable* table) { |
||||
return grpc_channel_arg_pointer_create((char*)GRPC_ARG_TARGET_AUTHORITY_TABLE, |
||||
table, |
||||
&target_authority_table_arg_vtable); |
||||
} |
||||
|
||||
TargetAuthorityTable* FindTargetAuthorityTableInArgs( |
||||
const grpc_channel_args* args) { |
||||
const grpc_arg* arg = |
||||
grpc_channel_args_find(args, GRPC_ARG_TARGET_AUTHORITY_TABLE); |
||||
if (arg != nullptr) { |
||||
if (arg->type == GRPC_ARG_POINTER) { |
||||
return static_cast<TargetAuthorityTable*>(arg->value.pointer.p); |
||||
} else { |
||||
gpr_log(GPR_ERROR, "value of " GRPC_ARG_TARGET_AUTHORITY_TABLE |
||||
" channel arg was not pointer type; ignoring"); |
||||
} |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
} // namespace grpc_core
|
@ -1,40 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 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_CORE_LIB_SECURITY_TRANSPORT_TARGET_AUTHORITY_TABLE_H |
||||
#define GRPC_CORE_LIB_SECURITY_TRANSPORT_TARGET_AUTHORITY_TABLE_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/slice/slice_hash_table.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
/// A hash table mapping target addresses to authorities.
|
||||
typedef SliceHashTable<grpc_core::UniquePtr<char>> TargetAuthorityTable; |
||||
|
||||
/// Returns a channel argument containing \a table.
|
||||
grpc_arg CreateTargetAuthorityTableChannelArg(TargetAuthorityTable* table); |
||||
|
||||
/// Returns the target authority table from \a args or nullptr.
|
||||
TargetAuthorityTable* FindTargetAuthorityTableInArgs( |
||||
const grpc_channel_args* args); |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_TARGET_AUTHORITY_TABLE_H */ |
@ -1,199 +0,0 @@ |
||||
/*
|
||||
* Copyright 2016 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_CORE_LIB_SLICE_SLICE_HASH_TABLE_H |
||||
#define GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/gpr/useful.h" |
||||
#include "src/core/lib/gprpp/memory.h" |
||||
#include "src/core/lib/gprpp/ref_counted.h" |
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
||||
#include "src/core/lib/slice/slice_internal.h" |
||||
|
||||
/// Hash table implementation.
|
||||
///
|
||||
/// This implementation uses open addressing
|
||||
/// (https://en.wikipedia.org/wiki/Open_addressing) with linear
|
||||
/// probing (https://en.wikipedia.org/wiki/Linear_probing).
|
||||
///
|
||||
/// The keys are \a grpc_slice objects. The values can be any type.
|
||||
///
|
||||
/// Hash tables are intentionally immutable, to avoid the need for locking.
|
||||
|
||||
namespace grpc_core { |
||||
|
||||
template <typename T> |
||||
class SliceHashTable : public RefCounted<SliceHashTable<T>> { |
||||
public: |
||||
struct Entry { |
||||
grpc_slice key; |
||||
T value; |
||||
bool is_set; |
||||
}; |
||||
|
||||
// Function for comparing values.
|
||||
// TODO(roth): Eliminate this and the Cmp() method from this API once
|
||||
// grpc_channel_args is redesigned to require that keys are unique.
|
||||
typedef int (*ValueCmp)(const T&, const T&); |
||||
|
||||
/// Creates a new hash table containing \a entries, which is an array
|
||||
/// of length \a num_entries. Takes ownership of all keys and values in \a
|
||||
/// entries. If not null, \a value_cmp will be used to compare values in
|
||||
/// the context of \a Cmp(). If null, raw pointer (\a GPR_ICMP) comparison
|
||||
/// will be used.
|
||||
static RefCountedPtr<SliceHashTable> Create(size_t num_entries, |
||||
Entry* entries, |
||||
ValueCmp value_cmp); |
||||
|
||||
// Use Create function instead of using this directly.
|
||||
SliceHashTable(size_t num_entries, Entry* entries, ValueCmp value_cmp); |
||||
virtual ~SliceHashTable(); |
||||
|
||||
/// Returns the value from the table associated with \a key.
|
||||
/// Returns null if \a key is not found.
|
||||
const T* Get(const grpc_slice& key) const; |
||||
|
||||
/// Compares \a a vs. \a b.
|
||||
/// A table is considered "smaller" (resp. "greater") if:
|
||||
/// - GPR_ICMP(a->value_cmp, b->value_cmp) < 1 (resp. > 1),
|
||||
/// - else, it contains fewer (resp. more) entries,
|
||||
/// - else, if strcmp(a_key, b_key) < 1 (resp. > 1),
|
||||
/// - else, if value_cmp(a_value, b_value) < 1 (resp. > 1).
|
||||
static int Cmp(const SliceHashTable& a, const SliceHashTable& b); |
||||
|
||||
private: |
||||
void Add(const grpc_slice& key, T& value); |
||||
|
||||
// Default value comparison function, if none specified by caller.
|
||||
static int DefaultValueCmp(const T& a, const T& b) { return GPR_ICMP(a, b); } |
||||
|
||||
const ValueCmp value_cmp_; |
||||
const size_t size_; |
||||
size_t max_num_probes_; |
||||
Entry* entries_; |
||||
}; |
||||
|
||||
//
|
||||
// implementation -- no user-serviceable parts below
|
||||
//
|
||||
|
||||
template <typename T> |
||||
RefCountedPtr<SliceHashTable<T>> SliceHashTable<T>::Create(size_t num_entries, |
||||
Entry* entries, |
||||
ValueCmp value_cmp) { |
||||
return MakeRefCounted<SliceHashTable<T>>(num_entries, entries, value_cmp); |
||||
} |
||||
|
||||
template <typename T> |
||||
SliceHashTable<T>::SliceHashTable(size_t num_entries, Entry* entries, |
||||
ValueCmp value_cmp) |
||||
: value_cmp_(value_cmp), |
||||
// Keep load factor low to improve performance of lookups.
|
||||
size_(num_entries * 2), |
||||
max_num_probes_(0) { |
||||
entries_ = static_cast<Entry*>(gpr_zalloc(sizeof(Entry) * size_)); |
||||
for (size_t i = 0; i < num_entries; ++i) { |
||||
Entry* entry = &entries[i]; |
||||
Add(entry->key, entry->value); |
||||
} |
||||
} |
||||
|
||||
template <typename T> |
||||
SliceHashTable<T>::~SliceHashTable() { |
||||
for (size_t i = 0; i < size_; ++i) { |
||||
Entry& entry = entries_[i]; |
||||
if (entry.is_set) { |
||||
grpc_slice_unref_internal(entry.key); |
||||
entry.value.~T(); |
||||
} |
||||
} |
||||
gpr_free(entries_); |
||||
} |
||||
|
||||
template <typename T> |
||||
void SliceHashTable<T>::Add(const grpc_slice& key, T& value) { |
||||
const size_t hash = grpc_slice_hash_internal(key); |
||||
for (size_t offset = 0; offset < size_; ++offset) { |
||||
const size_t idx = (hash + offset) % size_; |
||||
if (!entries_[idx].is_set) { |
||||
entries_[idx].is_set = true; |
||||
entries_[idx].key = key; |
||||
entries_[idx].value = std::move(value); |
||||
// Keep track of the maximum number of probes needed, since this
|
||||
// provides an upper bound for lookups.
|
||||
if (offset > max_num_probes_) max_num_probes_ = offset; |
||||
return; |
||||
} |
||||
} |
||||
GPR_ASSERT(false); // Table should never be full.
|
||||
} |
||||
|
||||
template <typename T> |
||||
const T* SliceHashTable<T>::Get(const grpc_slice& key) const { |
||||
const size_t hash = grpc_slice_hash_internal(key); |
||||
// We cap the number of probes at the max number recorded when
|
||||
// populating the table.
|
||||
for (size_t offset = 0; offset <= max_num_probes_; ++offset) { |
||||
const size_t idx = (hash + offset) % size_; |
||||
if (!entries_[idx].is_set) break; |
||||
if (grpc_slice_eq(entries_[idx].key, key)) { |
||||
return &entries_[idx].value; |
||||
} |
||||
} |
||||
return nullptr; // Not found.
|
||||
} |
||||
|
||||
template <typename T> |
||||
int SliceHashTable<T>::Cmp(const SliceHashTable& a, const SliceHashTable& b) { |
||||
ValueCmp value_cmp_a = |
||||
a.value_cmp_ != nullptr ? a.value_cmp_ : DefaultValueCmp; |
||||
ValueCmp value_cmp_b = |
||||
b.value_cmp_ != nullptr ? b.value_cmp_ : DefaultValueCmp; |
||||
// Compare value_fns
|
||||
const int value_fns_cmp = GPR_ICMP((void*)value_cmp_a, (void*)value_cmp_b); |
||||
if (value_fns_cmp != 0) return value_fns_cmp; |
||||
// Compare sizes
|
||||
if (a.size_ < b.size_) return -1; |
||||
if (a.size_ > b.size_) return 1; |
||||
// Compare rows.
|
||||
for (size_t i = 0; i < a.size_; ++i) { |
||||
if (!a.entries_[i].is_set) { |
||||
if (b.entries_[i].is_set) { |
||||
return -1; // a empty but b non-empty
|
||||
} |
||||
continue; // both empty, no need to check key or value
|
||||
} else if (!b.entries_[i].is_set) { |
||||
return 1; // a non-empty but b empty
|
||||
} |
||||
// neither entry is empty
|
||||
const int key_cmp = grpc_slice_cmp(a.entries_[i].key, b.entries_[i].key); |
||||
if (key_cmp != 0) return key_cmp; |
||||
const int value_cmp = value_cmp_a(a.entries_[i].value, b.entries_[i].value); |
||||
if (value_cmp != 0) return value_cmp; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H */ |
@ -1,102 +0,0 @@ |
||||
/*
|
||||
* Copyright 2016 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_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H |
||||
#define GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/gprpp/memory.h" |
||||
#include "src/core/lib/gprpp/ref_counted.h" |
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
||||
#include "src/core/lib/slice/slice_internal.h" |
||||
|
||||
/// Weak hash table implementation.
|
||||
///
|
||||
/// This entries in this table are weak: an entry may be removed at any time due
|
||||
/// to a number of reasons: memory pressure, hash collisions, etc.
|
||||
///
|
||||
/// The keys are \a grpc_slice objects. The values are of arbitrary type.
|
||||
///
|
||||
/// This class is thread unsafe. It's the caller's responsibility to ensure
|
||||
/// proper locking when accessing its methods.
|
||||
|
||||
namespace grpc_core { |
||||
|
||||
template <typename T, size_t Size> |
||||
class SliceWeakHashTable : public RefCounted<SliceWeakHashTable<T, Size>> { |
||||
public: |
||||
/// Creates a new table of at most \a size entries.
|
||||
static RefCountedPtr<SliceWeakHashTable> Create() { |
||||
return MakeRefCounted<SliceWeakHashTable<T, Size>>(); |
||||
} |
||||
|
||||
/// Use Create function instead of using this directly.
|
||||
SliceWeakHashTable() = default; |
||||
~SliceWeakHashTable() = default; |
||||
|
||||
/// Add a mapping from \a key to \a value, taking ownership of \a key. This
|
||||
/// operation will always succeed. It may discard older entries.
|
||||
void Add(const grpc_slice& key, T value) { |
||||
const size_t idx = grpc_slice_hash_internal(key) % Size; |
||||
entries_[idx].Set(key, std::move(value)); |
||||
return; |
||||
} |
||||
|
||||
/// Returns the value from the table associated with / \a key or null if not
|
||||
/// found.
|
||||
const T* Get(const grpc_slice& key) const { |
||||
const size_t idx = grpc_slice_hash_internal(key) % Size; |
||||
const auto& entry = entries_[idx]; |
||||
return grpc_slice_eq(entry.key(), key) ? entry.value() : nullptr; |
||||
} |
||||
|
||||
private: |
||||
/// The type of the table "rows".
|
||||
class Entry { |
||||
public: |
||||
Entry() = default; |
||||
~Entry() { |
||||
if (is_set_) grpc_slice_unref_internal(key_); |
||||
} |
||||
const grpc_slice& key() const { return key_; } |
||||
|
||||
/// Return the entry's value, or null if unset.
|
||||
const T* value() const { |
||||
if (!is_set_) return nullptr; |
||||
return &value_; |
||||
} |
||||
|
||||
/// Set the \a key and \a value (which is moved) for the entry.
|
||||
void Set(const grpc_slice& key, T&& value) { |
||||
if (is_set_) grpc_slice_unref_internal(key_); |
||||
key_ = key; |
||||
value_ = std::move(value); |
||||
is_set_ = true; |
||||
} |
||||
|
||||
private: |
||||
grpc_slice key_; |
||||
T value_; |
||||
bool is_set_ = false; |
||||
}; |
||||
|
||||
Entry entries_[Size]; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H */ |
@ -0,0 +1,38 @@ |
||||
//
|
||||
// Copyright 2020 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 <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/channel/channel_args.h" |
||||
|
||||
// Channel arg key for the authority override.
|
||||
#define GRPC_ARG_AUTHORITY_OVERRIDE "grpc.authority_override" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
/// Returns a channel argument containing \a authority.
|
||||
grpc_arg CreateAuthorityOverrideChannelArg(const char* authority) { |
||||
return grpc_channel_arg_string_create( |
||||
const_cast<char*>(GRPC_ARG_AUTHORITY_OVERRIDE), |
||||
const_cast<char*>(authority)); |
||||
} |
||||
|
||||
/// Returns the authority override from \a args or nullptr.
|
||||
const char* FindAuthorityOverrideInArgs(const grpc_channel_args* args) { |
||||
return grpc_channel_args_find_string(args, GRPC_ARG_AUTHORITY_OVERRIDE); |
||||
} |
||||
|
||||
} // namespace grpc_core
|
@ -0,0 +1,32 @@ |
||||
//
|
||||
// Copyright 2020 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_CORE_LIB_TRANSPORT_AUTHORITY_OVERRIDE_H |
||||
#define GRPC_CORE_LIB_TRANSPORT_AUTHORITY_OVERRIDE_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
namespace grpc_core { |
||||
|
||||
/// Returns a channel argument containing \a authority.
|
||||
grpc_arg CreateAuthorityOverrideChannelArg(const char* authority); |
||||
|
||||
/// Returns the authority override from \a args or nullptr.
|
||||
const char* FindAuthorityOverrideInArgs(const grpc_channel_args* args); |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_LIB_TRANSPORT_AUTHORITY_OVERRIDE_H */ |
@ -1,227 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 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/lib/slice/slice_hash_table.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <vector> |
||||
|
||||
#include <gtest/gtest.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/iomgr/exec_ctx.h" |
||||
#include "src/core/lib/slice/slice_internal.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
namespace grpc_core { |
||||
namespace { |
||||
|
||||
typedef SliceHashTable<grpc_core::UniquePtr<char>> TestHashTable; |
||||
|
||||
struct TestEntry { |
||||
const char* key; |
||||
const char* value; |
||||
}; |
||||
|
||||
void CheckValues(const std::vector<TestEntry>& input, |
||||
const TestHashTable& table) { |
||||
for (const TestEntry& expected : input) { |
||||
grpc_slice key = grpc_slice_from_static_string(expected.key); |
||||
const grpc_core::UniquePtr<char>* actual = table.Get(key); |
||||
ASSERT_NE(actual, nullptr); |
||||
EXPECT_STREQ(expected.value, actual->get()); |
||||
grpc_slice_unref(key); |
||||
} |
||||
} |
||||
|
||||
void CheckNonExistentValue(const char* key_string, const TestHashTable& table) { |
||||
grpc_slice key = grpc_slice_from_static_string(key_string); |
||||
ASSERT_EQ(nullptr, table.Get(key)); |
||||
grpc_slice_unref(key); |
||||
} |
||||
|
||||
void PopulateEntries(const std::vector<TestEntry>& input, |
||||
TestHashTable::Entry* output) { |
||||
for (size_t i = 0; i < input.size(); ++i) { |
||||
output[i].key = grpc_slice_from_copied_string(input[i].key); |
||||
output[i].value = grpc_core::UniquePtr<char>(gpr_strdup(input[i].value)); |
||||
} |
||||
} |
||||
|
||||
RefCountedPtr<TestHashTable> CreateTableFromEntries( |
||||
const std::vector<TestEntry>& test_entries, |
||||
TestHashTable::ValueCmp value_cmp) { |
||||
TestHashTable::Entry* entries = static_cast<TestHashTable::Entry*>( |
||||
gpr_zalloc(sizeof(*entries) * test_entries.size())); |
||||
PopulateEntries(test_entries, entries); |
||||
RefCountedPtr<TestHashTable> table = |
||||
TestHashTable::Create(test_entries.size(), entries, value_cmp); |
||||
gpr_free(entries); |
||||
return table; |
||||
} |
||||
|
||||
TEST(SliceHashTable, Basic) { |
||||
const std::vector<TestEntry> test_entries = { |
||||
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}, |
||||
{"key_3", "value_3"}, {"key_4", "value_4"}, {"key_5", "value_5"}, |
||||
{"key_6", "value_6"}, {"key_7", "value_7"}, {"key_8", "value_8"}, |
||||
{"key_9", "value_9"}, {"key_10", "value_10"}, {"key_11", "value_11"}, |
||||
{"key_12", "value_12"}, {"key_13", "value_13"}, {"key_14", "value_14"}, |
||||
{"key_15", "value_15"}, {"key_16", "value_16"}, {"key_17", "value_17"}, |
||||
{"key_18", "value_18"}, {"key_19", "value_19"}, {"key_20", "value_20"}, |
||||
{"key_21", "value_21"}, {"key_22", "value_22"}, {"key_23", "value_23"}, |
||||
{"key_24", "value_24"}, {"key_25", "value_25"}, {"key_26", "value_26"}, |
||||
{"key_27", "value_27"}, {"key_28", "value_28"}, {"key_29", "value_29"}, |
||||
{"key_30", "value_30"}, {"key_31", "value_31"}, {"key_32", "value_32"}, |
||||
{"key_33", "value_33"}, {"key_34", "value_34"}, {"key_35", "value_35"}, |
||||
{"key_36", "value_36"}, {"key_37", "value_37"}, {"key_38", "value_38"}, |
||||
{"key_39", "value_39"}, {"key_40", "value_40"}, {"key_41", "value_41"}, |
||||
{"key_42", "value_42"}, {"key_43", "value_43"}, {"key_44", "value_44"}, |
||||
{"key_45", "value_45"}, {"key_46", "value_46"}, {"key_47", "value_47"}, |
||||
{"key_48", "value_48"}, {"key_49", "value_49"}, {"key_50", "value_50"}, |
||||
{"key_51", "value_51"}, {"key_52", "value_52"}, {"key_53", "value_53"}, |
||||
{"key_54", "value_54"}, {"key_55", "value_55"}, {"key_56", "value_56"}, |
||||
{"key_57", "value_57"}, {"key_58", "value_58"}, {"key_59", "value_59"}, |
||||
{"key_60", "value_60"}, {"key_61", "value_61"}, {"key_62", "value_62"}, |
||||
{"key_63", "value_63"}, {"key_64", "value_64"}, {"key_65", "value_65"}, |
||||
{"key_66", "value_66"}, {"key_67", "value_67"}, {"key_68", "value_68"}, |
||||
{"key_69", "value_69"}, {"key_70", "value_70"}, {"key_71", "value_71"}, |
||||
{"key_72", "value_72"}, {"key_73", "value_73"}, {"key_74", "value_74"}, |
||||
{"key_75", "value_75"}, {"key_76", "value_76"}, {"key_77", "value_77"}, |
||||
{"key_78", "value_78"}, {"key_79", "value_79"}, {"key_80", "value_80"}, |
||||
{"key_81", "value_81"}, {"key_82", "value_82"}, {"key_83", "value_83"}, |
||||
{"key_84", "value_84"}, {"key_85", "value_85"}, {"key_86", "value_86"}, |
||||
{"key_87", "value_87"}, {"key_88", "value_88"}, {"key_89", "value_89"}, |
||||
{"key_90", "value_90"}, {"key_91", "value_91"}, {"key_92", "value_92"}, |
||||
{"key_93", "value_93"}, {"key_94", "value_94"}, {"key_95", "value_95"}, |
||||
{"key_96", "value_96"}, {"key_97", "value_97"}, {"key_98", "value_98"}, |
||||
{"key_99", "value_99"}, |
||||
}; |
||||
RefCountedPtr<TestHashTable> table = |
||||
CreateTableFromEntries(test_entries, nullptr); |
||||
// Check contents of table.
|
||||
CheckValues(test_entries, *table); |
||||
CheckNonExistentValue("XX", *table); |
||||
} |
||||
|
||||
int StringCmp(const grpc_core::UniquePtr<char>& a, |
||||
const grpc_core::UniquePtr<char>& b) { |
||||
return strcmp(a.get(), b.get()); |
||||
} |
||||
|
||||
int PointerCmp(const grpc_core::UniquePtr<char>& a, |
||||
const grpc_core::UniquePtr<char>& b) { |
||||
return GPR_ICMP(a.get(), b.get()); |
||||
} |
||||
|
||||
TEST(SliceHashTable, CmpEqual) { |
||||
const std::vector<TestEntry> test_entries_a = { |
||||
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}}; |
||||
RefCountedPtr<TestHashTable> table_a = |
||||
CreateTableFromEntries(test_entries_a, StringCmp); |
||||
const std::vector<TestEntry> test_entries_b = { |
||||
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}}; |
||||
RefCountedPtr<TestHashTable> table_b = |
||||
CreateTableFromEntries(test_entries_b, StringCmp); |
||||
// table_a equals itself.
|
||||
EXPECT_EQ(0, TestHashTable::Cmp(*table_a, *table_a)); |
||||
// table_a equals table_b.
|
||||
EXPECT_EQ(0, TestHashTable::Cmp(*table_a, *table_b)); |
||||
} |
||||
|
||||
TEST(SliceHashTable, CmpDifferentSizes) { |
||||
// table_a has 3 entries, table_b has only 2.
|
||||
const std::vector<TestEntry> test_entries_a = { |
||||
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}}; |
||||
RefCountedPtr<TestHashTable> table_a = |
||||
CreateTableFromEntries(test_entries_a, StringCmp); |
||||
const std::vector<TestEntry> test_entries_b = {{"key_0", "value_0"}, |
||||
{"key_1", "value_1"}}; |
||||
RefCountedPtr<TestHashTable> table_b = |
||||
CreateTableFromEntries(test_entries_b, StringCmp); |
||||
EXPECT_GT(TestHashTable::Cmp(*table_a, *table_b), 0); |
||||
EXPECT_LT(TestHashTable::Cmp(*table_b, *table_a), 0); |
||||
} |
||||
|
||||
TEST(SliceHashTable, CmpDifferentKey) { |
||||
// One key doesn't match and is lexicographically "smaller".
|
||||
const std::vector<TestEntry> test_entries_a = { |
||||
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}}; |
||||
RefCountedPtr<TestHashTable> table_a = |
||||
CreateTableFromEntries(test_entries_a, StringCmp); |
||||
const std::vector<TestEntry> test_entries_b = { |
||||
{"key_zz", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}}; |
||||
RefCountedPtr<TestHashTable> table_b = |
||||
CreateTableFromEntries(test_entries_b, StringCmp); |
||||
EXPECT_GT(TestHashTable::Cmp(*table_a, *table_b), 0); |
||||
EXPECT_LT(TestHashTable::Cmp(*table_b, *table_a), 0); |
||||
} |
||||
|
||||
TEST(SliceHashTable, CmpDifferentValue) { |
||||
// One value doesn't match.
|
||||
const std::vector<TestEntry> test_entries_a = { |
||||
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}}; |
||||
RefCountedPtr<TestHashTable> table_a = |
||||
CreateTableFromEntries(test_entries_a, StringCmp); |
||||
const std::vector<TestEntry> test_entries_b = { |
||||
{"key_0", "value_z"}, {"key_1", "value_1"}, {"key_2", "value_2"}}; |
||||
RefCountedPtr<TestHashTable> table_b = |
||||
CreateTableFromEntries(test_entries_b, StringCmp); |
||||
EXPECT_LT(TestHashTable::Cmp(*table_a, *table_b), 0); |
||||
EXPECT_GT(TestHashTable::Cmp(*table_b, *table_a), 0); |
||||
} |
||||
|
||||
TEST(SliceHashTable, CmpDifferentCmpFunctions) { |
||||
// Same values but different "equals" functions.
|
||||
const std::vector<TestEntry> test_entries_a = { |
||||
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}}; |
||||
RefCountedPtr<TestHashTable> table_a = |
||||
CreateTableFromEntries(test_entries_a, StringCmp); |
||||
const std::vector<TestEntry> test_entries_b = { |
||||
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}}; |
||||
RefCountedPtr<TestHashTable> table_b = |
||||
CreateTableFromEntries(test_entries_b, PointerCmp); |
||||
EXPECT_NE(TestHashTable::Cmp(*table_a, *table_b), 0); |
||||
} |
||||
|
||||
TEST(SliceHashTable, CmpEmptyKeysDifferentValue) { |
||||
// Same (empty) key, different values.
|
||||
const std::vector<TestEntry> test_entries_a = {{"", "value_0"}}; |
||||
RefCountedPtr<TestHashTable> table_a = |
||||
CreateTableFromEntries(test_entries_a, StringCmp); |
||||
const std::vector<TestEntry> test_entries_b = {{"", "value_1"}}; |
||||
RefCountedPtr<TestHashTable> table_b = |
||||
CreateTableFromEntries(test_entries_b, PointerCmp); |
||||
EXPECT_NE(TestHashTable::Cmp(*table_a, *table_b), 0); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char** argv) { |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
grpc::testing::TestEnvironment env(argc, argv); |
||||
grpc_core::ExecCtx::GlobalInit(); |
||||
int result = RUN_ALL_TESTS(); |
||||
grpc_core::ExecCtx::GlobalShutdown(); |
||||
return result; |
||||
} |
@ -1,107 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 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/lib/slice/slice_weak_hash_table.h" |
||||
|
||||
#include <cstring> |
||||
#include <sstream> |
||||
|
||||
#include <gtest/gtest.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/gpr/useful.h" |
||||
#include "src/core/lib/iomgr/exec_ctx.h" |
||||
#include "src/core/lib/slice/slice_internal.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
namespace grpc_core { |
||||
namespace { |
||||
|
||||
grpc_slice BuildRefCountedKey(const char* key_str) { |
||||
const size_t key_length = strlen(key_str); |
||||
grpc_slice key = grpc_slice_malloc_large(key_length); |
||||
memcpy(GRPC_SLICE_START_PTR(key), key_str, key_length); |
||||
return key; |
||||
} |
||||
|
||||
TEST(SliceWeakHashTable, Basic) { |
||||
auto table = SliceWeakHashTable<grpc_core::UniquePtr<char>, 10>::Create(); |
||||
// Single key-value insertion.
|
||||
grpc_slice key = BuildRefCountedKey("key"); |
||||
grpc_slice_ref(key); // Get doesn't own.
|
||||
table->Add(key, grpc_core::UniquePtr<char>(gpr_strdup("value"))); |
||||
ASSERT_NE(table->Get(key), nullptr); |
||||
ASSERT_STREQ(table->Get(key)->get(), "value"); |
||||
grpc_slice_unref(key); |
||||
// Unknown key.
|
||||
ASSERT_EQ(table->Get(grpc_slice_from_static_string("unknown_key")), nullptr); |
||||
} |
||||
|
||||
TEST(SliceWeakHashTable, ValueTypeConstructor) { |
||||
struct Value { |
||||
Value() : a(123) {} |
||||
int a; |
||||
}; |
||||
auto table = SliceWeakHashTable<Value, 1>::Create(); |
||||
grpc_slice key = BuildRefCountedKey("key"); |
||||
grpc_slice_ref(key); // Get doesn't own.
|
||||
table->Add(key, Value()); |
||||
ASSERT_EQ(table->Get(key)->a, 123); |
||||
grpc_slice_unref(key); |
||||
} |
||||
|
||||
TEST(SliceWeakHashTable, ForceOverload) { |
||||
constexpr int kTableSize = 10; |
||||
auto table = |
||||
SliceWeakHashTable<grpc_core::UniquePtr<char>, kTableSize>::Create(); |
||||
// Insert a multiple of the maximum size table.
|
||||
for (int i = 0; i < kTableSize * 2; ++i) { |
||||
std::ostringstream oss; |
||||
oss << "key-" << i; |
||||
grpc_slice key = BuildRefCountedKey(oss.str().c_str()); |
||||
oss.clear(); |
||||
oss << "value-" << i; |
||||
table->Add(key, grpc_core::UniquePtr<char>(gpr_strdup(oss.str().c_str()))); |
||||
} |
||||
// Verify that some will have been replaced.
|
||||
int num_missing = 0; |
||||
for (int i = 0; i < kTableSize * 2; ++i) { |
||||
std::ostringstream oss; |
||||
oss << "key-" << i; |
||||
grpc_slice key = BuildRefCountedKey(oss.str().c_str()); |
||||
if (table->Get(key) == nullptr) num_missing++; |
||||
grpc_slice_unref(key); |
||||
} |
||||
// At least kTableSize elements will be missing.
|
||||
ASSERT_GE(num_missing, kTableSize); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char** argv) { |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
grpc::testing::TestEnvironment env(argc, argv); |
||||
grpc_core::ExecCtx::GlobalInit(); |
||||
int result = RUN_ALL_TESTS(); |
||||
grpc_core::ExecCtx::GlobalShutdown(); |
||||
return result; |
||||
} |
Loading…
Reference in new issue