typedef struct st_lf_hash { LF_DYNARRAY array; /* hash itself */ 这个内部的element size 是sizeof(LF_SLIST *) LF_ALLOCATOR alloc; /* allocator for elements */ my_hash_get_key get_key; /* see HASH */ --》query_cache_table_get_key CHARSET_INFO *charset; /* see HASH */ lf_hash_func *hash_function; /* see HASH */ uint key_offset, key_length; /* see HASH */ uint element_size; /* size of memcpy'ed area on insert */ uint flags; /* LF_HASH_UNIQUE, etc */ int32 volatile size; /* size of array */ int32 volatile count; /* number of elements in the hash */ /** "Initialize" hook - called to finish initialization of object provided by LF_ALLOCATOR (which is pointed by "dst" parameter) and set element key from object passed as parameter to lf_hash_insert (pointed by "src" parameter). Allows to use LF_HASH with objects which are not "trivially copyable". NULL value means that element initialization is carried out by copying first element_size bytes from object which provided as parameter to lf_hash_insert. */ lf_hash_init_func *initialize; } LF_HASH;
typedef struct st_lf_allocator { LF_PINBOX pinbox; --》 这个这样初始化 //lf_pinbox_init(&allocator->pinbox, // free_ptr_offset (实际上是offsetof(LF_SLIST, key)), // (lf_pinbox_free_func *)alloc_free, allocator); uchar * volatile top; uint element_size; --》 sizeof(LF_SLIST)+lf_hash->element_size uint32 volatile mallocs; lf_allocator_func *constructor; /* called, when an object is malloc()'ed */ lf_allocator_func *destructor; /* called, when an object is free()'d */ } LF_ALLOCATOR;
LF_PINBOX
pinstack_top_ver 是要解决aba 的问题的
1 2 3 4 5 6 7 8
typedef struct { LF_DYNARRAY pinarray; -->> lf_dynarray_init(&pinbox->pinarray, sizeof(LF_PINS)); lf_pinbox_free_func *free_func; --》 (lf_pinbox_free_func *)alloc_free void *free_func_arg; --》 //LF_HASH->alloc uint free_ptr_offset; --> offsetof(LF_SLIST, key) uint32 volatile pinstack_top_ver; /* this is a versioned pointer */ uint32 volatile pins_in_array; /* number of elements in array */ } LF_PINBOX;
LF_PINS
1 2 3 4 5 6 7 8 9 10 11 12
typedef struct st_lf_pins { void * volatile pin[LF_PINBOX_PINS]; LF_PINBOX *pinbox; void *purgatory; uint32 purgatory_count; uint32 volatile link; /* we want sizeof(LF_PINS) to be 64 to avoid false sharing */ #if SIZEOF_INT*2+SIZEOF_CHARP*(LF_PINBOX_PINS+2) != 64 char pad[64-sizeof(uint32)*2-sizeof(void*)*(LF_PINBOX_PINS+2)]; #endif } LF_PINS;
LF_SLIST
1 2 3 4 5 6 7 8 9 10
typedef struct { intptr volatile link; /* a pointer to the next element in a listand a flag */ uint32 hashnr; /* reversed hash number, for sorting */ const uchar *key; size_t keylen; /* data is stored here, directly after the keylen. thus the pointer to data is (void*)(slist_element_ptr+1) */ } LF_SLIST;
LF_PINS *lf_pinbox_get_pins(LF_PINBOX *pinbox) { uint32 pins, next, top_ver; LF_PINS *el; /* We have an array of max. 64k elements. The highest index currently allocated is pinbox->pins_in_array. Freed elements are in a lifo stack, pinstack_top_ver. pinstack_top_ver is 32 bits; 16 low bits are the index in the array, to the first element of the list. 16 high bits are a version (every time the 16 low bits are updated, the 16 high bits are incremented). Versioning prevents the ABA problem. */ // 先检查free stack中是否有之前别的线程还回来的 top_ver = pinbox->pinstack_top_ver; do { // 因为pinbox->pinarray最多64K个元素,而pinbox->pinstack_top_ver是32bit, // 所以他只有低16位是真正的stack top idx,高16位是version // 所以这里给top_ver取模LF_PINBOX_MAX_PINS便可以拿到stack top idx if (!(pins = top_ver % LF_PINBOX_MAX_PINS)) { /* the stack of free elements is empty */ // 如果stack top index为0代表当前free stack里没有,则扩展pinbox->pinarray // 的元素个数,加1,取一个新的位置 pins = pinbox->pins_in_array.fetch_add(1) + 1; if (unlikely(pins >= LF_PINBOX_MAX_PINS)) { return 0; } /* note that the first allocated element has index 1 (pins==1). index 0 is reserved to mean "NULL pointer" */ 拿到新位置对应在pinbox->pins_in_array中的元素地址 el = (LF_PINS *)lf_dynarray_lvalue(&pinbox->pinarray, pins); if (unlikely(!el)) { return 0; } break; } // 如果free stack里有元素,则弹出top位置的元素 el = (LF_PINS *)lf_dynarray_value(&pinbox->pinarray, pins); next = el->link; // CAS更新pinbox->pinstack_top_ver,后面+LF_PINBOX_MAX_PINS是为了 // 更新前16位的version,这样,每次修改top位置之后,其version都会加1,然后 // 在CAS中同时比较top idx和version来避免ABA问题 } while (!atomic_compare_exchange_strong( &pinbox->pinstack_top_ver, &top_ver, top_ver - pins + next + LF_PINBOX_MAX_PINS)); /* set el->link to the index of el in the dynarray (el->link has two usages: - if element is allocated, it's its own index - if element is free, it's its next element in the free stack */ // 当LF_PINS分配出去的时候,其link指向的是自己在pinbox->pins_in_array // 中的index // 当LF_PINS被还回来push到free stack中时,其link指向的是next element el->link = pins; el->purgatory_count = 0; el->pinbox = pinbox; return el; }