在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的数字字符,余数的赋值就通过这个数组,高效,方便,是提高了很多的速度。