Redis源码分析之工具类util
在redis源碼中的輔助工具類中,主要包括大小端轉換、SHA算法以及util.h中對應的算法。
大小端轉換:
LittleEndian:低位字節數據存放于低地址,高位字節數據存放于高地址。
BigEndian:低位字節數據存放于高地址,高位字節數據存放于低地址。
Linux系統中有自帶的大小端轉換方法,16位、32位的轉換,但是沒有針對64位的轉換,但是redis中加入了對64位數據的大小端轉換方法,api接口如下:
void memrev16(void *p); void memrev32(void *p); void memrev64(void *p); uint16_t intrev16(uint16_t v); uint32_t intrev32(uint32_t v); uint64_t intrev64(uint64_t v);其中,以64位為例:
void memrev64(void *p) {unsigned char *x = p, t;t = x[0];x[0] = x[7];x[7] = t;t = x[1];x[1] = x[6];x[6] = t;t = x[2];x[2] = x[5];x[5] = t;t = x[3];x[3] = x[4];x[4] = t; }x[7]與x[0]、x[6]與x[1]、x[5]與x[2]、x[4]與x[3]進行互換,是不是很簡單,一目了然。
在Redis中,加密算法的實現使用的是SHA算法。SHA是安全hash算法,與md5一樣,都是屬于消息摘要算法,底層實現的機制是hash,不可逆的,在加密長度上,做了很大的擴展,安全性也更高長度不超過2^64位的字符串或二進制流,最終生成一個20Byte的摘要。
typedef struct {uint32_t state[5];uint32_t count[2];unsigned char buffer[64]; } SHA1_CTX;void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]); void SHA1Init(SHA1_CTX* context); void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len); void SHA1Final(unsigned char digest[20], SHA1_CTX* context);測試方法或者調用方法如下:
int sha1Test(int argc, char **argv) {SHA1_CTX ctx;unsigned char hash[20], buf[BUFSIZE];int i;UNUSED(argc);UNUSED(argv);for(i=0;i<BUFSIZE;i++)buf[i] = i;SHA1Init(&ctx);for(i=0;i<1000;i++)SHA1Update(&ctx, buf, BUFSIZE);SHA1Final(hash, &ctx);printf("SHA1=");for(i=0;i<20;i++)printf("%02x", hash[i]);printf("\n");return 0; }util.c通用工具類的算法實現,具體的API,主要涉及的是數字和字符串之間的轉換,如下:
#define MAX_LONG_DOUBLE_CHARS 5*1024int stringmatchlen(const char *p, int plen, const char *s, int slen, int nocase); int stringmatch(const char *p, const char *s, int nocase); int stringmatchlen_fuzz_test(void); long long memtoll(const char *p, int *err); uint32_t digits10(uint64_t v); uint32_t sdigits10(int64_t v); int ll2string(char *s, size_t len, long long value); int string2ll(const char *s, size_t slen, long long *value); int string2l(const char *s, size_t slen, long *value); int string2ld(const char *s, size_t slen, long double *dp); int d2string(char *buf, size_t len, double value); int ld2string(char *buf, size_t len, long double value, int humanfriendly); sds getAbsolutePath(char *filename); unsigned long getTimeZone(void);根據函數的名字就可以知曉該函數的作用,其中有一個方法是ll2string(),將long long型數字轉字符的方法,正常的做法,就是除10取余,加上對應的數字字符,但是要轉換的可是long long型數字,長度非常長,效率會導致比較低,所以在Redis中,直接按除100算,2位,2位的賦值,而且用數字字符數字,做處理,直接按下標來賦值,避免了對余數的多次判斷,代碼如下:
/* 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) {static const char digits[201] ="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. */if (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];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] = '-';return length; }digit[201]就是從00-99的數字字符,余數的賦值就通過這個數組,高效,方便,是提高了很多的速度。
?
總結
以上是生活随笔為你收集整理的Redis源码分析之工具类util的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微机原理8086CPU
- 下一篇: flowable设计器节点属性扩展_go