OPENSSL_free(h);
}
+static ossl_inline int match_key(HT_KEY *a, HT_KEY *b)
+{
+ /*
+ * keys match if they are both present, the same size
+ * and compare equal in memory
+ */
+ if (a != NULL && b != NULL && a->keysize == b->keysize)
+ return !memcmp(a->keybuf, b->keybuf, a->keysize);
+
+ return 1;
+}
+
static int ossl_ht_insert_locked(HT *h, uint64_t hash,
struct ht_internal_value_st *newval,
HT_VALUE **olddata)
if (ival == NULL)
empty_idx = j;
if (compare_hash(hash, ihash)) {
- if (olddata == NULL) {
- /* invalid */
- return 0;
+ /* Its the same hash, lets make sure its not a collision */
+ if (match_key(&newval->value.key, &ival->key)) {
+ if (olddata == NULL) {
+ /* invalid */
+ return 0;
+ }
}
/* Do a replacement */
if (!CRYPTO_atomic_store(&md->neighborhoods[neigh_idx].entries[j].hash,
void *data,
uintptr_t *type)
{
- struct ht_internal_value_st *new;
struct ht_internal_value_st *tmp;
+ size_t nvsize = sizeof(*tmp);
- new = OPENSSL_malloc(sizeof(*new));
+ if (h->config.collision_check == 1)
+ nvsize += key->keysize;
- if (new == NULL)
+ tmp = OPENSSL_malloc(nvsize);
+
+ if (tmp == NULL)
return NULL;
- tmp = (struct ht_internal_value_st *)ossl_rcu_deref(&new);
tmp->ht = h;
tmp->value.value = data;
tmp->value.type_id = type;
+ tmp->value.key.keybuf = NULL;
+ if (h->config.collision_check) {
+ tmp->value.key.keybuf = (uint8_t *)(tmp+1);
+ tmp->value.key.keysize = key->keysize;
+ memcpy(tmp->value.key.keybuf, key->keybuf, key->keysize);
+ }
+
return tmp;
}
for (j = 0; j < NEIGHBORHOOD_LEN; j++) {
if (!CRYPTO_atomic_load(&md->neighborhoods[neigh_idx].entries[j].hash,
&ehash, h->atomic_lock))
- break;
- if (compare_hash(hash, ehash)) {
- vidx = ossl_rcu_deref(&md->neighborhoods[neigh_idx].entries[j].value);
+ return NULL;
+ vidx = ossl_rcu_deref(&md->neighborhoods[neigh_idx].entries[j].value);
+ if (compare_hash(hash, ehash) && match_key(&vidx->value.key, key)) {
ret = (HT_VALUE *)vidx;
break;
}
hash = h->config.ht_hash_fn(key->keybuf, key->keysize);
- neigh_idx = hash & md->neighborhood_mask;
- PREFETCH_NEIGHBORHOOD(md->neighborhoods[neigh_idx]);
+ neigh_idx = hash & h->md->neighborhood_mask;
+ PREFETCH_NEIGHBORHOOD(h->md->neighborhoods[neigh_idx]);
for (j = 0; j < NEIGHBORHOOD_LEN; j++) {
- if (compare_hash(hash, md->neighborhoods[neigh_idx].entries[j].hash)) {
- h->wpd.value_count--;
- if (!CRYPTO_atomic_store(&md->neighborhoods[neigh_idx].entries[j].hash,
+ v = (struct ht_internal_value_st *)h->md->neighborhoods[neigh_idx].entries[j].value;
+ if (compare_hash(hash, h->md->neighborhoods[neigh_idx].entries[j].hash)) {
+ if (!match_key(key, &v->value.key))
+ continue;
+ if (!CRYPTO_atomic_store(&h->md->neighborhoods[neigh_idx].entries[j].hash,
0, h->atomic_lock))
break;
- v = (struct ht_internal_value_st *)md->neighborhoods[neigh_idx].entries[j].value;
- ossl_rcu_assign_ptr(&md->neighborhoods[neigh_idx].entries[j].value,
+ h->wpd.value_count--;
+ ossl_rcu_assign_ptr(&h->md->neighborhoods[neigh_idx].entries[j].value,
&nv);
rc = 1;
break;
typedef struct ht_internal_st HT;
+/*
+ * Represents a key to a hashtable
+ */
+typedef struct ht_key_header_st {
+ size_t keysize;
+ uint8_t *keybuf;
+} HT_KEY;
+
/*
* Represents a value in the hash table
*/
typedef struct ht_value_st {
void *value;
uintptr_t *type_id;
+ HT_KEY key;
} HT_VALUE;
/*
OSSL_LIB_CTX *ctx;
void (*ht_free_fn)(HT_VALUE *obj);
uint64_t (*ht_hash_fn)(uint8_t *key, size_t keylen);
+ uint32_t collision_check;
uint32_t init_neighborhoods;
} HT_CONFIG;
-/*
- * Key value for a hash lookup
- */
-typedef struct ht_key_header_st {
- size_t keysize;
- uint8_t *keybuf;
-} HT_KEY;
-
/*
* Hashtable key rules
* Any struct can be used to formulate a hash table key, as long as the
NULL,
NULL,
NULL,
+ 1,
0,
};
INTKEY key;
NULL, /* use default context */
hashtable_intfree, /* our free function */
hashtable_hash, /* our hash function */
+ 1, /* Check collisions */
625000, /* preset hash size */
};
HT *h;
NULL, /* use default context */
hashtable_mt_free, /* our free function */
NULL, /* default hash function */
+ 1, /* Check collisions */
0, /* default hash size */
};
int ret = 0;