这几周,笔者写了好几篇有关Tdengine开源代码解读的博客,其实按照代码质量来说https://blog.csdn.net/BEYONDMA/article/details/98473143这篇有关定时器的解读是水平最高的,不过这篇似乎没引起什么讨论。究其原因可能还是这个定时器的逻辑理解起来难度比较高,从这篇的唯一评论也能看出来。

难度较高也就限制了嘴炮式程序员的发挥空间,之前在解读有关consumer-producer的文章(https://blog.csdn.net/BEYONDMA/article/details/96578186)后,引发的各方所谓大神的评论,比如以下这种:

所以能落个清静,笔者也是比较开心。凭我自身的感觉这段时间通过阅读TDengine的代码,尤其是在陶老师亲自的指点下进行解读,感觉C语言的编程的水平提高非常快,在这里也感谢一下陶老可以开源这么优秀的代码,供大家学习。鉴于难度较高的代码接受度不高,所以这次为大家带来一个相对简单一些的缓存实现代码。

为什么要开源

前几天看陶老师的朋友圈,赫然写着这么一句话“如果你的产品真的牛,那就一定要开源”如果水平就那样就千万别开源了,因为没开源就可以对外宣称自主可控,不过一旦开源可就不是自己说的算了“,笔者看到后有一种醍醐灌顶的感觉,代码是没有二义性的,开源就意味着坦荡的面对世界,自身不保留秘密,这是开宗立派的气势。

无论是创立禅宗的达摩,还是儒家圣人孔子、兵家始终孙武,这些人物在布道时的最大特点都是毫无保留。而需要保留的情况往往是自身水平尚不过硬,需要留有一定的神秘感才能生存。

所以将开源是加速产品发展的手段,如果质量过硬就能迅速积累口碑打开市场,如果质量不行也能马上知道自身的成色,尽快转型。

TDCache的基本原理

废话不多说了,直接上代码,本次解读的源码位置在https://github.com/taosdata/TDengine/blob/master/src/client/src/tscCache.c,其基本的工作原理如下:

1.缓存初始化(taosOpenConnCache):首先初始化缓存对象SConnCache,再初始化哈希表connHashList,并调用taosTmrReset,重置timer(这也就是咱们上次解读的timer)

2.链接加入缓存(taosAddConnIntoCache):首先通过ip、port、username计算其哈希值(hash),然后将此链接(connInfo)加入connHashList[hash]对应的pNode节点,pNode本身又是一个双链表,也会根据添加时间将哈希值相同的connInfo排序,放入pNode双链表中。注意这里pNode是哈希表connHashList的一个节点,而其自身也是一个链表。

3.将链接由缓存中取出(taosGetConnFromCache):根据ip、port、username计算其哈希值(hash),取出connHashList[hash]对应的pNode节点,再从pNode当中取出ip、port与需求相同的元素。

其工作示意图如下:

TDCache的代码

   1.taosOpenConnCache

void *taosOpenConnCache(int maxSessions, void (*cleanFp)(void *), void *tmrCtrl, int64_t keepTimer) {SConnHash **connHashList;mpool_h     connHashMemPool;SConnCache *pObj;connHashMemPool = taosMemPoolInit(maxSessions, sizeof(SConnHash));//初始化SConnHashif (connHashMemPool == 0) return NULL;connHashList = calloc(sizeof(SConnHash *), maxSessions);//初始化connHashList if (connHashList == 0) {taosMemPoolCleanUp(connHashMemPool);return NULL;}pObj = malloc(sizeof(SConnCache));if (pObj == NULL) {taosMemPoolCleanUp(connHashMemPool);free(connHashList);return NULL;}memset(pObj, 0, sizeof(SConnCache));pObj->count = calloc(sizeof(int), maxSessions);pObj->total = 0;pObj->keepTimer = keepTimer;pObj->maxSessions = maxSessions;pObj->connHashMemPool = connHashMemPool;pObj->connHashList = connHashList;pObj->cleanFp = cleanFp;pObj->tmrCtrl = tmrCtrl;taosTmrReset(taosCleanConnCache, pObj->keepTimer * 2, pObj, pObj->tmrCtrl, &pObj->pTimer);//这是咱们上次解读过的timer,到期进行缓存的清理pthread_mutex_init(&pObj->mutex, NULL);return pObj;
}

 taosAddConnIntoCache的代码:

void *taosAddConnIntoCache(void *handle, void *data, uint32_t ip, short port, char *user) {int         hash;SConnHash * pNode;SConnCache *pObj;uint64_t time = taosGetTimestampMs();pObj = (SConnCache *)handle;if (pObj == NULL || pObj->maxSessions == 0) return NULL;if (data == NULL) {tscTrace("data:%p ip:%p:%d not valid, not added in cache", data, ip, port);return NULL;}hash = taosHashConn(pObj, ip, port, user);//通过ip port user计算哈希值pNode = (SConnHash *)taosMemPoolMalloc(pObj->connHashMemPool);pNode->ip = ip;pNode->port = port;pNode->data = data;pNode->prev = NULL;pNode->time = time;pthread_mutex_lock(&pObj->mutex);//以下是将链接信息加入pNode的链表pNode->next = pObj->connHashList[hash];if (pObj->connHashList[hash] != NULL) (pObj->connHashList[hash])->prev = pNode;pObj->connHashList[hash] = pNode;pObj->total++;pObj->count[hash]++;taosRemoveExpiredNodes(pObj, pNode->next, hash, time);pthread_mutex_unlock(&pObj->mutex);tscTrace("%p ip:0x%x:%d:%d:%p added, connections in cache:%d", data, ip, port, hash, pNode, pObj->count[hash]);return pObj;
}
void *taosGetConnFromCache(void *handle, uint32_t ip, short port, char *user) {int         hash;SConnHash * pNode;SConnCache *pObj;void *      pData = NULL;pObj = (SConnCache *)handle;if (pObj == NULL || pObj->maxSessions == 0) return NULL;uint64_t time = taosGetTimestampMs();hash = taosHashConn(pObj, ip, port, user);//计算哈希值 pthread_mutex_lock(&pObj->mutex);pNode = pObj->connHashList[hash];//取出pNode,并找到与ip port 与需求相同的链接while (pNode) {if (time >= pObj->keepTimer + pNode->time) {taosRemoveExpiredNodes(pObj, pNode, hash, time);pNode = NULL;break;}if (pNode->ip == ip && pNode->port == port) break;pNode = pNode->next;}if (pNode) {taosRemoveExpiredNodes(pObj, pNode->next, hash, time);if (pNode->prev) {pNode->prev->next = pNode->next;} else {pObj->connHashList[hash] = pNode->next;}if (pNode->next) {pNode->next->prev = pNode->prev;}pData = pNode->data;taosMemPoolFree(pObj->connHashMemPool, (char *)pNode);pObj->total--;pObj->count[hash]--;}pthread_mutex_unlock(&pObj->mutex);if (pData) {tscTrace("%p ip:0x%x:%d:%d:%p retrieved, connections in cache:%d", pData, ip, port, hash, pNode, pObj->count[hash]);}return pData;
}

我们看到这次pNode的又是双链表,双链表本身也是一种循环的数据结构,这本身也代表着一种禅意吧。

从这50行缓存实现的代码中,我读出了禅意相关推荐

  1. 50行的python游戏代码_50行代码实现贪吃蛇(具体思路及代码)

    [下载文档:  50行代码实现贪吃蛇(具体思路及代码).txt ] (友情提示:右键点上行txt文档名->目标另存为) 50行代码实现贪吃蛇(具体思路及代码) 最近一直在准备用来面试的几个小de ...

  2. 50行的python游戏代码_使用50行Python教AI玩运杆游戏

    编译:yxy 出品:ATYUN订阅号 嗨,大家好!今天我想展示如何使用50行Python代码教一台机器来平衡杆!我们将使用标准的OpenAI Gym作为我们的测试环境,并只使用numpy创建我们的智能 ...

  3. 50行的python游戏代码_50行Python代码写一个语言检测器

    你有没有曾经好奇过Chrome浏览器是如何知道一个网页的语言,并对外国文字的网页提供翻译服务的?或者,Facebook是如何翻译你朋友用写在你主页上的外国文字?检测一种语言实际上非常简单,改进了用户体 ...

  4. c语言50行以内有趣的代码,分享一段有趣的小代码

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #include #include #include //数字雨 typedef struct { int x, y; char ch; }STU; ST ...

  5. 标准输出缓存在多进程代码中引起的一个问题

    这里先看两个例子: 1) 源码如下: #include <sys/types.h> #include <stdio.h> #include <stdlib.h> # ...

  6. 50行代码实现3D模拟真实撒金币动效

    我们将会用50行不到的代码来实现一个3D模拟撒金币动效.你只需要一点Egret基础就能够快速上手,如果你不了解Egret,这里有一篇3分钟创建hello world来带你快速入门. 实现效果 源码和在 ...

  7. 50行代码教AI实现动作平衡 | 附完整代码

    作者 | Mike Shi 译者 | linstancy 责编 | Jane 出品 | AI科技大本营(id:rgznai100) [导读]本文将为大家展示如何通过 Numpy 库和 50行 Pyth ...

  8. python写一个游戏多少代码-使用50行Python代码从零开始实现一个AI平衡小游戏

    集智导读: 本文会为大家展示机器学习专家 Mike Shi 如何用 50 行 Python 代码创建一个 AI,使用增强学习技术,玩耍一个保持杆子平衡的小游戏.所用环境为标准的 OpenAI Gym, ...

  9. python爬虫实战:利用scrapy,短短50行代码下载整站短视频

    近日,有朋友向我求助一件小事儿,他在一个短视频app上看到一个好玩儿的段子,想下载下来,可死活找不到下载的方法.这忙我得帮,少不得就抓包分析了一下这个app,找到了视频的下载链接,帮他解决了这个小问题 ...

最新文章

  1. PHP--------解决网址URL编码问题
  2. Centos7安装Nginx+PHP
  3. python ssl_Python3 ssl模块不可用的问题
  4. 5 PP配置-组织架构-定义生产管理员
  5. Missing iOS Distribution signing identity问题解决
  6. sqlserver 2005的安装部署
  7. 在 tornado 中异步无阻塞的执行耗时任务
  8. Java8中的 Stream 那么彪悍,你知道它的原理是什么吗?
  9. 电脑如何录屏?分享4个屏幕录制的好方法,建议收藏
  10. libVLC 事件机制
  11. 第五人格服务器维修中怎么进,第五人格怎么进不去_进不去游戏原因汇总及解决办法_软吧...
  12. php查看其配置文件路径,php配置文件php.ini所在路径如何查看?
  13. 稳住不慌:运维职业成长路线规划
  14. 关闭vscode链接检查,去掉VSCODE 编辑器的链接下划线
  15. Ubuntu-查看ubuntu系统的版本信息
  16. [小程序]两数比较(5种写法)
  17. TI 生态大宇宙 - 波卡 Polkadot
  18. 计算机图形渲染基础知识(个人笔记)
  19. pytorch指定GPU训练
  20. Android自定义UI陷阱:LayoutInflater.from().inflate()一定不能工作在父类或虚类里

热门文章

  1. nginx防御简单CC攻击的方法
  2. linux下Kdevelop开发基本步骤
  3. GIT切换分支的简单操作
  4. python3安装psycopg2
  5. 【Linux 虚拟机】VMware虚拟机安装Ubuntu系统英文改中文的方法
  6. 二维码的生成和解析(qrcode 和 zxing)
  7. linux右键没有创建新文件夹,将新建文档添加回Ubuntu 18.04中的右键菜单
  8. 远程往服务器上传送文件,服务器远程传送文件
  9. IP协议及MAC帧格式
  10. 什么扫地机器人好用,哪一款扫地机器人好?