• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2018 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include "src/core/lib/gprpp/mutex_lock.h"
22 #include "src/core/lib/slice/slice_internal.h"
23 #include "src/core/tsi/ssl/session_cache/ssl_session.h"
24 #include "src/core/tsi/ssl/session_cache/ssl_session_cache.h"
25 
26 #include <grpc/support/log.h>
27 #include <grpc/support/string_util.h>
28 
29 namespace tsi {
30 
cache_key_avl_destroy(void * key,void * unused)31 static void cache_key_avl_destroy(void* key, void* unused) {}
32 
cache_key_avl_copy(void * key,void * unused)33 static void* cache_key_avl_copy(void* key, void* unused) { return key; }
34 
cache_key_avl_compare(void * key1,void * key2,void * unused)35 static long cache_key_avl_compare(void* key1, void* key2, void* unused) {
36   return grpc_slice_cmp(*static_cast<grpc_slice*>(key1),
37                         *static_cast<grpc_slice*>(key2));
38 }
39 
cache_value_avl_destroy(void * value,void * unused)40 static void cache_value_avl_destroy(void* value, void* unused) {}
41 
cache_value_avl_copy(void * value,void * unused)42 static void* cache_value_avl_copy(void* value, void* unused) { return value; }
43 
44 // AVL only stores pointers, ownership belonges to the linked list.
45 static const grpc_avl_vtable cache_avl_vtable = {
46     cache_key_avl_destroy,   cache_key_avl_copy,   cache_key_avl_compare,
47     cache_value_avl_destroy, cache_value_avl_copy,
48 };
49 
50 /// Node for single cached session.
51 class SslSessionLRUCache::Node {
52  public:
Node(const grpc_slice & key,SslSessionPtr session)53   Node(const grpc_slice& key, SslSessionPtr session) : key_(key) {
54     SetSession(std::move(session));
55   }
56 
~Node()57   ~Node() { grpc_slice_unref_internal(key_); }
58 
59   // Not copyable nor movable.
60   Node(const Node&) = delete;
61   Node& operator=(const Node&) = delete;
62 
AvlKey()63   void* AvlKey() { return &key_; }
64 
65   /// Returns a copy of the node's cache session.
CopySession() const66   SslSessionPtr CopySession() const { return session_->CopySession(); }
67 
68   /// Set the \a session (which is moved) for the node.
SetSession(SslSessionPtr session)69   void SetSession(SslSessionPtr session) {
70     session_ = SslCachedSession::Create(std::move(session));
71   }
72 
73  private:
74   friend class SslSessionLRUCache;
75 
76   grpc_slice key_;
77   grpc_core::UniquePtr<SslCachedSession> session_;
78 
79   Node* next_ = nullptr;
80   Node* prev_ = nullptr;
81 };
82 
SslSessionLRUCache(size_t capacity)83 SslSessionLRUCache::SslSessionLRUCache(size_t capacity) : capacity_(capacity) {
84   GPR_ASSERT(capacity > 0);
85   gpr_mu_init(&lock_);
86   entry_by_key_ = grpc_avl_create(&cache_avl_vtable);
87 }
88 
~SslSessionLRUCache()89 SslSessionLRUCache::~SslSessionLRUCache() {
90   Node* node = use_order_list_head_;
91   while (node) {
92     Node* next = node->next_;
93     grpc_core::Delete(node);
94     node = next;
95   }
96   grpc_avl_unref(entry_by_key_, nullptr);
97   gpr_mu_destroy(&lock_);
98 }
99 
Size()100 size_t SslSessionLRUCache::Size() {
101   grpc_core::MutexLock lock(&lock_);
102   return use_order_list_size_;
103 }
104 
FindLocked(const grpc_slice & key)105 SslSessionLRUCache::Node* SslSessionLRUCache::FindLocked(
106     const grpc_slice& key) {
107   void* value =
108       grpc_avl_get(entry_by_key_, const_cast<grpc_slice*>(&key), nullptr);
109   if (value == nullptr) {
110     return nullptr;
111   }
112   Node* node = static_cast<Node*>(value);
113   // Move to the beginning.
114   Remove(node);
115   PushFront(node);
116   AssertInvariants();
117   return node;
118 }
119 
Put(const char * key,SslSessionPtr session)120 void SslSessionLRUCache::Put(const char* key, SslSessionPtr session) {
121   grpc_core::MutexLock lock(&lock_);
122   Node* node = FindLocked(grpc_slice_from_static_string(key));
123   if (node != nullptr) {
124     node->SetSession(std::move(session));
125     return;
126   }
127   grpc_slice key_slice = grpc_slice_from_copied_string(key);
128   node = grpc_core::New<Node>(key_slice, std::move(session));
129   PushFront(node);
130   entry_by_key_ = grpc_avl_add(entry_by_key_, node->AvlKey(), node, nullptr);
131   AssertInvariants();
132   if (use_order_list_size_ > capacity_) {
133     GPR_ASSERT(use_order_list_tail_);
134     node = use_order_list_tail_;
135     Remove(node);
136     // Order matters, key is destroyed after deleting node.
137     entry_by_key_ = grpc_avl_remove(entry_by_key_, node->AvlKey(), nullptr);
138     grpc_core::Delete(node);
139     AssertInvariants();
140   }
141 }
142 
Get(const char * key)143 SslSessionPtr SslSessionLRUCache::Get(const char* key) {
144   grpc_core::MutexLock lock(&lock_);
145   // Key is only used for lookups.
146   grpc_slice key_slice = grpc_slice_from_static_string(key);
147   Node* node = FindLocked(key_slice);
148   if (node == nullptr) {
149     return nullptr;
150   }
151   return node->CopySession();
152 }
153 
Remove(SslSessionLRUCache::Node * node)154 void SslSessionLRUCache::Remove(SslSessionLRUCache::Node* node) {
155   if (node->prev_ == nullptr) {
156     use_order_list_head_ = node->next_;
157   } else {
158     node->prev_->next_ = node->next_;
159   }
160   if (node->next_ == nullptr) {
161     use_order_list_tail_ = node->prev_;
162   } else {
163     node->next_->prev_ = node->prev_;
164   }
165   GPR_ASSERT(use_order_list_size_ >= 1);
166   use_order_list_size_--;
167 }
168 
PushFront(SslSessionLRUCache::Node * node)169 void SslSessionLRUCache::PushFront(SslSessionLRUCache::Node* node) {
170   if (use_order_list_head_ == nullptr) {
171     use_order_list_head_ = node;
172     use_order_list_tail_ = node;
173     node->next_ = nullptr;
174     node->prev_ = nullptr;
175   } else {
176     node->next_ = use_order_list_head_;
177     node->next_->prev_ = node;
178     use_order_list_head_ = node;
179     node->prev_ = nullptr;
180   }
181   use_order_list_size_++;
182 }
183 
184 #ifndef NDEBUG
calculate_tree_size(grpc_avl_node * node)185 static size_t calculate_tree_size(grpc_avl_node* node) {
186   if (node == nullptr) {
187     return 0;
188   }
189   return 1 + calculate_tree_size(node->left) + calculate_tree_size(node->right);
190 }
191 
AssertInvariants()192 void SslSessionLRUCache::AssertInvariants() {
193   size_t size = 0;
194   Node* prev = nullptr;
195   Node* current = use_order_list_head_;
196   while (current != nullptr) {
197     size++;
198     GPR_ASSERT(current->prev_ == prev);
199     void* node = grpc_avl_get(entry_by_key_, current->AvlKey(), nullptr);
200     GPR_ASSERT(node == current);
201     prev = current;
202     current = current->next_;
203   }
204   GPR_ASSERT(prev == use_order_list_tail_);
205   GPR_ASSERT(size == use_order_list_size_);
206   GPR_ASSERT(calculate_tree_size(entry_by_key_.root) == use_order_list_size_);
207 }
208 #else
AssertInvariants()209 void SslSessionLRUCache::AssertInvariants() {}
210 #endif
211 
212 }  // namespace tsi
213