Mosquitto-1.5.4源码分析,主题订阅的数据结构及SUBSCRIBE的函数跳转关系

简介: Mosquitto-1.5.4源码分析,主题订阅的数据结构及SUBSCRIBE的函数跳转关系

1.4.x之前的版本可以参考博客,使用的是树来实现:



mosquito从版本1.5.x开始,主题订阅的数据结构有变化。采用哈希表来存储。每一层都有一个哈希表来存储。


/src/database.c


这里初始化了两个主题,一个是业务主题“”,为空;另一个是系统主题“$SYS”


函数sub__add_hier_entry很重要,新增哈希key-value都靠它来实现。


int db__open(struct mosquitto__config *config, struct mosquitto_db *db)
{
  struct mosquitto__subhier *subhier;
  if(!config || !db) return MOSQ_ERR_INVAL;
  db->last_db_id = 0;
  db->contexts_by_id = NULL;
  db->contexts_by_sock = NULL;
  db->contexts_for_free = NULL;
#ifdef WITH_BRIDGE
  db->bridges = NULL;
  db->bridge_count = 0;
#endif
  // Initialize the hashtable
  db->clientid_index_hash = NULL;
  db->subs = NULL;
    subhier = sub__add_hier_entry(NULL, &db->subs, "", strlen(""));//业务子树根节点
  if(!subhier) return MOSQ_ERR_NOMEM;
    subhier = sub__add_hier_entry(NULL, &db->subs, "$SYS", strlen("$SYS"));//系统子树根节点
  if(!subhier) return MOSQ_ERR_NOMEM;
subs.c,会创建内存
child = mosquitto__malloc(sizeof(struct mosquitto__subhier));
struct mosquitto__subhier *sub__add_hier_entry(struct mosquitto__subhier *parent, struct mosquitto__subhier **sibling, const char *topic, size_t len)
{
  struct mosquitto__subhier *child;
  assert(sibling);
  child = mosquitto__malloc(sizeof(struct mosquitto__subhier));
  if(!child){
  log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
  return NULL;
  }
  child->parent = parent;
  child->topic_len = len;
  if(UHPA_ALLOC_TOPIC(child) == 0){
  child->topic_len = 0;
  mosquitto__free(child);
  log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
  return NULL;
  }else{
  strncpy(UHPA_ACCESS_TOPIC(child), topic, child->topic_len+1);
  }
  child->subs = NULL;
  child->children = NULL;
  child->retained = NULL;
  if(child->topic_len+1 > sizeof(child->topic.array)){
  if(child->topic.ptr){
    HASH_ADD_KEYPTR(hh, *sibling, child->topic.ptr, child->topic_len, child);
  }else{
    mosquitto__free(child);
    return NULL;
  }
  }else{
  HASH_ADD(hh, *sibling, topic.array, child->topic_len, child);
  }
  return child;
}


image.png

截图1



每一层都有一个哈希表来存储。


例如,系统消息的主题表示为:


$SYS/broker/version


$SYS/broker/uptime


$SYS/broker/clients/total


$SYS/broker/clients/inactive


$SYS/broker/clients/disconnected


哈希表结构我用草图绘制,如截图2所示


image.png


截图2


subs.c源文件的static int sub__add_recurse()函数是核心所在,负责添加哈希元素。


对于业务主题(非系统主题)的订阅,其流程如下,请观看截图3的下半部分,有详细的函数跳转流程:

image.png


image.png

截图3


订阅的最终目标就是执行语句HASH_ADD(hh, *sibling, topic.array, child->topic_len, child); 往哈希表添加元素!


相关文章
|
1天前
|
算法 JavaScript 前端开发
JavaScript算法和数据结构:写一个二分查找的函数。
JavaScript算法和数据结构:写一个二分查找的函数。
33 0
|
1天前
剑指 Offer 30. 包含min函数的栈
剑指 Offer 30. 包含min函数的栈
22 0
|
6月前
|
存储 Java C语言
lua变量、数据类型、if判断条件和数据结构table以及【lua 函数】
lua变量、数据类型、if判断条件和数据结构table以及【lua 函数】
48 0
|
7月前
|
存储
数据结构Pta训练题函数题详解三
数据结构Pta训练题函数题详解
40 0
|
7月前
|
编译器 程序员 测试技术
详解动态内存管理【malloc/calloc/realloc/free函数/柔性数组】【C语言/进阶/数据结构基础】
详解动态内存管理【malloc/calloc/realloc/free函数/柔性数组】【C语言/进阶/数据结构基础】
174 0
|
1天前
【数据结构】二叉树-堆(函数实现)
【数据结构】二叉树-堆(函数实现)
13 2
|
1天前
|
Python
python学习-函数模块,数据结构,字符串和列表(下)
python学习-函数模块,数据结构,字符串和列表
73 0
|
1天前
|
索引 Python
python学习-函数模块,数据结构,字符串和列表(上)
python学习-函数模块,数据结构,字符串和列表
30 0
|
1天前
|
Java 数据库连接 API
Java 学习路线:基础知识、数据类型、条件语句、函数、循环、异常处理、数据结构、面向对象编程、包、文件和 API
Java 是一种广泛使用的、面向对象的编程语言,始于1995年,以其跨平台性、安全性和可靠性著称,应用于从移动设备到数据中心的各种场景。基础概念包括变量(如局部、实例和静态变量)、数据类型(原始和非原始)、条件语句(if、else、switch等)、函数、循环、异常处理、数据结构(如数组、链表)和面向对象编程(类、接口、继承等)。深入学习还包括包、内存管理、集合框架、序列化、网络套接字、泛型、流、JVM、垃圾回收和线程。构建工具如Gradle、Maven和Ant简化了开发流程,Web框架如Spring和Spring Boot支持Web应用开发。ORM工具如JPA、Hibernate处理对象与数
95 3
|
1天前
|
存储 算法
《剑指offer》之“包含min函数的栈”题解
《剑指offer》之“包含min函数的栈”题解
11 0