
This PR incorporates changes related to key embedding described in the https://github.com/redis/redis/issues/12216 With this change there will be no `key` pointer and embedded the key within the `dictEntry`. 1 byte is used for additional bookkeeping. Overall the saving would be 7 bytes on average. Key changes: New dict entry type introduced, which is now used as an entry for the main dictionary: ```c typedef struct { union { void *val; uint64_t u64; int64_t s64; double d; } v; struct dictEntry *next; /* Next entry in the same hash bucket. */ uint8_t key_header_size; /* offset into key_buf where the key is located at. */ unsigned char key_buf[]; /* buffer with embedded key. */ } embeddedDictEntry; ``` One new function has been added to the dictType: ```c size_t (*embedKey)(unsigned char *buf, size_t buf_len, const void *key, unsigned char *header_size); ``` Change is opt-in per dict type, hence sets, hashes and other types that are using dictionary are not impacted. With this change main dictionary now owns the data, so copy on insert in dbAdd is no longer needed. ### Benchmarking results TLDR; Around 9-10% memory usage reduction in overall memory usage for scenario with key of 16 bytes and value of 8 bytes and 16 bytes. The throughput per second varies but is similar or greater in most of the run(s) with the changes against unstable (ae2d421). --------- Signed-off-by: Harkrishn Patro <harkrisp@amazon.com> Signed-off-by: Madelyn Olson <madelyneolson@gmail.com> Co-authored-by: Madelyn Olson <madelyneolson@gmail.com>
81 lines
3.9 KiB
C
81 lines
3.9 KiB
C
#ifndef DICTARRAY_H_
|
|
#define DICTARRAY_H_
|
|
|
|
#include "dict.h"
|
|
#include "adlist.h"
|
|
|
|
typedef struct _kvstore kvstore;
|
|
typedef struct _kvstoreIterator kvstoreIterator;
|
|
typedef struct _kvstoreDictIterator kvstoreDictIterator;
|
|
|
|
typedef int(kvstoreScanShouldSkipDict)(dict *d);
|
|
typedef int(kvstoreExpandShouldSkipDictIndex)(int didx);
|
|
|
|
#define KVSTORE_ALLOCATE_DICTS_ON_DEMAND (1 << 0)
|
|
#define KVSTORE_FREE_EMPTY_DICTS (1 << 1)
|
|
kvstore *kvstoreCreate(dictType *type, int num_dicts_bits, int flags);
|
|
void kvstoreEmpty(kvstore *kvs, void(callback)(dict *));
|
|
void kvstoreRelease(kvstore *kvs);
|
|
unsigned long long kvstoreSize(kvstore *kvs);
|
|
unsigned long kvstoreBuckets(kvstore *kvs);
|
|
size_t kvstoreMemUsage(kvstore *kvs);
|
|
unsigned long long kvstoreScan(kvstore *kvs,
|
|
unsigned long long cursor,
|
|
int onlydidx,
|
|
dictScanFunction *scan_cb,
|
|
kvstoreScanShouldSkipDict *skip_cb,
|
|
void *privdata);
|
|
int kvstoreExpand(kvstore *kvs, uint64_t newsize, int try_expand, kvstoreExpandShouldSkipDictIndex *skip_cb);
|
|
int kvstoreGetFairRandomDictIndex(kvstore *kvs);
|
|
void kvstoreGetStats(kvstore *kvs, char *buf, size_t bufsize, int full);
|
|
|
|
int kvstoreFindDictIndexByKeyIndex(kvstore *kvs, unsigned long target);
|
|
int kvstoreGetFirstNonEmptyDictIndex(kvstore *kvs);
|
|
int kvstoreGetNextNonEmptyDictIndex(kvstore *kvs, int didx);
|
|
int kvstoreNumNonEmptyDicts(kvstore *kvs);
|
|
int kvstoreNumAllocatedDicts(kvstore *kvs);
|
|
int kvstoreNumDicts(kvstore *kvs);
|
|
uint64_t kvstoreGetHash(kvstore *kvs, const void *key);
|
|
|
|
/* kvstore iterator specific functions */
|
|
kvstoreIterator *kvstoreIteratorInit(kvstore *kvs);
|
|
void kvstoreIteratorRelease(kvstoreIterator *kvs_it);
|
|
int kvstoreIteratorGetCurrentDictIndex(kvstoreIterator *kvs_it);
|
|
dictEntry *kvstoreIteratorNext(kvstoreIterator *kvs_it);
|
|
|
|
/* Rehashing */
|
|
void kvstoreTryResizeDicts(kvstore *kvs, int limit);
|
|
uint64_t kvstoreIncrementallyRehash(kvstore *kvs, uint64_t threshold_us);
|
|
size_t kvstoreOverheadHashtableLut(kvstore *kvs);
|
|
size_t kvstoreOverheadHashtableRehashing(kvstore *kvs);
|
|
unsigned long kvstoreDictRehashingCount(kvstore *kvs);
|
|
|
|
/* Specific dict access by dict-index */
|
|
unsigned long kvstoreDictSize(kvstore *kvs, int didx);
|
|
kvstoreDictIterator *kvstoreGetDictIterator(kvstore *kvs, int didx);
|
|
kvstoreDictIterator *kvstoreGetDictSafeIterator(kvstore *kvs, int didx);
|
|
void kvstoreReleaseDictIterator(kvstoreDictIterator *kvs_id);
|
|
dictEntry *kvstoreDictIteratorNext(kvstoreDictIterator *kvs_di);
|
|
dictEntry *kvstoreDictGetRandomKey(kvstore *kvs, int didx);
|
|
dictEntry *kvstoreDictGetFairRandomKey(kvstore *kvs, int didx);
|
|
unsigned int kvstoreDictGetSomeKeys(kvstore *kvs, int didx, dictEntry **des, unsigned int count);
|
|
int kvstoreDictExpand(kvstore *kvs, int didx, unsigned long size);
|
|
unsigned long kvstoreDictScanDefrag(kvstore *kvs,
|
|
int didx,
|
|
unsigned long v,
|
|
dictScanFunction *fn,
|
|
dictDefragFunctions *defragfns,
|
|
void *privdata);
|
|
typedef dict *(kvstoreDictLUTDefragFunction)(dict *d);
|
|
void kvstoreDictLUTDefrag(kvstore *kvs, kvstoreDictLUTDefragFunction *defragfn);
|
|
void *kvstoreDictFetchValue(kvstore *kvs, int didx, const void *key);
|
|
dictEntry *kvstoreDictFind(kvstore *kvs, int didx, void *key);
|
|
dictEntry *kvstoreDictAddRaw(kvstore *kvs, int didx, void *key, dictEntry **existing);
|
|
void kvstoreDictSetKey(kvstore *kvs, int didx, dictEntry *de, void *key);
|
|
void kvstoreDictSetVal(kvstore *kvs, int didx, dictEntry *de, void *val);
|
|
dictEntry *kvstoreDictTwoPhaseUnlinkFind(kvstore *kvs, int didx, const void *key, dictEntry ***plink, int *table_index);
|
|
void kvstoreDictTwoPhaseUnlinkFree(kvstore *kvs, int didx, dictEntry *he, dictEntry **plink, int table_index);
|
|
int kvstoreDictDelete(kvstore *kvs, int didx, const void *key);
|
|
|
|
#endif /* DICTARRAY_H_ */
|