The cached data is stored in the chunk of the slabclass structure of the corresponding level, in the form of a double-linked list, with item as the base unit. The item is also stored in a bucket in a chained hashtable to provide a quick-find index.
The first is to understand the basic data unit of the cache item structure:
typedef struct _STRITEM {
struct _stritem *next; Double-linked list back pointer in slab
struct _stritem *prev; Forward pointer to a doubly linked list in slab
struct _stritem *h_next; Point to the hash table the next item in the bucket for the item/* Hash chain Next */
rel_time_t time; Last access Timestamp/* Least recent access * *
rel_time_t Exptime; Expiration */Expire time */
int nbytes; Data Size/* size of data */
unsigned short refcount; Reference count
uint8_t Nsuffix; /* Length of flags-and-length String */
uint8_t It_flags; /* item_* above */
uint8_t Slabs_clsid; Where the slab, the slab in the Slabclass array subscript/* Which slab class we ' re in */
uint8_t Nkey; The length of key/* key length, w/terminating null and padding */
/* This odd type prevents type-punning issues if we do
* The little shuffle to save space is not using CAS. */
Union {
uint64_t CAs;
Char end;
} data[];//Real Data
/* If It_flags & Item_cas we have 8 bytes CAS */
/* Then null-terminated key */
/* Then "flags length\r\n" (no terminating null) */
/* then data with terminating \ r \ n (no terminating null; it ' s binary!) */
} item;
The structure diagram for item is as follows:
Item holds the data structure Slabclass:
Slabclass structure
typedef struct {
unsigned int size; The size of each chunk of the slab/* Sizes of items */
unsigned int perslab; Number of chunk that can be stored in size/* How many items per slab */
void *slots; /* Recycle the item linked list,
When the assigned item is recycled from time to time, the space is returned to slab,
Instead, the slab is removed directly from the chunk doubly linked list,
Hanging to the tail of the slots list for recycling,
And you do not need to initialize the item structure the next time you use it,
Instead, change the value of each property directly. List of item Ptrs */
unsigned int sl_curr; /* Indicates the current slots linked list
How many of the idle item is recycled.
Total free items in list */
unsigned int slabs; Number of current kinds of slab allocated/* How many slabs were allocated for this class */
void **slab_list; /* Initially, memcached assigns a slab for each level of Slabclass,
When this slab memory block is used,
Memcached is assigning a new slab,
So slabclass can have multiple slab at the same level,
These slab are managed by slab_list arrays,
Slab. Array of slab pointers */
unsigned int list_size; /* Indicates how many slab are currently slabclass
Size of prev Array */
unsigned int killing; /* index+1 of dying slab, or zero if none */
size_t requested; /* The number of requested bytes */
} slabclass_t;
Static slabclass_t Slabclass[max_number_of_slab_classes];//slab Array (where SLAB is arranged by its chunk from small to large)
(Note: Slabclas at the same level may include multiple slab at that level, maintained in pointer array slab_list)
Item structure stored in Slabclass:
Within the Slabclass, only the last slab has free memory, and the other slab chunk are allocated.
End_page_ptr: A block of free memory pointing to the last slab
End_page_free: Indicates how many idle chunk are left in the last slab. The chunk in the green section of the figure represents the idle chunk.
Each slabclass maintains a doubly linked list, and all assigned item is placed in the linked list according to the last access time, which is equivalent to the LRU queue.
All Slabclass lists are stored in the *heads, *tails two arrays:
Static item *heads[largest_id];//chunk array of list header pointers: An array of chunk-linked headers for each level slabclass in the Slabclass array
Static item *tails[largest_id];//chunk array of end-of-line pointers: An array of chunk chain footers at each level in the Slabclass array slabclass
Item Space allocation Policy:
* * Each time you need to allocate space for a new item, the ID of the corresponding level of Slabclass is calculated first based on the size of the item, and then the Slabclass is found in the Slabclass array.
* * After locating to the corresponding Slabclass, first check whether the last chunk of the LRU queue is out of date, the expiration is assigned to the user, otherwise to the item Recycle list slots Check the idle chunk The chunk that are not recycled are allocated from slab idle (unassigned) chunk, and if not, the LRU algorithm looks forward from the tail in the doubly linked list of assigned chunk to be able to release (the longest inaccessible) item, and then, in turn, gets the space for the new item.
* * When an item is deleted, the chunk space is not returned to the corresponding slab, but the chunk is removed from the assigned chunk linked list of the slab, and the chunk is then hung to the head of the Recycle list slots for recycling. And the item in the chunk is not released until the chunk is re-exploited to update the item's property values directly. (You don't have to initialize the item structure every time to improve efficiency!) )
Chain-type hsahtable:
At the same time, item in Slab's chunk list is also stored in Hashtable. When you need to find the item for a given key, first hash the hash table to the item corresponding to the key, and then use the item information in Hashtable to get the item in the Slabclass index position.
Two hashtable are used, one main table, and one "original table". Normally, operations are performed in the main table, and when the expansion is in progress, it is first done in the original table.
When the number of item in the table is greater than 1.5 times times the number of table buckets, it starts to expand to twice times the original, using the gradual expansion mode, the number of each migration can be set. The main table and the original table are dynamically switched, when the expansion begins, the primary table's class capacity is copied to the original table, the original table to replace the main table temporarily accept the operation, and the main table capacity expanded to twice times, and then gradually from the original table the data hash to the main table after the expansion, when the data are all migrated, all the operations back to the main table.
This is consistent with the two Hashtable operations in Redis.
Distributed cache system Memcached data storage slab and Hashtable