The preface project uses the redis data structure. I don't want to simply call the API. Here I will record my reading notes. Original article address: SDS:
// String type alias typedef char * SDS;
The other is sdshdr:
// Hold the structure of SDS struct sdshdr {// number of used string spaces in Buf int Len; // the number of reserved string spaces in Buf int free; // char Buf [] Where the string is actually stored;};
SDS is only the alias of char * of the string array type, while sdshdr is used to hold and save SDS information, such as sdshdr. len can be used to obtain sdshdr in the complexity of O (1. the actual length of the string stored in Buf, while sdshdr. free is used to save sdshdr. buf reserves (sdshdr should be short for SDS handler)
Using sdshdr as the sdssds module makes it a little tricky to use the sdshdr structure: Through pointer computation, it enables the sdshdr structure to be passed and processed like the SDS type, and restore to sdshdr as needed. The following function definition is used to understand this technique. The sdsnewlen function returns a new SDS value. In fact, it creates an sdshdr structure:
SDS sdsnewlen (const void * init, size_t initlen) {struct sdshdr * Sh; If (init) {// create SH = malloc (sizeof (struct sdshdr) + initlen + 1);} else {// re-allocate SH = calloc (1, sizeof (struct sdshdr) + initlen + 1);} If (SH = NULL) return NULL; SH-> Len = initlen; SH-> free = 0; // the value of free is 0if (initlen & init) {memcpy (Sh-> Buf, init, initlen);} sh-> Buf [initlen] = '\ 0'; // only return the return (char *) Sh-> Buf ;}
By using variables to hold a value of SDS, we can directly pass SDS to those functions that only process the SDS value itself. For example, the sdstoupper function is an example:
Static inline size_t sdslen (const SDS s) {// calculate the corresponding sdshdr structure from SDS struct sdshdr * Sh = (void *) (S-(sizeof (struct sdshdr); Return sh-> Len;} void sdstoupper (SDS s) {int Len = sdslen (s), J; for (j = 0; j <Len; j ++) s [J] = toupper (s [J]);}
Here is a trick. Through pointer calculation, we can calculate the corresponding sdshdr structure from the SDS value: Although SDS is directed to the Buf of char * (PS: And empty arrays do not occupy memory space, array name is the memory address), but the sizeof (struct sdshdr) + initlen + 1 is allocated, through SDS-sizeof (struct sdshdr) the first address of struct sdshdr can be calculated to obtain Len and free information. The sdsavail function is an example of the technique in this example:
static inline size_t sdsavail(const sds s){struct sdshdr *sh = (void *)(s - (sizeof(struct sdshdr)));return sh->free;}
The memory allocation function implementation is related to the Implementation Decision-making of reids. The function is sdsmakeroomfor:
SDS sdsmakeroomfor (sds s, size_t addlen) {struct sdshdr * Sh, * newsh; size_t free = sdsavail (s); size_t Len, newlen; // The reserved space can meet the needs of local stitching if (free> = addlen) return s; Len = sdslen (s); SH = (void *) (S-(sizeof (struct sdshdr ))); // set the string length of the new SDS. // This length is greater than the actual length required to complete the splicing. // use the reserved space optimization function. newlen = (LEN + addlen ); if (newlen <1024*1024) newlen * = 2; elsenewlen + = 1024; // reassign sdshdrnewsh = realloc (Sh, sizeof (struct sdshdr) + newlen + 1 ); if (newsh = NULL) return NULL; newsh-> free = newlen-len; // return only the return newsh-> Buf ;}
This memory allocation policy indicates that when the SDS value is expanded (expand), additional space is always reserved. By spending more memory, reallocate is reduced) the number of times, and optimized the processing speed of the next expansion operation, and then paste the SDS string extension method of redis, a good idea:
/*** Extend SDS by Len and splice T to the end of SDS */SDS sdscatlen (sds s, const void * t, size_t Len) {struct sdshdr * Sh; size_t curlen = sdslen (s); // O (n) S = sdsmakeroomfor (S, Len); If (S = NULL) return NULL; // copy memcpy (S + curlen, T, Len); // update Len and free attributes SH = (void *) (S-(sizeof (struct sdshdr ))); sh-> Len = curlen + Len; SH-> free = sh-> free-len; // The Terminator s [curlen + Len] = '\ 0'; return s ;} /*** concatenate a char array to the end of SDS */SDS sdscat (sds s, const char * t) {return sdscatlen (S, T, strlen (t ));}
OK. Now, I am sorry for the slow learning of SDS (Simple Dynamic string). I am still writing business logic code. I'm curious about how the hashs and sets structures are implemented !!