2 // Copyright (c) 2010-2017 Intel Corporation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
17 #include <rte_hash_crc.h>
20 #include "prox_malloc.h"
22 #define KV_STORE_BUCKET_DEPTH 8
24 struct kv_store_expire_entry {
25 /* if set to 0, the entry is disabled */
27 /* Memory contains the key, followed by the actual value. */
31 struct kv_store_expire {
38 void (*expire)(void *entry_value);
43 static struct kv_store_expire *kv_store_expire_create(uint32_t n_entries, size_t key_size, size_t value_size, int socket, void (*expire)(void *entry_value), uint64_t timeout)
45 struct kv_store_expire *ret;
50 if (!rte_is_power_of_2(n_entries))
51 n_entries = rte_align32pow2(n_entries);
52 entry_size = sizeof(struct kv_store_expire_entry) + key_size + value_size;
54 memsize += sizeof(struct kv_store_expire);
55 memsize += entry_size * n_entries;
57 ret = prox_zmalloc(memsize, socket);
61 ret->bucket_mask = n_entries / KV_STORE_BUCKET_DEPTH - 1;
62 ret->bucket_size = entry_size * KV_STORE_BUCKET_DEPTH;
63 ret->entry_size = entry_size;
64 ret->key_size = key_size;
66 ret->timeout = timeout;
71 static size_t kv_store_expire_size(struct kv_store_expire *kv_store)
73 return (kv_store->bucket_mask + 1) * KV_STORE_BUCKET_DEPTH;
76 static void entry_set_timeout(struct kv_store_expire_entry *entry, uint64_t timeout)
78 entry->timeout = timeout;
81 static struct kv_store_expire_entry *entry_next(struct kv_store_expire *kv_store, struct kv_store_expire_entry *entry)
83 return (struct kv_store_expire_entry *)((uint8_t *)entry + kv_store->entry_size);
86 static void *entry_key(__attribute__((unused)) struct kv_store_expire *kv_store, struct kv_store_expire_entry *entry)
88 return (uint8_t *)entry->mem;
91 static void *entry_value(struct kv_store_expire *kv_store, struct kv_store_expire_entry *entry)
93 return (uint8_t *)entry->mem + kv_store->key_size;
96 static struct kv_store_expire_entry *kv_store_expire_get_first(struct kv_store_expire *kv_store)
98 return (struct kv_store_expire_entry *)&kv_store->mem[0];
101 static struct kv_store_expire_entry *kv_store_expire_get_first_in_bucket(struct kv_store_expire *kv_store, void *key)
103 uint32_t key_hash = rte_hash_crc(key, kv_store->key_size, 0);
104 uint32_t bucket_idx = key_hash & kv_store->bucket_mask;
106 return (struct kv_store_expire_entry *)&kv_store->mem[bucket_idx * kv_store->bucket_size];
109 static int entry_key_matches(struct kv_store_expire *kv_store, struct kv_store_expire_entry *entry, void *key)
111 return !memcmp(entry_key(kv_store, entry), key, kv_store->key_size);
114 static struct kv_store_expire_entry *kv_store_expire_get(struct kv_store_expire *kv_store, void *key, uint64_t now)
116 struct kv_store_expire_entry *entry = kv_store_expire_get_first_in_bucket(kv_store, key);
118 for (int i = 0; i < KV_STORE_BUCKET_DEPTH; ++i) {
119 if (entry->timeout && entry->timeout >= now) {
120 if (entry_key_matches(kv_store, entry, key)) {
121 entry->timeout = now + kv_store->timeout;
125 entry = entry_next(kv_store, entry);
130 static struct kv_store_expire_entry *kv_store_expire_put(struct kv_store_expire *kv_store, void *key, uint64_t now)
132 struct kv_store_expire_entry *e = kv_store_expire_get_first_in_bucket(kv_store, key);
134 for (int i = 0; i < KV_STORE_BUCKET_DEPTH; ++i) {
135 if (e->timeout && e->timeout >= now) {
136 e = entry_next(kv_store, e);
140 kv_store->expire(entry_value(kv_store, e));
143 rte_memcpy(entry_key(kv_store, e), key, kv_store->key_size);
144 e->timeout = now + kv_store->timeout;
151 /* If the entry is not found, a put operation is tried and if that
152 succeeds, that entry is returned. The bucket is full if NULL Is
154 static struct kv_store_expire_entry *kv_store_expire_get_or_put(struct kv_store_expire *kv_store, void *key, uint64_t now)
156 struct kv_store_expire_entry *entry = kv_store_expire_get_first_in_bucket(kv_store, key);
157 struct kv_store_expire_entry *v = NULL;
159 for (int i = 0; i < KV_STORE_BUCKET_DEPTH; ++i) {
160 if (entry->timeout && entry->timeout >= now) {
161 if (entry_key_matches(kv_store, entry, key)) {
162 entry->timeout = now + kv_store->timeout;
169 entry = entry_next(kv_store, entry);
174 kv_store->expire(entry_value(kv_store, v));
175 rte_memcpy(entry_key(kv_store, v), key, kv_store->key_size);
176 v->timeout = now + kv_store->timeout;
183 static size_t kv_store_expire_expire_all(struct kv_store_expire *kv_store)
185 struct kv_store_expire_entry *entry = kv_store_expire_get_first(kv_store);
186 size_t elems = kv_store_expire_size(kv_store);
190 if (entry->timeout) {
191 kv_store->expire(entry_value(kv_store, entry));
195 entry = entry_next(kv_store, entry);