blob: 219567f36f8049aed864ed9f9dc35557a9f4ab1e [file] [log] [blame]
Craig Tiller5ef31ab2016-11-10 16:27:48 -08001//
2// Copyright 2016, Google Inc.
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30//
31
Craig Tiller7c70b6c2017-01-23 07:48:42 -080032#include "src/core/lib/slice/slice_hash_table.h"
Craig Tiller5ef31ab2016-11-10 16:27:48 -080033
34#include <stdbool.h>
35#include <string.h>
36
37#include <grpc/support/alloc.h>
38#include <grpc/support/log.h>
39
Craig Tiller7c70b6c2017-01-23 07:48:42 -080040#include "src/core/lib/slice/slice_internal.h"
Craig Tiller5ef31ab2016-11-10 16:27:48 -080041#include "src/core/lib/transport/metadata.h"
42
Craig Tiller7c70b6c2017-01-23 07:48:42 -080043struct grpc_slice_hash_table {
Craig Tiller5ef31ab2016-11-10 16:27:48 -080044 gpr_refcount refs;
Craig Tiller5ef31ab2016-11-10 16:27:48 -080045 size_t size;
Craig Tiller7c70b6c2017-01-23 07:48:42 -080046 grpc_slice_hash_table_entry* entries;
Craig Tiller5ef31ab2016-11-10 16:27:48 -080047};
48
Craig Tiller7c70b6c2017-01-23 07:48:42 -080049static bool is_empty(grpc_slice_hash_table_entry* entry) {
50 return entry->vtable == NULL;
51}
52
Craig Tiller5ef31ab2016-11-10 16:27:48 -080053// Helper function for insert and get operations that performs quadratic
54// probing (https://en.wikipedia.org/wiki/Quadratic_probing).
Craig Tiller7c70b6c2017-01-23 07:48:42 -080055static size_t grpc_slice_hash_table_find_index(
56 const grpc_slice_hash_table* table, const grpc_slice key, bool find_empty) {
57 size_t hash = grpc_slice_hash(key);
Craig Tiller5ef31ab2016-11-10 16:27:48 -080058 for (size_t i = 0; i < table->size; ++i) {
Craig Tiller7c70b6c2017-01-23 07:48:42 -080059 const size_t idx = (hash + i * i) % table->size;
60 if (is_empty(&table->entries[idx])) {
61 return find_empty ? idx : table->size;
62 }
63 if (grpc_slice_eq(table->entries[idx].key, key)) {
64 return idx;
65 }
Craig Tiller5ef31ab2016-11-10 16:27:48 -080066 }
67 return table->size; // Not found.
68}
69
Craig Tiller7c70b6c2017-01-23 07:48:42 -080070static void grpc_slice_hash_table_add(
71 grpc_slice_hash_table* table, grpc_slice key, void* value,
72 const grpc_slice_hash_table_vtable* vtable) {
Craig Tiller5ef31ab2016-11-10 16:27:48 -080073 GPR_ASSERT(value != NULL);
74 const size_t idx =
Craig Tiller7c70b6c2017-01-23 07:48:42 -080075 grpc_slice_hash_table_find_index(table, key, true /* find_empty */);
Craig Tiller5ef31ab2016-11-10 16:27:48 -080076 GPR_ASSERT(idx != table->size); // Table should never be full.
Craig Tiller7c70b6c2017-01-23 07:48:42 -080077 grpc_slice_hash_table_entry* entry = &table->entries[idx];
78 entry->key = grpc_slice_ref_internal(key);
Craig Tiller5ef31ab2016-11-10 16:27:48 -080079 entry->value = vtable->copy_value(value);
80 entry->vtable = vtable;
81}
82
Craig Tiller7c70b6c2017-01-23 07:48:42 -080083grpc_slice_hash_table* grpc_slice_hash_table_create(
84 size_t num_entries, grpc_slice_hash_table_entry* entries) {
Craig Tiller6f417882017-02-16 14:09:39 -080085 grpc_slice_hash_table* table = gpr_zalloc(sizeof(*table));
Craig Tiller5ef31ab2016-11-10 16:27:48 -080086 gpr_ref_init(&table->refs, 1);
Craig Tiller5ef31ab2016-11-10 16:27:48 -080087 // Quadratic probing gets best performance when the table is no more
88 // than half full.
89 table->size = num_entries * 2;
Craig Tiller7c70b6c2017-01-23 07:48:42 -080090 const size_t entry_size = sizeof(grpc_slice_hash_table_entry) * table->size;
Craig Tiller6f417882017-02-16 14:09:39 -080091 table->entries = gpr_zalloc(entry_size);
Craig Tiller5ef31ab2016-11-10 16:27:48 -080092 for (size_t i = 0; i < num_entries; ++i) {
Craig Tiller7c70b6c2017-01-23 07:48:42 -080093 grpc_slice_hash_table_entry* entry = &entries[i];
94 grpc_slice_hash_table_add(table, entry->key, entry->value, entry->vtable);
Craig Tiller5ef31ab2016-11-10 16:27:48 -080095 }
96 return table;
97}
98
Craig Tiller7c70b6c2017-01-23 07:48:42 -080099grpc_slice_hash_table* grpc_slice_hash_table_ref(grpc_slice_hash_table* table) {
Craig Tiller5ef31ab2016-11-10 16:27:48 -0800100 if (table != NULL) gpr_ref(&table->refs);
101 return table;
102}
103
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800104void grpc_slice_hash_table_unref(grpc_exec_ctx* exec_ctx,
105 grpc_slice_hash_table* table) {
Craig Tiller5ef31ab2016-11-10 16:27:48 -0800106 if (table != NULL && gpr_unref(&table->refs)) {
107 for (size_t i = 0; i < table->size; ++i) {
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800108 grpc_slice_hash_table_entry* entry = &table->entries[i];
109 if (!is_empty(entry)) {
110 grpc_slice_unref_internal(exec_ctx, entry->key);
Craig Tiller5ef31ab2016-11-10 16:27:48 -0800111 entry->vtable->destroy_value(exec_ctx, entry->value);
112 }
113 }
114 gpr_free(table->entries);
115 gpr_free(table);
Craig Tiller5ef31ab2016-11-10 16:27:48 -0800116 }
Craig Tiller5ef31ab2016-11-10 16:27:48 -0800117}
118
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800119void* grpc_slice_hash_table_get(const grpc_slice_hash_table* table,
120 const grpc_slice key) {
Craig Tiller5ef31ab2016-11-10 16:27:48 -0800121 const size_t idx =
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800122 grpc_slice_hash_table_find_index(table, key, false /* find_empty */);
Craig Tiller5ef31ab2016-11-10 16:27:48 -0800123 if (idx == table->size) return NULL; // Not found.
124 return table->entries[idx].value;
125}