首页
登录 | 注册

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

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

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

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

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

    所以能落个清静,笔者也是比较开心。凭我自身的感觉这段时间通过阅读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与需求相同的元素。

其工作示意图如下:

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

    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));//初始化SConnHash
  if (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的又是双链表,双链表本身也是一种循环的数据结构,这本身也代表着一种禅意吧。


相关文章

  • Fish Redux中的Dispatch是怎么实现的?
    零.前言 我们在使用fish-redux构建应用的时候,界面代码(view)和事件的处理逻辑(reducer,effect)是完全解耦的,界面需要处理事件的时候将action分发给对应的事件处理逻辑去进行处理,而这个分发的过程就是下面要讲的 ...
  • 一份还热乎的蚂蚁金服面经(已拿Offer)!附答案!!
    本文来自我的知识星球的球友投稿,他在最近的校招中拿到了蚂蚁金服的实习生Offer,整体思路和面试题目由作者--泽林提供,部分答案由Hollis整理自知识星球<Hollis和他的朋友们>中「直面Java」板块. 经历了漫长一个月的 ...
  • 阿里开发者招聘节 | 面试题02-04:给定一个二叉搜索树(BST),找到树中第K小的节点
    为帮助开发者们提升面试技能.有机会入职阿里,云栖社区特别制作了这个专辑--阿里巴巴资深技术专家们结合多年的工作.面试经验总结提炼而成的面试真题这一次将陆续放出(面试题官方参考答案将在专辑结束后统一汇总分享,点此进入答题并围观他人答案).并通 ...
  • 作者:郑锴,花名铁杰,阿里巴巴高级技术专家,Apache Hadoop PMC,Apache Kerby 创立者.深耕分布式系统开发和开源大数据多年,先后专注在安全,存储和计算领域.之前在 Intel,目前转战阿里云上,致力于提供更好用更有 ...
  • 别人家的工程师:阿里巴巴工程师有了新帮手,AI可帮助修Bug
    尽管工程师用代码创造了AI,但AI又可以对这些代码点评一番.甚至修复Bug,工程师和AI的关系正在变得微妙. AI评委引热议,阿里巴巴表示:AI不会取代工程师 4月18日,2019阿里巴巴研发效能峰会--"83行代码挑战赛&quo ...
  • 像数据科学家一样思考:12步指南(下)
    第三阶段-完成 一旦产品构建完成,你仍然需要做一些事情来使项目更加成功并使你的未来生活更轻松.那么我们如何完成数据科学项目呢? 10-交付产品 完成阶段的第一步是产品交付.为了创建可以交付给客户的有效产品,首先必须了解客户的观点.其次,你需 ...

2019 jeepshoe.net webmaster#jeepshoe.net
13 q. 0.360 s.
京ICP备10005923号