How to select the buffer size and allocation method when processing strings-see how redis works
I recently read the redis code and think that the reading sequence provided by reading the Redis source code is good, because I have read the lua code before and have some experience. I feel that the recommended sequence is reasonable. so let's start with the implementation of redis's internal strings. During reading, I can see a trick that I personally think is awesome. post Code first:
(I have to say that the Code comments of redis are very detailed... Lua comments cannot be compared)
sds sdscatvprintf(sds s, const char *fmt, va_list ap) { va_list cpy; char staticbuf[1024], *buf = staticbuf, *t; size_t buflen = strlen(fmt)*2; /* We try to start using a static buffer for speed. * If not possible we revert to heap allocation. */ if (buflen > sizeof(staticbuf)) { buf = zmalloc(buflen); if (buf == NULL) return NULL; } else { buflen = sizeof(staticbuf); } /* Try with buffers two times bigger every time we fail to * fit the string in the current buffer size. */ while(1) { buf[buflen-2] = '\0'; va_copy(cpy,ap); vsnprintf(buf, buflen, fmt, cpy); va_end(cpy); if (buf[buflen-2] != '\0') { if (buf != staticbuf) zfree(buf); buflen *= 2; buf = zmalloc(buflen); if (buf == NULL) return NULL; continue; } break; } /* Finally concat the obtained string to the SDS string and return it. */ t = sdscat(s, buf); if (buf != staticbuf) zfree(buf); return t;}
Sds is the internal string type of redis, which is actually the typedef of char *. The difference lies in its access method. Here we can regard it as char.
Almost from the function name, we can know that this function concatenates string s and formatted string and returns the new string.
It is not difficult to implement this function, but there is a problem to consider, because you do not know the length of the 'formatted string', so we need to use the buffer, but the size of the buffer should be selected, is it directly placed on the function stack or on the stack? This is a problem.
Redis adopts the following methods:
First open a 1024-byte staticbuf array on the stack; estimate the possible 'formatted string' size (strlen (fmt) * 2 ); if the length of the 'formatted string' is greater than the length of the staticbuf array, zmalloc (which can be viewed as malloc) is used to open a memory of the corresponding size on the stack; what if the actual 'formatted string' is larger than the estimate? First, zfree (which can be seen as free) memory opened on the heap, and then a 2 times the size of the memory on the heap; if it is not enough, Repeat 4; finally, remember to release the heap memory (if opened) to prevent memory leakage.