1.FREE SOLO - 自己动手实现Raft - 17 - leveldb源码分析与调试-3
2.FREE SOLO - 自己动手实现Raft - 11 - libuv源码分析与调试-2
3.Recast NavigationSoloMesh源码分析(三)——行走面过滤
4.FREE SOLO - 自己动手实现Raft - 16 - leveldb源码分析与调试-2
5.FREE SOLO - 自己动手实现Raft - 13 - libuv源码分析与调试-4
6.FREE SOLO - 自己动手实现Raft - 15 - leveldb源码分析与调试-1
FREE SOLO - 自己动手实现Raft - 17 - leveldb源码分析与调试-3
leveldb的编码数据流动路径是单向的,从内存中的源码memtable流向不可变的memtable,最终写入到磁盘上的编码sorted table文件中。以下是源码几个关键状态的分析,来了解内存和磁盘上数据的编码分布。
以下是源码android 系统相机源码分析所涉及的状态:
1. 数据全在内存中
随机写入条数据,观察到数据全部存储在memtable中,编码此时还没有进行compaction操作。源码
2. 数据全在磁盘中
写入大量数据,编码并等待数据完全落盘后重启leveldb。源码此时,编码数据全部存储在磁盘中,源码分布在不同的编码level中。在每个level的源码sstable文件中,可以看到key的编码最大值与最小值。
3. 数据部分在内存中,部分在磁盘中
随机写入条数据,发现内存中的memtable已满,触发compaction操作,数据开始写入到sstable文件。同时,继续写入的数据由于还未达到memtable上限,仍然保存在内存中。
4. 总结
通过观察不同数据写入量导致的数据在内存与磁盘间的流动,我们可以看到leveldb内部状态的京东集群内存源码转换。
下篇文章将分析LRUCache数据状态的变化。敬请期待!
FREE SOLO - 自己动手实现Raft - - libuv源码分析与调试-2
本次内容将深入剖析libuv如何处理网络事件,具体流程如下:
首先,EventLoop通过创建epoll fd,在Linux系统中提前准备。
然后,利用uv_run函数启动EventLoop,调用epoll_wait处理网络事件。
服务端socket创建流程:通过uv_tcp_bind、uv__tcp_bind、maybe_new_socket和new_socket进入new_socket函数。在new_socket中,先创建socket fd,再利用uv__stream_open将fd赋值给uv_stream_t,代表TcpServer。listen fd设置为。
紧接着,调用系统bind函数。
紧接着,使用uv_tcp_listen执行listen操作。
通过io_watcher建立listen fd与回调函数uv__server_io之间的联系,将此io_watcher加入到loop的watcher_queue中。
当有连接请求时,黄金通道预警源码io_watcher回调uv__server_io,执行accpt4系统调用,创建socket。接受fd设置为。
在uv__server_io中创建好socket fd后,通过stream->connection_cb调用用户提供的回调函数on_new_connection。
用户在on_new_connection中调用uv_accept,创建uv_tcp_t结构,表示TcpClient。
接着,通过uv_read_start和uv__io_start函数,将socket fd注册到loop的监听队列中,回调函数为uv__stream_io。
后续流程涉及客户端主动连接及数据读写。
总结本次内容,深入理解libuv在处理网络事件时的机制与流程,掌握其关键步骤。
Recast NavigationSoloMesh源码分析(三)——行走面过滤
本文是对SoloMesh源码分析系列文章的第三部分,主题为行走面过滤。此阶段的处理是对体素化后Heightfield的修正和标记,旨在优化导航网格的构建过程。
行走面过滤分为三个主要步骤:过滤悬空的可走障碍物、过滤高度差过大的span以及过滤不可通过高度span。
首先,源码类的图片过滤悬空的可走障碍物通过函数rcFilterLowHangingWalkableObstacles实现。此过程识别上下两个体素,其中下体素可行走,而上体素不可行走。若上下两体素上表面相差不超过walkClimb,则将上体素标记为可行走。
接着,过滤高度差过大的span通过rcFilterLedgeSpans函数完成。此过程寻找如图所示的两种情况。首先,确保上span与下span与邻居的上span下span之间存在超过walkHeight的空隙,表明可通过一个agent的高度。然后,根据两种不同的情况,对体素进行判断,以解决转角台阶的识别问题。实际上,该步骤的目的是通过补充斜向体素的考虑,解决体素连接关系仅考虑4方邻居的问题。然而,该方法存在影响同方向体素的副作用,即图示的错误例子。解决这一问题的方法是排除同方向的两个体素比较。
最后,绝地反击的源码过滤不可通过高度span通过rcFilterWalkableLowHeightSpans实现。此过程检查上下两个span之间空隙,若小于等于walkHeight,则将下span标记为不可行走。
总结:代码逻辑相对简单,具体实现细节可直接在github的wcqdong/recastnavigation项目中查看源码注释,以深入理解此阶段的详细处理流程。
FREE SOLO - 自己动手实现Raft - - leveldb源码分析与调试-2
本文聚焦于leveldb的写入机制,包括log的写入与memtable的写入过程。在深入分析之前,让我们回顾leveldb的核心数据结构,这将为后续的探讨提供直观的参考。
数据写入流程主要包括两个阶段:首先,将数据写入log,紧接着将数据写入memtable以供查询。
在log的写入过程中,数据经由一系列封装,最终通过调用log::Writer::AddRecord实现写入。在这一过程中,数据通过DBImpl::Put和DB::Put进行封装,最终由DBImpl::Write调用实现。
对于memtable的写入,数据同样经历DBImpl::Put和DB::Put的封装,随后由DBImpl::Write和MemTableInserter::Put进行处理,最后调用MemTable::Add完成写入。这一系列操作确保了数据的高效存储与检索。
数据读取方面,主要依赖于DBImpl::Get调用,通过MemTable::Get和SkipList::FindGreaterOrEqual操作在SkipList中进行搜索,实现从memtable中读取数据。同时,数据也可从sorted table中获取。
总结整个流程,本文主要梳理了数据写入与读取的调用栈,以及memtable与log在leveldb中的角色。下一次,我们将深入探讨大量数据写入后,内存与磁盘中数据状态的变化,以进一步理解leveldb的高效与可靠。
期待下次的分享,敬请关注!
FREE SOLO - 自己动手实现Raft - - libuv源码分析与调试-4
深入分析libuv库中的Timer事件处理流程,主要包括初始化、启动、停止以及重启等关键步骤。
初始化Timer事件,使用uv_timer_init函数,该函数仅调用uv__handle_init,将Timer handle添加至loop的handle_queue。
启动Timer事件,通过uv_timer_start函数实现,计算过期时间后将Timer插入loop内部的堆结构中,同时使用timer_less_than比较函数进行排序。
停止Timer事件,执行uv_timer_stop,从堆中移除Timer,uv__handle_stop递减handle引用计数,当loop内无active handle时退出循环。
重启Timer事件,在uv_timer_again函数中判断是否设置repeat参数。若设置,则连续调用uv_timer_stop和uv_timer_start,重启Timer。
Timer事件的回调触发,在loop的uv__run_timers阶段执行,从堆顶取出过期节点,并调用对应的回调函数,同时根据需要重启Timer。
至此,对libuv库中的Timer事件处理有了全面的了解,下期将深入探讨async事件的处理机制。
FREE SOLO - 自己动手实现Raft - - leveldb源码分析与调试-1
leveldb 是由 Google 基础架构工程师 Jeff Dean 所设计的,是一种高效、可靠的键值对存储系统。它基于LSM(Log-Structured Merge)存储引擎,代码简洁精炼,非常适合深入学习与理解。leveldb 不仅可以作为一个简单的键值对引擎使用,而且内部组件如LRU Cache也具有独立的实用性,还能在此基础上封装出其他操作接口,例如vraft中的raftlog和metadata等。
通过理解leveldb,能够对后续学习如rocksdb等更高级的数据库引擎提供坚实基础。本文旨在从状态机的角度解析leveldb,帮助读者深入理解其内部工作原理。
在leveldb中,关键状态包括但不限于内存、磁盘状态以及LRU Cache状态。内存数据与磁盘数据的交互是leveldb的核心,用户的键值对数据通过日志写入到memtable,然后通过immutable memtable最终到达磁盘上的sorted table文件,这些文件按照级别(level)从0到6逐级存储。通过在关键时刻添加ToJson函数,可以记录这些状态的变化,便于分析。
LRU Cache在leveldb中的实现同样值得深入研究。它作为一种缓存机制,有助于优化数据访问效率。通过在LRU Cache中添加ToJson函数并打印状态,可以直观地观察其内部结构和状态的动态变化。
为了更好地理解leveldb,本文将重点分析关键数据结构,并通过观察不同动作导致的状态变化,来深入探究leveldb的内部机制。在后续文章中,将详细展示leveldb内部状态的转换过程,以帮助读者掌握其核心工作原理。
FREE SOLO - 自己动手实现Raft - - libuv源码分析与调试-1
了解EventLoop这一核心概念,就是“Reactor模型”的主体框架。Reactor模型是一种程序设计模式,其本质在于如何对外界各种刺激做出反应,利用单一或者多个线程,处理各类外部事件,如网络数据包接收、定时器超时等,根据不同事件注册相应的回调函数。
以“状态机思维”分析libuv源码,为后续开发奠定基础。状态机思想提供了一种简洁高效的方式来描述程序的工作流程。在libuv中,主要有两种核心数据结构:Handle与Request。Handle代表常驻内存提供服务的数据结构,如uv_tcp_s,表示TcpServer,不断对外提供服务,同样可以作为TcpClient。Request则代表一次请求,如uv_req_s,其生命周期与请求处理过程相同,不会驻留在内存中。请求被处理后,该数据结构随即释放。
libuv能够处理多种不同事件,常见的几种包括:网络事件、文件系统事件、信号事件、异步操作完成事件等。未来,我们将深入解析这些核心事件的相关源代码。