redis源码之util
生活随笔
收集整理的這篇文章主要介紹了
redis源码之util
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
? ? ? ? ?util.c里面是一些常見的輔助處理算法,下面看一下。
/* Convert a string representing an amount of memory into the number of* bytes, so for instance memtoll("1Gb") will return 1073741824 that is* (1024*1024*1024).** On parsing error, if *err is not NULL, it's set to 1, otherwise it's* set to 0. On error the function return value is 0, regardless of the* fact 'err' is NULL or not. */ long long memtoll(const char *p, int *err) {//將表示內存量的字符串轉換為字節(jié)const char *u;char buf[128];long mul; /* unit multiplier */ //單位乘數(shù)long long val;unsigned int digits;if (err) *err = 0;/* Search the first non digit character. */ //搜索第一個非數(shù)字字符u = p;if (*u == '-') u++;while(*u && isdigit(*u)) u++; //isdigit檢查其參數(shù)是否為十進制數(shù)字字符if (*u == '\0' || !strcasecmp(u,"b")) { //strcasecmp比較兩個字符串是否相等,且不區(qū)分大小寫mul = 1;} else if (!strcasecmp(u,"k")) {mul = 1000;} else if (!strcasecmp(u,"kb")) {mul = 1024;} else if (!strcasecmp(u,"m")) {mul = 1000*1000;} else if (!strcasecmp(u,"mb")) {mul = 1024*1024;} else if (!strcasecmp(u,"g")) {mul = 1000L*1000*1000;} else if (!strcasecmp(u,"gb")) {mul = 1024L*1024*1024;} else {if (err) *err = 1;return 0;}/* Copy the digits into a buffer, we'll use strtoll() to convert* the digit (without the unit) into a number. */digits = u-p;if (digits >= sizeof(buf)) {if (err) *err = 1;return 0;}memcpy(buf,p,digits);buf[digits] = '\0';char *endptr;errno = 0;val = strtoll(buf,&endptr,10); //strtoll將字符串轉換為長整數(shù)if ((val == 0 && errno == EINVAL) || *endptr != '\0') {if (err) *err = 1;return 0;}return val*mul; }此函數(shù)可以來將對應單位轉換為多少字節(jié),先找出對應單位,然后把值存儲在字符串中并將字符串轉成long long類型,最后返回乘積。
/* Convert a long long into a string. Returns the number of* characters needed to represent the number.* If the buffer is not big enough to store the string, 0 is returned.** Based on the following article (that apparently does not provide a* novel approach but only publicizes an already used technique):** https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920** Modified in order to handle signed integers since the original code was* designed for unsigned integers. */ int ll2string(char *dst, size_t dstlen, long long svalue) {//將long long轉換為字符串static const char digits[201] = //數(shù)組大小是200,下標是0~199"0001020304050607080910111213141516171819" "2021222324252627282930313233343536373839""4041424344454647484950515253545556575859""6061626364656667686970717273747576777879""8081828384858687888990919293949596979899";int negative; //負unsigned long long value;/* The main loop works with 64bit unsigned integers for simplicity, so* we convert the number here and remember if it is negative. *///LLONG_MIN = -9223372036854775808 LLONG_MAX = 9223372036854775807if (svalue < 0) {if (svalue != LLONG_MIN) {value = -svalue;} else {value = ((unsigned long long) LLONG_MAX)+1;}negative = 1;} else {value = svalue;negative = 0;}/* Check length. */uint32_t const length = digits10(value)+negative;if (length >= dstlen) return 0;/* Null term. */uint32_t next = length;dst[next] = '\0';next--;while (value >= 100) {int const i = (value % 100) * 2;value /= 100;dst[next] = digits[i + 1]; //每次處理2個,這樣可以少循環(huán)一倍dst[next - 1] = digits[i];next -= 2;}/* Handle last 1-2 digits. */if (value < 10) {dst[next] = '0' + (uint32_t) value;} else {int i = (uint32_t) value * 2;dst[next] = digits[i + 1];dst[next - 1] = digits[i];}/* Add sign. */if (negative) dst[0] = '-';//若為負數(shù),在字符串開頭加上負號標志return length; }這里借用了字符串數(shù)組,每次處理2個,少循環(huán)了一倍。
/* Convert a string into a long long. Returns 1 if the string could be parsed* into a (non-overflowing) long long, 0 otherwise. The value will be set to* the parsed value when appropriate.** Note that this function demands that the string strictly represents* a long long: no spaces or other characters before or after the string* representing the number are accepted, nor zeroes at the start if not* for the string "0" representing the zero number.** Because of its strictness, it is safe to use this function to check if* you can convert a string into a long long, and obtain back the string* from the number without any loss in the string representation. */ int string2ll(const char *s, size_t slen, long long *value) { //字符串轉換成long longconst char *p = s;size_t plen = 0;int negative = 0;unsigned long long v;/* A zero length string is not a valid number. */if (plen == slen)return 0;/* Special case: first and only digit is 0. */if (slen == 1 && p[0] == '0') {if (value != NULL) *value = 0;return 1;}/* Handle negative numbers: just set a flag and continue like if it* was a positive number. Later convert into negative. */if (p[0] == '-') {negative = 1;p++; plen++;/* Abort on only a negative sign. */if (plen == slen)return 0;}/* First digit should be 1-9, otherwise the string should just be 0. */if (p[0] >= '1' && p[0] <= '9') {v = p[0]-'0'; //字符 - '0' 就為數(shù)字p++; plen++;} else {return 0;}/* Parse all the other digits, checking for overflow at every step. */while (plen < slen && p[0] >= '0' && p[0] <= '9') {if (v > (ULLONG_MAX / 10)) /* Overflow. */return 0;v *= 10;if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */return 0;v += p[0]-'0';p++; plen++;}/* Return if not all bytes were used. */if (plen < slen)return 0;/* Convert to negative if needed, and do the final overflow check when* converting from unsigned long long to long long. */if (negative) {if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */return 0;if (value != NULL) *value = -v;} else {if (v > LLONG_MAX) /* Overflow. */return 0;if (value != NULL) *value = v;}return 1; }注意long long類型值溢出的判斷。
/* Get random bytes, attempts to get an initial seed from /dev/urandom and* the uses a one way hash function in counter mode to generate a random* stream. However if /dev/urandom is not available, a weaker seed is used.** This function is not thread safe, since the state is global. */ void getRandomBytes(unsigned char *p, size_t len) { //獲取隨機數(shù)種子/* Global state. */static int seed_initialized = 0;static unsigned char seed[20]; /* The SHA1 seed, from /dev/urandom. */static uint64_t counter = 0; /* The counter we hash with the seed. */if (!seed_initialized) {/* Initialize a seed and use SHA1 in counter mode, where we hash* the same seed with a progressive counter. For the goals of this* function we just need non-colliding strings, there are no* cryptographic security needs. */FILE *fp = fopen("/dev/urandom","r");if (fp == NULL || fread(seed,sizeof(seed),1,fp) != 1) { //fread從給定輸入流stream讀取最多count個對象到數(shù)組buffer中/* Revert to a weaker seed, and in this case reseed again* at every call.*/ for (unsigned int j = 0; j < sizeof(seed); j++) { //fopen讀取失敗,使用弱種子struct timeval tv;gettimeofday(&tv,NULL);pid_t pid = getpid();seed[j] = tv.tv_sec ^ tv.tv_usec ^ pid ^ (long)fp;}} else {seed_initialized = 1;}if (fp) fclose(fp);}//sha1加密while(len) { unsigned char digest[20];SHA1_CTX ctx;unsigned int copylen = len > 20 ? 20 : len;SHA1Init(&ctx);SHA1Update(&ctx, seed, sizeof(seed));//將新數(shù)據(jù)(原始數(shù)據(jù)、填充位、長度)依次附加到context->buffer[]SHA1Update(&ctx, (unsigned char*)&counter,sizeof(counter));SHA1Final(digest, &ctx);counter++;memcpy(p,digest,copylen);len -= copylen;p += copylen;} }獲取隨機數(shù)種子。
/* Given the filename, return the absolute path as an SDS string, or NULL* if it fails for some reason. Note that "filename" may be an absolute path* already, this will be detected and handled correctly.** The function does not try to normalize everything, but only the obvious* case of one or more "../" appearing at the start of "filename"* relative path. */ sds getAbsolutePath(char *filename) { //給定文件名,將絕對路徑作為SDS字符串返回char cwd[1024];sds abspath;sds relpath = sdsnew(filename);printf("relpath =%s\n",relpath);relpath = sdstrim(relpath," \r\n\t"); // \t 的意思是 橫向跳到下一制表符位置if (relpath[0] == '/') return relpath; /* Path is already absolute. *//* If path is relative, join cwd and relative path. */if (getcwd(cwd,sizeof(cwd)) == NULL) { //getcwd()會將當前工作目錄的絕對路徑復制到參數(shù)buffer所指的內存空間中sdsfree(relpath);return NULL;}abspath = sdsnew(cwd);printf("abspath =%s\n",abspath);if (sdslen(abspath) && abspath[sdslen(abspath)-1] != '/')abspath = sdscat(abspath,"/");/* At this point we have the current path always ending with "/", and* the trimmed relative path. Try to normalize the obvious case of* trailing ../ elements at the start of the path.** For every "../" we find in the filename, we remove it and also remove* the last element of the cwd, unless the current cwd is "/". */while (sdslen(relpath) >= 3 &&relpath[0] == '.' && relpath[1] == '.' && relpath[2] == '/')//排除../對應的目錄{sdsrange(relpath,3,-1);if (sdslen(abspath) > 1) {char *p = abspath + sdslen(abspath)-2;int trimlen = 1;while(*p != '/') {p--;trimlen++;}sdsrange(abspath,0,-(trimlen+1));}}/* Finally glue the two parts together. */abspath = sdscatsds(abspath,relpath);sdsfree(relpath);return abspath; }注意對../目錄的處理。
總結
以上是生活随笔為你收集整理的redis源码之util的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: va_list函数
- 下一篇: linux pread/pwrite