CockroachDB 源码闲逛 - II (insert a row)
本文将深入探讨 CockroachDB 的启动过程以及处理一条简单 SQL(如插入一行数据)的具体流程。CockroachDB 使用 Go 语言中流行的源码源码 Cobra 库来构建其命令行界面(CLI),在使用 `start` 命令启动服务端后,回收回收代码从特定位置开始执行。旧物旧物
启动初期,源码源码spark提交任务源码CockroachDB 会准备好各种日志和 pprof 功能。回收回收pprof 功能允许通过开关控制定期导出 CPU 和内存(通过 go/jemalloc)的旧物旧物性能分析报告,并定期清除旧的源码源码 pprof 数据,这有助于在排查问题时找到事故现场的回收回收堆栈或性能数据。
之后,旧物旧物服务端使用一个端口同时处理 PostgreSQL、源码源码HTTP 和 gRPC 协议,回收回收代码进入 `Server.start()` 方法。旧物旧物这个方法包含复杂的源码源码逻辑用于节点发现和 bootstrap。主要关注点在于 SQL 处理,尤其是 PostgreSQL 协议下的客户端连接。
当客户端通过 PG 协议连接到服务端时,代码进入 `pgwire.Server#ServeConn` 方法。通过校验版本等步骤后,进入 `conn.serveImpl` 方法,这是处理请求的主要逻辑。在这里,每个客户端连接由两个 goroutine 分别处理读取协议解析和命令执行。这种设计允许在执行过程中同时接收客户端连接事件,例如在执行大规模 SQL 过程时,osgi源码分析通过关闭其中一个 goroutine 可以在 SQL 执行的同时响应客户端的 `FIN` 指令。
在客户端连接的两个 goroutine 准备好后,发送的 SQL 语句开始在 `coordinator-side` 进行处理。首先,`read goroutine` 解析网络包,并根据不同的 PG cmd 分发到相应的方法进行处理。对于简单的文本执行查询,`handleSimpleQuery` 方法相对简单。为了区分不同批量的命令,当一组命令推送到 `stmtBuf` 后,会插入一个哨兵 `Sync` 来标记当前批次结束以及后续命令属于下一个批次。
随后,`process goroutine` 从 `stmtBuf` 中获取命令,根据不同的命令类型分发到相应的 `exec*` 方法。例如,简单查询产生的 `ExecStmt` 会进入 `execStmt` 方法,在此之前会创建 `stmtRes` 来封装后续返回客户端响应的缓冲区刷新逻辑。
在处理 SQL 语句时,CockroachDB 会维护一个状态机(StateMachine),用于管理当前连接的事务状态。状态机的定义和行为主要与事务相关,包括 `noTxn`、`open`、`abort`、`implicit` 等状态。论坛爬虫源码在处理插入一行数据的简单语句(如 `INSERT INTO t (a) VALUES (1);`)时,流程如下:
首先,客户端与服务端建立连接,启动两个 goroutine。当插入语句发送到服务端后,`read goroutine` 开始解析并放置到 `stmtBuf`。
随后,`process goroutine` 从 `stmtBuf` 拿出命令,识别为 `ExecStmt`。由于执行此语句前未开始事务,当前连接的状态机处于 `stateNoTxn`。因此,执行 `execStmtInNoTxnState` 方法,因为没有事务,仅执行 `execStmtInNoTxnState` 的默认分支,返回 `eventTxnStart` 事件和 `eventTxnStartPayload`。此时,状态机应用 `noTxnToOpen` 进程,为隐式事务的启动做准备。服务端通过 `client.NewTxn` 创建事务,获取时间戳并准备 `sender` 和 `coordinator` 等工作。接着,设置 `advanceInfo` 为 `advanceOne`、`noRewind`(无需回移 `stmtBuf`,通常重试时需要回移)和 `txnState` 为 `txnStart`。android 魔方源码事务状态为 `open` 后,`execCmd` 会从 `stmtBuf` 中继续取出插入语句并执行。
当当前事务状态为 `open` 且为 `implicit` 时,`execStmtInOpenState` 方法继续执行。由于当前 SQL 不是 `BEGIN`、`COMMIT` 等操作,挂载了 `handleAutoCommit` 的 `defer` 函数,并处理 `AS OF` 时间逻辑后,进入 `dispatchToExecutionEngine` 方法。
在 `makeExecPlan` 方法中,创建逻辑计划。接下来,评估是否能够分布执行逻辑计划(对于插入操作,CockroachDB 当前不支持分布式计划)。然后,为逻辑计划准备上下文,调用 `execWithDistSQLEngine`。对于不可分布执行的情况,创建简化版的 `planCtx`,用于生成物理计划。在此步骤中,生成物理计划(如 `row count` 算子)并最终生成执行流程。
在准备和生成流程后,服务端启动在本地节点的执行流程。通过 `local execution` 的阳澄 源码 `setup` 和 `run` 方法,执行生成的处理器(如 `planNodeToRowSource`)。在 `run` 方法中,执行 `rowCountNode` 算子,进而触发 `insertNode` 的 `BatchNext`,以火山模式(一次过一个批处理的多个行)执行插入操作。
插入操作中,`BatchNext` 分批处理,根据 `maxInsertBatchSize`(默认为 )进行分批。对于非最后一批次,会通过 `txn.Run` 发送至存储节点,将数据分批存储。在 `checkHelper` 函数中,检查表约束,分为 `eval` 和 `input` 模式,前者是老逻辑,后者在插入前检查约束结果,作为插入算子的输入,有利于优化插入操作。
添加批处理时,调用 `initResult` 准备每个 `CPut` 的结果。如果批处理中某个命令失败(如序列化失败),会在 `initResult` 中保存序列化失败信息。
之后,将准备好的批处理发送至 `replica-side`。在 `finalize` 中,将 `EndTransactionRequest` 添加到批处理的末尾,通过 `txn.Run` 发起。此时,批处理中包含一个条件 `put` 和一个结束事务请求,服务端通过 `DistSender.Send` 将批处理发送至 `replica-side`。批处理中的 `result` 包含 `err` 信息,用于验证批处理序列化无误。
在 `replica-side`,请求到达节点的存储层,找到相关范围的副本对象并处理等待逻辑。对于写入操作,使用 Raft 进行 `Replica.executeWriteBatch`。在此方法中,使用 `Latch` 机制来优化对交叠和非交叠批处理的处理,同时执行批处理命令的 `evaluateWriteBatch` 方法将所有命令应用到数据中,生成 `engine.Batch` 并构建 `ProposalData`。最终,通过 Raft 提出修改,实现数据的最终一致性。
最后,执行成功或失败后,结果会沿原路径返回至客户端。
总结,本文详细阐述了 CockroachDB 从启动到处理简单 SQL(如插入操作)的全过程。通过深入分析,读者能够更好地理解 CockroachDB 的内部工作机制,为后续阅读代码提供基础。未来计划将关注点扩展到重试处理逻辑,进一步探索 `stmtBuf` 和状态机在 CockroachDB 中的使用。
微信ç½ååç¬ç¹ç³»å
ææ¶åï¼ç¬ç¹çå¿ä¼è®©äººå¾å®¹æ产çå¤ç§å ³ç³»ãæåªäºç¬å ·ç¹è²ç微信åç³»åï¼è®©æ们æ¥ççå§ã
ç¬ç¹ç微信åç³»å
好å¬ç微信æ个ç¬ç¹çååã
ææç±³è
夹æ¿ç¼éçç·äºº
æå±±æ¥çå³é
轻轻çå±çï¼å¼å¤ä¸ä¸ªæµ®å¨çååã
æºç äºæ¬¡æ¹ç¨ï¼
ç¥ç§å宾*/
å·´é»ä½é³
ä¸æçç»å°¾
ç¶è£ æ°§æ°
å³çå°çå
åäºåéè¿ã
æ²æªå°½ï¼äººæ£ã
æ¶é´æ»æ¯å²ç¬æã
ç¹æ®ç人
è延æ è¡@
æèºéå¹´çç½ç»çæ´»
没æä»ä¹æ¯æç¨çï¼é¤äºææ ã
æ§ç©ï¼è人ï¼æ§å»ºç
æµéçæ°´å¹´è½»èå¤å°ï¼
å¯ä¸ç±»å微信å称
赤èä»å¥³ï¼
æç»´éå ½
é»è¾æªç©
å¦æé£ç尽头æå
ä½ è¢«è½¯ç¦äºã
å·å°å¹´
æ§å¶ï¼è¿·å¤±çå¿åå¡ã
å°å¿æ大æ è
é´å½±æ¯æ¶é´çæ ¸å¿ã
åå¹´æ¶é1
åè¡°æç½®æ¢
å»è½»å±ã
å°å¾·éå¹´1
缺货ç±æ
èå²çåå¬
迪ç¾åå
ç°è²æ¼©æ¶¡
ä¸åæ¸ éä¸åé
åæ°§æ è¡è ã
åäºäº¤é ç人
é»ç½è@
ç»çæ¶ä»£I
è¦å¾æèºã
æ åæ 书
æ¢ ç®å¹´å
寻æ¾ä¸ä¸ªå®¶
å¤æ¥å¦æ·±ç§|
æéå¨æ¢¦éã
åè¹å§ï¼ç½é©¬çå
åå°æ¢¦ä¸
微信çååå¾ç¬ç¹ã微信çååå¾å¥½å¬ã
åé 梦
å寿
寻ä¸è·¯å¥¶è¶é¦
æ è¡è 请å¿ææ°ã
è念丽丽
ç½é¹¿è¢«éæ¾å°æ£®æä¸åªæ¯ä¸ºäºå¯»æ¾é²¸é±¼ã
#å¦æä½ ä¸æç½ï¼è¯·å强起æ¥
è¹æè¸
ä¸è¦éæ¥
åæé主æµ
强迫形ç¶I
带çé声å¹æ¯ã
é¢å ·æ 人I
æµ·ä¸ä¸æ¯èè²çç
éã
å·å¨¥æåä¸ä¸ªåé
åå¶èå°æ¥ä¼å¼å¾å¾æ¼äº®ã
å°å·å¦ç
åè§é£éçæ¶å
æ欢
èå£å¡æ ¼
ä½ å¨æ¼«é¿å¤å¤©çç¡ç
大四学姐,如何处理旧货?
1/6赠送最直接的方式就是赠送了,既然自己带不走,丢了也可惜,不如送给你关系好的学弟学妹们,以好物尽其用。2/6专业课书籍而关于书籍方面,专业课书籍是比较好卖的,你可以在你的学弟学妹那里宣传一下,卖自己的专业课书籍,价格可以便宜一点,一般还是比较抢手的。
3/6课外书籍课外书籍你可以作为购买你专业课书籍的赠送品,实在送不出去的,你也可以让收废品的领走卖掉就好了。simba.taobao.com根据文章内容为您推荐广告旧物回收小程序开发废品预约上门回收app垃圾分类系统源码搭建¥ 元¥ 元查看
4/6二手市场针对类似小桌子、收纳盒、小台灯之类的小东西,建议拿到二手市场去卖吧,毕业季,每个大学应该都会举办一次比较热闹的二手市场,那个时候你就可以去摆摊卖掉。
5/6衣服而针对过多的衣服,如果觉得丢了可惜,可以去做爱心捐赠,帮助山区的孩子也是不错的,一般宿舍楼门前就有捐赠箱。
6/6寄回去你要是实在舍不得,不妨就咬咬牙,寄回去,可能邮费会花上一小笔钱,但是一般还是相对比较划算的。
怎样删除网卡绑定的协议
批处理怎样删除网卡绑定协议以及垃圾文件清理
看看这个arp.bat (绑定网卡的批处理)请你把它存为×.bat文件 ,双击执行,另处一个是能把所有2K或XP以上的机器的垃圾文件删除掉的
源代码:
cd c:\
if exist ipconfig.txt del ipconfig.txt
ipconfig /all >ipconfig.txt
find "IP Address" ipconfig.txt >ip.txt
find "Physical Address" ipconfig.txt >mac.txt
start "notepad " c:\ipconfig.txt
for /f "skip=2 tokens=" %%i in (ip.txt) do set ip=%%i
for /f "skip=2 tokens=" %%m in (mac.txt) do set mac=%%m
goto mac
:mac
arp -d
arp -s ..0. -E0-0F-7B--E2
ping .0.0.1
goto ip
:ip
arp -s %ip% %mac%
ping .0.0.1
goto mac
我的解释:
进入目录改磁盘路径为C:\ C盘
如果存在有一个ipconfig.txt文本文件就删除掉
使用命令获得网络参数 写在C:\ ipconfig.txt
在ipconfig.txt里找到IP Address字样写到ip.txt
也就当前的IP地址是什么,开始记事本 打开c:\ipconfig.txt
在ipconfig.txt里找到物理地址Physical Address 写到Mac.txt 文件中
这样IP中有IP地址,MAC有批处理地址
设从IP文件中提取I 参数并设置IP和参数相同
设从Mac文件中提取M 参数并设置MAC和参数相同
跳转到MAC 标识符下
MAC 标识符(执行开始)
释放所有网络绑定或连接
绑定 IP MAC 即arp –s 绑定参数+IP地址+空格+物理地址
查看本地TCP连接是否正常
跳转到IP 标识符下
执行绑定参数 %ip% IP和MAC相应%mac%
查看本地TCP连接是否正常
重新返回MAC 标识符下
@echo off
echo 这个命令由管理员钦星发出......
echo 正在清除系统垃圾文件,请稍等......
del /f /s /q %systemdrive%\*.tmp
del /f /s /q %systemdrive%\*._mp
del /f /s /q %systemdrive%\*.log
del /f /s /q %systemdrive%\*.gid
del /f /s /q %systemdrive%\*.chk
del /f /s /q %systemdrive%\*.old
del /f /s /q %systemdrive%\recycled\*.
*del /f /s /q %windir%\*.bak
del /f /s /q %windir%\prefetch\*.
*del /s /q %windir%\temp & md %windir%\temp
del /f /q %userprofile%\cookies\*.
*del /f /q %userprofile%\recent\*.
*del /f /s /q "%userprofile%\Local Settings\Temporary Internet Files\*.*"
del /f /s /q "%userprofile%\Local Settings\Temp\*.*"
del /f /s /q "%userprofile%\recent\*.*"
echo 清除系统LJ完成!
echo. & pause
exit
解释:
关闭显示开关,@做为关键命令保留下来,@echo off关闭 @echo on 打开
ECHO语句没有参数符直接的提示: 这个命令由管理员钦星发出...... 这些语句
提示正在清除系统垃圾文件,请稍等......
del 主要用于命令删除文件,如:DEL C.TXT 删除C.TXT 文本文件,它有很多参数,我们来看一下
/f 强制删除,不问为什么
/s子目录所有文件
/p 不要问答 y /N 这样类的,相当于直接回答“是”,我要把文件删除
所以“直接删除文件”也是另一种表现
哪些文件才是我们要删除的呢、?来看一下
1 我们的临时文件,这主要是由于软件操作和上网产生的
2 系统垃圾文件,这里主要有日志文件和查检文件和备份文件
回收站,WINNT下的备份文件,个人临时文件cookie文件
上网的临时文件和\recent的临时文件
他们主要放在哪了呢?以上对面就有目录
所有 ×.tmp 临时文件
×.LOG 记录日志文件
×.Chk 查检文件
×.OLD旧文件备份
%systemdrive%指安装的主目录如C盘中(必定是个磁盘)
%windir%一般指我们的NT目录如C:\WINNT
%userprofile% 一般是用户所在的文件目录,如管理员的和来宾用户目录是不在同一下的. 往往这里是用户软件和垃圾最多的地方
提示完毕,退出
Navigation包 Global_planner全局路径规划源码详细解析
学习总结,如有错误欢迎指正!一丶plan_node.cpp从程序入口开始,首先在plan_node.cpp的main函数中,初始化了全局路径规划器。
costmap_2d::Costmap2DROS?lcr("costmap",?buffer);global_planner::PlannerWithCostmap?pppp("planner",?&lcr);在函数PlannerWithCostmap中设置了两种调用makePlan的路径:
PlannerWithCostmap::PlannerWithCostmap(string?name,?Costmap2DROS*?cmap)?:GlobalPlanner(name,?cmap->getCostmap(),?cmap->getGlobalFrameID())?{ ros::NodeHandle?private_nh("~");cmap_?=?cmap;make_plan_service_?=?private_nh.advertiseService("make_plan",?&PlannerWithCostmap::makePlanService,?this);pose_sub_?=?private_nh.subscribe<rm::PoseStamped>("goal",?1,?&PlannerWithCostmap::poseCallback,?this);}1.通过make_plan服务
req.start.header.frame_id?=?"map";req.goal.header.frame_id?=?"map";bool?success?=?makePlan(req.start,?req.goal,?path);2.通过goal回调函数
//得到当前机器人在MAP中的位置cmap_->getRobotPose(global_pose);makePlan(global_pose,?*goal,?path);在getRobotPose函数中,通过tf_.transform(robot_pose, global_pose, global_frame_);函数,默认将机器人pose从base_link转换到map坐标系下,可通过参数设置。得到起始点和目标点传入到makePlan中。
二丶 planner_core.cpp//register?this?planner?as?a?BaseGlobalPlanner?pluginPLUGINLIB_EXPORT_CLASS(global_planner::GlobalPlanner,?nav_core::BaseGlobalPlanner)global_planner 是基类nav_core :: BaseGlobalPlanner的一个插件子类
首先在构造函数中需要初始化GlobalPlanner,在initialize中对一些参数进行赋值。
GlobalPlanner::GlobalPlanner(std::string?name,?costmap_2d::Costmap2D*?costmap,?std::string?frame_id)?:GlobalPlanner()?{ //initialize?the?plannerinitialize(name,?costmap,?frame_id);}当调用makePlan时,首先就是判断是否已经被初始化:
//?code?line?~?makePlan()if?(!initialized_)?{ ROS_ERROR("This?planner?has?not?been?initialized?yet,?but?it?is?being?used,?please?call?initialize()?before?use");return?false;}m初始化完成之后,清除之前规划的Plan,以防万一。然后检查起点和终点是否在我们所需要的坐标系下,一般在map系下。
//clear?the?plan,?just?in?case?,?code?line??makePlan()plan.clear();if?(goal.header.frame_id?!=?global_frame)?{ ...}if?(start.header.frame_id?!=?global_frame){ ...}将世界坐标系的点(map 坐标系)转换成图像坐标系(图像左下角)下的点(以像素表示)
if?(!costmap_->worldToMap(wx,?wy,?goal_x_i,?goal_y_i))?{ ROS_WARN_THROTTLE(1.0,"The?goal?sent?to?the?global?planner?is?off?the?global?costmap.?Planning?will?always?fail?to?this?goal.");return?false;}在Costmap2D和GlobalPlanner中都有实现worldToMap,其实都是一样的,在GlobalPlanner中则需要通过调用Costmap2D来获取局部地图的起始点和分辨率,而在Costmap2D则可以直接使用全局变量。
bool?Costmap2D::worldToMap(double?wx,?double?wy,?unsigned?int&?mx,?unsigned?int&?my)?const{ ?if?(wx?<?origin_x_?||?wy?<?origin_y_)return?false;?mx?=?(int)((wx?-?origin_x_)?/?resolution_);?my?=?(int)((wy?-?origin_y_)?/?resolution_);?if?(mx?<?size_x_?&&?my?<?size_y_)return?true;?return?false;}old_navfnbehavior ?作为一种旧式规划行为:
The start of the path does not match the actual start location.
The very end of the path moves along grid lines.
All of the coordinates are slightly shifted by half a grid cell
现在在worldToMap所使用的convert_offset_ = 0
接下来将机器人Robot所在的位置,在costmap中设置成free,当前位置不可能是一个障碍物。 即在clearRobotCell()函数中:mx,my即当前机器人位置。
PlannerWithCostmap::PlannerWithCostmap(string?name,?Costmap2DROS*?cmap)?:GlobalPlanner(name,?cmap->getCostmap(),?cmap->getGlobalFrameID())?{ ros::NodeHandle?private_nh("~");cmap_?=?cmap;make_plan_service_?=?private_nh.advertiseService("make_plan",?&PlannerWithCostmap::makePlanService,?this);pose_sub_?=?private_nh.subscribe<rm::PoseStamped>("goal",?1,?&PlannerWithCostmap::poseCallback,?this);}0设置规划地图边框:outlineMap,此函数由参数outline_map_决定。 根据costmap跟起始终止点计算网格的potential,计算的算法有两种:Dijkstra和A*,具体算法便不再讨论,资料很多。 当提取到plan之后,调用getPlanFromPotential,把path转换变成geometry_msgs::PoseStamped数据类型。
PlannerWithCostmap::PlannerWithCostmap(string?name,?Costmap2DROS*?cmap)?:GlobalPlanner(name,?cmap->getCostmap(),?cmap->getGlobalFrameID())?{ ros::NodeHandle?private_nh("~");cmap_?=?cmap;make_plan_service_?=?private_nh.advertiseService("make_plan",?&PlannerWithCostmap::makePlanService,?this);pose_sub_?=?private_nh.subscribe<rm::PoseStamped>("goal",?1,?&PlannerWithCostmap::poseCallback,?this);}1此时便得到所需要的路径plan,最终调用OrientationFilter平滑之后发布出去。
PlannerWithCostmap::PlannerWithCostmap(string?name,?Costmap2DROS*?cmap)?:GlobalPlanner(name,?cmap->getCostmap(),?cmap->getGlobalFrameID())?{ ros::NodeHandle?private_nh("~");cmap_?=?cmap;make_plan_service_?=?private_nh.advertiseService("make_plan",?&PlannerWithCostmap::makePlanService,?this);pose_sub_?=?private_nh.subscribe<rm::PoseStamped>("goal",?1,?&PlannerWithCostmap::poseCallback,?this);}22024-12-24 00:36
2024-12-23 23:32
2024-12-23 22:56
2024-12-23 22:05
2024-12-23 22:04