在上篇文章中初步的分析了一下,Redis工具类文件里的一些使用方法,包含2个随机算法和循环冗余校验算法,今天,继续学习Redis中的其它的一些辅助工具类的使用方法。包含里面的大小端转换算法,sha算法在Redis中的实现和通用工具类算法util.c。

先来看看大小端转换算法,大小端学习过操作系统的人一定知道是什么意思,在不同的操作系统中,高位数字的存储方式存在,高位在前,低位在后,或是高位在后,低位在前,所以这里面就涉及到转换,依据不同的操作系统,有不同的转换方式,所以Redis在这方面就开放了这样一批的API;

  1. /* 对于16位,32位,64位作大小端的转换 */
  2. void memrev16(void *p);
  3. void memrev32(void *p);
  4. void memrev64(void *p);
  5. uint16_t intrev16(uint16_t v);
  6. uint32_t intrev32(uint32_t v);
  7. uint64_t intrev64(uint64_t v);

挑出当中的一个API的实现:

  1. /* Toggle the 32 bit unsigned integer pointed by *p from little endian to
  2. * big endian */
  3. /* 32位须要4个字节,第0和第3个,第1和第2个字节作交换 */
  4. void memrev32(void *p) {
  5. unsigned char *x = p, t;
  6.  
  7. t = x[0];
  8. x[0] = x[3];
  9. x[3] = t;
  10. t = x[1];
  11. x[1] = x[2];
  12. x[2] = t;
  13. }

总之就是做头尾部的交换。

以下在Redis中的加密算法的实现,採用的是SHA算法,/SHA:Secure Hash Algorithm安全散列算法,与MD5算法类似,也是属于单向加密算法,在加密长度上,做了非常大的扩展,安全性也更高长度不超过2^64位的字符串或二进制流,经过SHA-1编码后,生成一个160位的二进制串 。在Redis中的C语言调用:

  1. int
  2. main(int argc, char **argv)
  3. {
  4. SHA1_CTX ctx;
  5. unsigned char hash[20], buf[BUFSIZE];
  6. int i;
  7.  
  8. for(i=0;i<BUFSIZE;i++)
  9. buf[i] = i;
  10. /* Redis代码中SHA算法的调用方法 */
  11. SHA1Init(&ctx);
  12. for(i=0;i<1000;i++)
  13. SHA1Update(&ctx, buf, BUFSIZE);
  14. SHA1Final(hash, &ctx);
  15.  
  16. printf("SHA1=");
  17. for(i=0;i<20;i++)
  18. printf("%02x", hash[i]);
  19. printf("\n");
  20. return 0;
  21. }

最后说说里面的util.c通用工具类的算法实现,里面但是有很多亮点的存在,先给出详细的API,主要涉及的是数字和字符串之间的转换:

  1. int stringmatchlen(const char *p, int plen, const char *s, int slen, int nocase); /*支持glob-style的通配符格式,如*表示随意一个或多个字符,?表示随意字符,[abc]表示方括号里随意一个字母。*/
  2. int stringmatch(const char *p, const char *s, int nocase); /*支持glob-style的通配符格式,长度的计算直接放在方法内部了,直接传入模式和原字符串*/
  3. long long memtoll(const char *p, int *err); /* 内存大小转化为单位为字节大小的数值表示 */
  4. int ll2string(char *s, size_t len, long long value); /* long long类型转化为string类型 */
  5. int string2ll(const char *s, size_t slen, long long *value); /* String类型转换为long long类型 */
  6. int string2l(const char *s, size_t slen, long *value); /* String类型转换为long类型,核心调用的方法还是string2ll()方法 */
  7. int d2string(char *buf, size_t len, double value); /* double类型转化为String类型 */
  8. sds getAbsolutePath(char *filename); /* 获取输入文件名称的绝对路径 */
  9. int pathIsBaseName(char *path); /* 推断一个路径是否就是纯粹的文件名称,不是相对路径或是绝对路径 */

看第一个方法,正則表達式匹配的原理实现,平时我们仅仅知道去调用系统的正則表達式去匹配字符串,却不知道当中的原理,今天总是明确了:

  1. /* Glob-style pattern matching. */
  2. /*支持glob-style的通配符格式,如*表示随意一个或多个字符,?表示随意字符,[abc]表示方括号里随意一个字母。*/
  3. int stringmatchlen(const char *pattern, int patternLen,
  4. const char *string, int stringLen, int nocase)
  5. {
  6. while(patternLen) {
  7. switch(pattern[0]) {
  8. case '*':
  9. while (pattern[1] == '*') {
  10. //假设出现的是**,说明一定匹配
  11. pattern++;
  12. patternLen--;
  13. }
  14. if (patternLen == 1)
  15. return 1; /* match */
  16. while(stringLen) {
  17. if (stringmatchlen(pattern+1, patternLen-1,
  18. string, stringLen, nocase))
  19. return 1; /* match */
  20. string++;
  21. stringLen--;
  22. }
  23. return 0; /* no match */
  24. break;
  25. case '?':
  26. if (stringLen == 0)
  27. return 0; /* no match */
  28. /* 由于?能代表不论什么字符,所以,匹配的字符再往后挪一个字符 */
  29. string++;
  30. stringLen--;
  31. break;
  32. case '[':
  33. {
  34. int not, match;
  35.  
  36. pattern++;
  37. patternLen--;
  38. not = pattern[0] == '^';
  39. if (not) {
  40. pattern++;
  41. patternLen--;
  42. }
  43. match = 0;
  44. while(1) {
  45. if (pattern[0] == '\\') {
  46. //假设遇到转义符,则模式字符往后移一个位置
  47. pattern++;
  48. patternLen--;
  49. if (pattern[0] == string[0])
  50. match = 1;
  51. } else if (pattern[0] == ']') {
  52. //直到遇到另外一个我中括号,则停止
  53. break;
  54. } else if (patternLen == 0) {
  55. pattern--;
  56. patternLen++;
  57. break;
  58. } else if (pattern[1] == '-' && patternLen >= 3) {
  59. int start = pattern[0];
  60. int end = pattern[2];
  61. int c = string[0];
  62. if (start > end) {
  63. int t = start;
  64. start = end;
  65. end = t;
  66. }
  67. if (nocase) {
  68. start = tolower(start);
  69. end = tolower(end);
  70. c = tolower(c);
  71. }
  72. pattern += 2;
  73. patternLen -= 2;
  74. if (c >= start && c <= end)
  75. match = 1;
  76. } else {
  77. if (!nocase) {
  78. if (pattern[0] == string[0])
  79. match = 1;
  80. } else {
  81. if (tolower((int)pattern[0]) == tolower((int)string[0]))
  82. match = 1;
  83. }
  84. }
  85. pattern++;
  86. patternLen--;
  87. }
  88. if (not)
  89. match = !match;
  90. if (!match)
  91. return 0; /* no match */
  92. string++;
  93. stringLen--;
  94. break;
  95. }
  96. case '\\':
  97. if (patternLen >= 2) {
  98. pattern++;
  99. patternLen--;
  100. }
  101. /* fall through */
  102. default:
  103. /* 假设没有正則表達式的keyword符,则直接比較 */
  104. if (!nocase) {
  105. if (pattern[0] != string[0])
  106. //不相等,直接不匹配
  107. return 0; /* no match */
  108. } else {
  109. if (tolower((int)pattern[0]) != tolower((int)string[0]))
  110. return 0; /* no match */
  111. }
  112. string++;
  113. stringLen--;
  114. break;
  115. }
  116. pattern++;
  117. patternLen--;
  118. if (stringLen == 0) {
  119. while(*pattern == '*') {
  120. pattern++;
  121. patternLen--;
  122. }
  123. break;
  124. }
  125. }
  126. if (patternLen == 0 && stringLen == 0)
  127. //假设匹配字符和模式字符匹配的长度都降低到0了,说明匹配成功了
  128. return 1;
  129. return 0;
  130. }

很奇妙的代码吧,从来没有想过去实现正則表達式原理的代码。另一个方法是ll2string方法,数字转字符的方法,假设是我们寻常的做法,就是除10取余,加上相应的数字字符,但是要转换的但是ll类型啊,长度很长,效率会导致比較低,所以在Redis中作者,直接按除100算,2位,2位的赋值,并且用数字字符数字,做处理,直接按下标来赋值,避免了对余数的多次推断:

  1. /* Convert a long long into a string. Returns the number of
  2. * characters needed to represent the number.
  3. * If the buffer is not big enough to store the string, 0 is returned.
  4. *
  5. * Based on the following article (that apparently does not provide a
  6. * novel approach but only publicizes an already used technique):
  7. *
  8. * https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920
  9. *
  10. * Modified in order to handle signed integers since the original code was
  11. * designed for unsigned integers. */
  12. /* long long类型转化为string类型 */
  13. int ll2string(char* dst, size_t dstlen, long long svalue) {
  14. static const char digits[201] =
  15. "0001020304050607080910111213141516171819"
  16. "2021222324252627282930313233343536373839"
  17. "4041424344454647484950515253545556575859"
  18. "6061626364656667686970717273747576777879"
  19. "8081828384858687888990919293949596979899";
  20. int negative;
  21. unsigned long long value;
  22.  
  23. /* The main loop works with 64bit unsigned integers for simplicity, so
  24. * we convert the number here and remember if it is negative. */
  25. /* 在这里做正负号的推断处理 */
  26. if (svalue < 0) {
  27. if (svalue != LLONG_MIN) {
  28. value = -svalue;
  29. } else {
  30. value = ((unsigned long long) LLONG_MAX)+1;
  31. }
  32. negative = 1;
  33. } else {
  34. value = svalue;
  35. negative = 0;
  36. }
  37.  
  38. /* Check length. */
  39. uint32_t const length = digits10(value)+negative;
  40. if (length >= dstlen) return 0;
  41.  
  42. /* Null term. */
  43. uint32_t next = length;
  44. dst[next] = '\0';
  45. next--;
  46. while (value >= 100) {
  47. //做值的换算
  48. int const i = (value % 100) * 2;
  49. value /= 100;
  50. //i所代表的余数值用digits字符数组中的相应数字取代了
  51. dst[next] = digits[i + 1];
  52. dst[next - 1] = digits[i];
  53. next -= 2;
  54. }
  55.  
  56. /* Handle last 1-2 digits. */
  57. if (value < 10) {
  58. dst[next] = '0' + (uint32_t) value;
  59. } else {
  60. int i = (uint32_t) value * 2;
  61. dst[next] = digits[i + 1];
  62. dst[next - 1] = digits[i];
  63. }
  64.  
  65. /* Add sign. */
  66. if (negative) dst[0] = '-';
  67. return length;
  68. }

digit[201]就是从00-99的数字字符,余数的赋值就通过这个数组,高效,方便,是提高了非常多的速度。又发现了Redis代码中的一些亮点。

Redis源代码分析(二十四)--- tool工具类(2)的更多相关文章

  1. Java从零开始学二十四(集合工具类Collections)

    一.Collections简介 在集合的应用开发中,集合的若干接口和若干个子类是最最常使用的,但是在JDK中提供了一种集合操作的工具类 —— Collections,可以直接通过此类方便的操作集合 二 ...

  2. Java笔记(二十四)……集合工具类Collections&Arrays

    Collections 集合框架的工具类,方法全部为静态 Collections与Collection的区别 Collection是集合框架的一个顶层接口,里面定义了单列集合的共性方法 Collect ...

  3. Redis源代码分析(十二)--- redis-check-dump本地数据库检測

    这个文件我在今天分析学习的时候,一直有种似懂非懂的感觉,代码量700+的代码,最后开放给系统的就是一个process()方法.这里说的说的数据库检測,是针对key的检測,会用到,以下提到的结构体: / ...

  4. Redis源代码分析(十)--- testhelp.h小测试框架和redis-check-aof.c 日志检测

    周期分析struct结构体redis代码.最后,越多越发现很多的代码其实大同小异.于struct有袋1,2不分析文件,关于set集合的一些东西,就放在下次分析好了,在选择下个分析的对象时,我考虑了一下 ...

  5. Vue.js 源码分析(二十四) 高级应用 自定义指令详解

    除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令. 官网介绍的比较抽象,显得很高大上,我个人对自定义指令的理解是:当自定义指令作用在一些DOM元素或组件上 ...

  6. ABP源码分析二十四:Notification

    NotificationDefinition: 用于封装Notification Definnition 的信息.注意和Notification 的区别,如果把Notification看成是具体的消息 ...

  7. PostgreSQL的 initdb 源代码分析之十四

    继续分析: /* * Make the per-database PG_VERSION for template1 only after init'ing it */ write_version_fi ...

  8. python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法

    python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法window安装redis,下载Redis的压缩包https://git ...

  9. Bootstrap<基础二十四> 缩略图

    Bootstrap 缩略图.大多数站点都需要在网格中布局图像.视频.文本等.Bootstrap 通过缩略图为此提供了一种简便的方式.使用 Bootstrap 创建缩略图的步骤如下: 在图像周围添加带有 ...

随机推荐

  1. 观察者模式(observer行为)c#简单的例子

    观察者模式(observer行为)c#简单的例子 几点:模式使观察目标和实现松耦合之间的依赖关系.通知会传播自己主动 样本:玩家击中后发生一系列变化的敌人:后发爆炸.敌人少1一个.... namesp ...

  2. [SignalR]配置路由

    原文:[SignalR]配置路由 注册路由,在代码如下(SignalR 1.*): 脚本修改如下: 但是其官方文档解释是: By default, the route URL which client ...

  3. NSIS:判断并安装.NET Framework 4 的例子

    原文 NSIS:判断并安装.NET Framework 4 的例子 现在.NET开发的软件已经大行其道,但有些操作系统并不符合软件的运行要求,所以,我们需要在安装程序中进行.NET Framework ...

  4. AIX6.1/11.2.0.3在有关数据库SWAP一个BUG

    昨天南京到客户服务数据库的优化调整,其中新上线,经过审查alert.log当日志现在是在过去一段时间内取得,每隔几个小时的时间滞后,班会报似的内容: Thu Aug 21 09:01:26 2014 ...

  5. UVa 11790 - Murcia&#39;s Skyline

    称号:给你一个行长度的建设和高度,我们祈求最长的和下降的高度. 分析:dp,最大上升子. 说明:具有长度,不能直接优化队列单调. #include <iostream> #include ...

  6. poj2443(简单的状态压缩)

    POJ2443 Set Operation Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 2679   Accepted:  ...

  7. TortoiseGit安装与配置(转)

    TortoiseGit 简称 tgit, 中文名海龟Git. 海龟Git只支持神器 Windows 系统, 有一个前辈海龟SVN, TortoiseSVN和TortoiseGit都是非常优秀的开源的版 ...

  8. zoj 3203 Light Bulb,三分之二的基本问题

    Light Bulb Time Limit: 1 Second      Memory Limit: 32768 KB Compared to wildleopard's wealthiness, h ...

  9. java 中间String分类

    String a = "aaa"; 用这样的方式的时候java首先在内存中寻找"aaa"字符串.假设有.就把aaa的地址给它 假设没有则创建 String a ...

  10. N-gram统计语言模型(总结)

    N-gram统计语言模型 1.统计语言模型 自然语言从它产生開始,逐渐演变成一种上下文相关的信息表达和传递的方式.因此让计算机处理自然语言.一个主要的问题就是为自然语言这样的上下文相关特性建立数学模型 ...