自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(60)
  • 问答 (1)
  • 收藏
  • 关注

原创 Google 的 C++编程规范

Google 的C++编程规范及C++类型推导;

2024-03-22 11:41:34 915

原创 STL中 function 源码解析

类模板std::function是一个通用的多态函数包装器,可以指向任何可调用对象,如何理解其行为,并且理解其中所付出的代价是至关重要的;本文基于GCC 9.4的实现解析其本质;

2024-03-22 11:39:54 928

原创 SRPC 框架服务端源码解析

SRPC是个轻量级、高性能、代码量很少开源的C++ RPC框架,目前在公司每天超百亿线上请求,兼具学习+使用的特点,非常适合初学者进行学习;

2024-01-25 21:41:39 1209 1

原创 C++中实现多线程和分布式

每块磁盘都有一个操作队列,多线程磁盘 IO 的一个思路是每个磁盘配一个线程,把所有针对该磁盘的 IO 都挪到同一个线程中,才可能比单线程快;(2)对于 需要写入但不需要等待响应的请求,可以使用 BlockingQueue 完成,例如 log,由一个专门的线程去写入文件,其他线程只需要往 BlockingQueue 写入即可;一个线程从 fd 收到耗时请求,并记住要把处理结果发送给 fd,但在处理过程中,fd 断开了连接,有新的连接到来,碰巧使用了相同的 fd。(3)线程池大小的阻抗匹配原则。

2024-01-19 15:57:26 835

原创 muduo 网络库源码解析和使用

Muduo库是陈硕开发的Tcp网络编程库,采用了Reactor模型,非常适合网络编程初学者。出于个人学习目的阅读了其源码实现,并梳理了其中核心模块的执行流程,以及试图揣测作者一些部分的实现心得,并从中学到了很多工程实践知识,首次切实感受到多线程的种种困境;

2024-01-19 15:55:12 1136

原创 Linux多线程服务端编程:线程安全的对象管理

注意,构造 shard_ptr 时,使用 模板类型推导 保存了 T1 的类型(而非 T 的类型,因为 T 可能是 T1 的基类),从而可以调用其相应析构函数(即使基类的析构函数不是虚函数,详见。(2)const 成员函数中可以修改静态数据成员,不可以修改非静态成员(此处的理解是,从语义方面来讲,静态成员变量类似于全局变量,不属于某个对象,因此不算是对对象进行了修改。(1)一个对象可被多线程观察到,线程 A 调用析构函数,线程 B 调用该对象其他函数,就可能会导致意想不到的后果;

2023-12-27 21:00:50 889

原创 智能指针篇------STL源码分析:shared_ptr 和 weak_ptr、unique_ptr

探究STL中 shared_ptr 和 weak_ptr 源码,分析其各种机制的实现原理:例如 析构动作在创建时捕获、weak_count 的作用、enable_shared_from_this 的实现机制

2023-12-27 17:39:41 1018

原创 网络编程:多进程和多线程编程

初始化时,shm_lpid、shm_nattach、shm_atime、shm_dtime 设置为 0,shm_ctime 设置为当前时间;创建共享内存,所有字节都被初始化为 0,与之关联的内核数据结构为 shmid_ds 被创建和初始化;作用是创建并初始化它,会将 sem_otime 设为 0,sem_ctime 设为当前系统时间;num_sems 指定信号量集中信号量的数目;操作,会更新进程的 semadj 变量,,来跟踪进程对信号量的修改情况;创建一个新的信号量集,或者获取一个已经存在的信号量集;

2023-12-22 20:37:54 98

原创 网络编程:信号、定时器、Libevent

一个进程给其他进程发送信号// 成功返回 0,失败返回 -1 并设置 errno目标进程由 pid 指定pid取值含义pid > 0信号发送给 PID 为 pid 的进程pid = 0信号发送给本进程组内的其他进程pid = -1发给除 init 进程外的所有进程,发送者需要拥有对目标进程发送信号的权限pid < -1发给 PGID 为 -pid 的进程组的所有成员信号值 sig 为 0,不发送任何信号(检测目标进程或进程组是否存在,这种检测方式不可靠);

2023-12-22 11:30:44 129

原创 高性能服务器框架及 IO 复用

服务器同时监听多个客户请求是通过select系统调用实现的;

2023-12-08 21:41:45 848

原创 高级IO函数

prot 设置访问权限,取值为 PROT_READ(可读)、PROT_WRITE(可写)、PROT_EXEC(可执行)、PROT_NONE(不能被访问) 这几个值的按位或;(2)输出,默认情况下,调试信息会保持到 /var/log/debug 中,普通信息到 /var/log/messages,内核消息到 /var/log/kern.log;中 pid 为 0,表示设置当前进程的 PGID 为 pgid;,会使得调用进程成为会话的首领,会新建一个进程组,调用进程成为该组首领,调用进程将甩开终端;

2023-12-08 10:07:19 57

原创 TCP 选项

在高速网络中,32 位序列号很容易使用完然后又从 0 开始,假设前面第一个 32 位序列号范围内的某个报文段丢失重传,但第二个 32 位序列号范围内的已经开始传输,接收方可能就无法区分接收到的报文段是属于重传的还是第二个范围内的,此时通过发送时间戳可以进行区分,因此接收者可以将时间戳看作一个 32 位的扩展序列号;主动连接的一方发送了一个非 0 的比例因子但没有收到对方的窗口缩放选项,会将自己发送与接收的比例因子都设为 0;三次握手的目的:交互初始序列号(ISN),利用数据包的选项承载特殊信息;

2023-12-07 15:33:15 105

原创 网络编程基础api

系统调用进入 LISTEN 状态,监听到某个连接请求时(收到 SYN),将该连接放入内核等待队列,发送 SYN + ACK,收到 ACK 后,进入 ESTABLISHED 状态;一个每个分片都有自己的 IP 头部,它们都具有相同的标识值,有不同的片偏移(数据部分的长度必须是 8 的整数倍),除了最后一个分片外,其他分片都设置 MF 标志;(2)type 指定服务类型,SOCK_STREAM(流服务)和 SOCK_UGRAM(数据报)对 TCP/IP 而言,前者表示使用 TCP,后者为 UDP;

2023-12-07 15:32:12 1202

原创 C++部分知识点对应汇编代码

动态内存调用,因为事先知道类的大小,因此首先将该类大小作为第一个参数,调用new函数申请空间,再调用相应构造函数。这种方式在类初始化时比较简单,因为已经知道基类大小,只需要初始化基类1,偏移基类1大小,初始化基类2即可。因此对于常量成员或引用类型成员,必须在初始化列表中进行初始化,因为它们无法在构造函数体内赋值。通过类对象调用函数时,this指针会作为第一个参数。

2023-11-20 16:26:12 85

原创 事务隔离级别和MVCC

InnoDB 把当前系统中所有的 ReadView 按照创建时间连成一个链表,当执行 purge 操作时,就把系统中最早生成的 ReadView 取出来(如果没有则新创建一个 ReadView ),然后从各回滚段的 History 链表取出 trx_no 较小的各组 undo log,如果该组日志的 trx_no 小于 ReadView 中的 trx_no,就会释放该组日志,如果该组日志包含因 delete mark 操作产生的 undo log,也要把相应记录真正删除。

2023-11-15 20:23:06 312

原创 InnoDB中 redo log 和 undo log、binlog

(2)有些需要保证原子性的操作生成多条 redo 日志,在该组最后一条 redo 日志后面加上一个特殊类型的 redo 日志(MLOG_MULTI_REC_END,该类型只有一个 type 字段(十进制的 31));服务器在内存中维护一个全局变量,每当向某个包含 row_id 隐藏列的表中插入一条数据时,就会将当前全局变量的值做为新纪录的 row_id 列的值,并将该全局变量自增 1;LRU 链表优化:只有被访问的缓冲页位于 young 区域的后 1/4 页面时,才会被移动到 LRU 链表的头部。

2023-11-13 21:46:09 102

原创 MySQL 是怎样运行的:基于规则的优化和EXPLAIN详解

与 s1 INNER JOIN s2 ON s1.key1 = s2.key2 相比,在内连接中对于 s1 表中的某个key1 记录,在 s2 表中可能有多条 key2 记录与之匹配,这会导致该记录被多次加入结果集。Table pullout:子查询的查询列表处只有主键或者唯一索引列,可以直接转换为内连接,因为 s2.key2 是唯一的这样就不会 s1.key1 能够匹配多条 s2.key2 的情况。(2)总结:MySQL在执行时,会优先尝试把派生表与外层循环合并,如果不行,再将派生表物化。

2023-11-13 16:35:47 196

原创 MySQL 是怎样运行的:单表访问方法、Join及基于成本的优化

对聚簇索引,本身就是按照主键顺序排序的,可以是范围查询,因为二级索引是包含索引列和主键的,在索引列值相同的情况下,是按主键排序的,只需扫描二级索引即可,并不需要扫描聚簇索引。很多情况下无法保证二级索引记录按照主键排序,例如范围扫描,此时要进行额外的排序工作。这里的合并是,先根据二级索引得到二级索引记录,先不进行回表,等合并后,再进行回表操作。这对二级索引来说,相当于要求等值查询,而非范围查询,并且需要给定所有的索引列。要求从每个索引中获取到的二级索引记录都是按照主键值排序的。

2023-11-07 19:54:53 160

原创 MySQL 数据目录和 InnoDB 表空间补充知识:详细结构

在Ubuntu下,MySQL的数据目录为(1)创建数据库时,会在数据目录下创建一个与数据库名同名的子目录。(除了这个系统数据外)(2)db.opt文件存储数据库的一些属性MySQL 8.0 之后不再提供(1)表结构定义。文件(2)表数据(1)系统表空间。只有一份,默认为数据目录下的文件(2)独立表空间;文件。、分别表示表的数据文件和索引文件每个页都包含了和(1)表空间下描述页号,4字节,因此一个表空间最多 64TB,即 (2^32)*16KB(2) 和 上/下页的页号,主要是数据页(INDEX 类型)使用

2023-11-07 16:24:28 234

原创 InnoDB 补充知识

从左到右各数字分别代表最多字符数、File_Head、Page_Head、Infimun和Supremum记录、Page Directory(最少为两个,Infimun 和 Supremum 各为一个 Slot)、File Trailer、变长字段最大长度、记录头信息、隐藏事务ID列、回滚指针列、隐藏主键;(之所以使用 127 作为区分,是因为可根据变长字段中存储的字节的第一个二进制位作为标志,若字节最高位为 1,说明该字节代表了半个字段长度,为 0 代表了单独的字段长度)。

2023-11-01 22:47:26 112

原创 MySQL 启动选项和字符集

MySQL 服务器采用线程池的方式,为每个连接进来的客户端分配一个线程。(客户端的数量会有限制,默认为 `max_connections = 151`,严格来讲还有额外一个是为超级用户准备的)客户端发起连接时,需要携带主机信息、用户名、密码等信息,服务器会进行验证。MySQL 服务器接收到的请求只是一个文本消息。

2023-11-01 15:53:48 440

原创 InnoDB事务

其记录了当前活跃事务ID列表及下一个开始事务的ID,因此可将事务分为:已经提交事务(min_trx_id,当前活跃事务列表中的最小值),正活跃事务列表(m_ids),未开始事务(max_trx_id)。如果开启新的写事务的话,其看到的最大的 trx_no 为 3 ,而trx_no为2的事务产生的Undo Log可以被删除,从上也可知删除Undo Log 1不会产生影响。Undo Log 2是在事务ID为 47 的 Update Undo Log,其正常提交后,trx_no为3。

2023-10-22 15:54:53 42

原创 InnoDB中的锁

(4)插入语句在插入一条记录之前,需要先定位到该记录在 B+树 的位置,如果插入的位置的下一条记录的索引上有间隙锁,才会发生阻塞。(7)通过索引以SLock的方式查询一个值时,即使查询的值不存在,其锁定的也是一个范围,即Gap Lock。当前事务持有了待插入记录的下一个记录的X锁,但是在该记录的等待队列中还存在一个S锁的请求,可能会发生死锁。(2)Next-Key Lock已经把 (1,3) 锁了,为什么还需要Gap Lock锁住(3,6)呢?(3)书中介绍,是对下一个键值加上Gap Lock。

2023-10-17 11:36:21 35

原创 InnoDB索引

(1)其采用了full inverted index的方式,辅助表中有两个列,一个是word字段,一个是ilist字段(DocumentID, Position),并且在word列设有索引;当数据库宕机时,缓存中的数据会丢失,重启数据库时,当用户对表进行全文检索时,InnoDB会自动读取未完成的文档,进行分词操作,再将分词结果放入到FTS Index Cache中。这里有个问题:如果按照上述分裂方式,那么在插入后删除,就会导致频繁的分裂和合并,应该是限定在插入的场景下使用。

2023-10-14 15:42:24 29

原创 Innodb表空间及存储格式

这个单独的表空间文件存放:该表的数据、索引和插入缓冲BITMAP等信息,其余信息(如undo信息、插入缓冲索引页、系统事务信息、doublewrite)仍存放在默认的表空间中(表中存在主键或唯一索引时,分区列必须是唯一索引的一个组成部分(不需要整个唯一索引列都是分区列,允许NULL值)。使用完这些后,才是64个连续页的申请。,在数据的导入操作,会对导入的每一行都进行外键检查,比较耗时,可以在导入过程中忽略外键检查。(1)段包含数据段、索引段、回滚段等,因为InnoDB是索引组织表,数据段和索引段一样。

2023-10-11 21:03:40 94

原创 Innodb体系结构

G是垂直显示;

2023-09-25 20:19:43 40

原创 高性能MySQL篇

默认采用自动提交(AUTOCOMMIT)模式,即除非显示开始事务,否则每个查询都被当成一个事务执行提交。InnoDB目前处理死锁的方法:将持有最少行级排它锁的事务进行回滚。可重复读是MySQL的默认隔离级别,而大多数数据库是读提交。MySQL最重要的特性是存储引擎架构。用户认证、是否具有执行某个查询的权限。

2023-09-25 15:34:14 65

原创 git版本控制工具的原理及常用指令

git的原理:通过维护一系列快照实现;并且额外维护了作者及提交时间戳等元数据跟踪源代码或其他文件的修改记录的工具,支持多人协作

2023-09-24 08:52:07 35

原创 STL红黑树

(1)插入左子树情况需要进行双边界判断的情况,举例说明:对于下述树,如果插入2,插入位置在结点3的左子树。:在上述函数中,若当前节点为header节点,则对其自增,下一个节点为最大的节点,尤其是在使用。但为了保证插入值是唯一的(即之前未出现在红黑树中),还需要做一些额外的判断。在该函数中,首先按照二叉搜索树的性质找到叶子节点,同时不断维护其父节点。(2)为何插入右子树不需要找到 父节点的后继节点进行上述双边界判断?的情况下,很容易混淆普通节点和header节点。结点的右子树,那么在遍历过程中,必定经过了。

2023-08-28 11:33:56 40

原创 STL中string和deque的实现

(3)重新分配时,判断当前数组大小是否大于新结点数量的2倍,若满足,说明有空间,但当前位置太靠前,则只需要进行移位即可。具体而言,是在左侧找比枢轴大的元素,右侧找比枢轴小的元素,进行交换。确定最大的迭代深度,这里的乘2的含义是:假设是理想情况下,每次都能选取到区间中位数的情况,这样每一边都是。需要判断下哪边的元素数量较小,则移动哪边,调用带三个参数的。,若满足,则说明此buffer中还有空间,向该buffer中添加元素,调整。函数,先判断是否是插入最前面或最后面的情况,若是,则调用相应的。

2023-08-16 15:42:46 26

原创 C++中STL底层实现:vector、list和unordered_map

(2)二次探测:表格大小为质数,负载系数在0.5以下,可以确定插入新元素所需的探测次数不多于2。(目前gcc的实现中,不光是bucket对应的节点采用链表相连,所有节点都是采用链表相连)如果采用有参构造函数,即构造时指定数量,才会创建出2,3,5~13等素数的大小的bucket,如果采用的是默认构造函数创建,则在第一次插入元素时分配一个较大值。这主要是由于主集团的存在,使得发生冲突的概率增加,并且又会增长主集团的大小。)计算出下一个bucket值,采用2倍的关系查找下一个bucket数量(实际上是。

2023-08-06 21:34:11 329

原创 CMU 15-445 (2023 Spring)数据库实验p4记录--完结篇

全局的LM根据隔离级别授予或释放锁。

2023-07-30 21:42:24 303

原创 数据库并发协议和恢复

(1)no-steal + force 当事务提交的page中包含有未提交事务的修改时,需要进行复制,撤销那些不想要的修改。写入时,创建新的版本,其开始时间设置为当前事务的时间戳,结束时间设置为无穷大。的话,如果锁是tuple级别的,那么就无法阻止插入操作,就会插入新数据,从而造成读取到新插入数据的问题。版本存储:tuple的版本通过链表相连,索引总是指向链表的头部,这会产生两种顺序:从新到旧,从旧到新。情况的发生,既发生脏读的情况,因为T1终止了,T2可能读到了T1之前修改的值,只能也进行终止。

2023-07-17 19:19:25 85

原创 CMU 15-445 (2023 Spring)数据库实验p3记录

当一个函数返回一个对象的拷贝时,如果使用移动语义进行复制,会阻碍编译器的优化。(1)强制情况,一定会触发copy elision的两种情况:(此时如果使用移动语义就会造成不必要的麻烦)当return语句返回的对象是一个纯右值,且该对象类型与函数返回值类型相同时初始化对象时,使用相同类型的纯右值初始化表达式A f() {return A();

2023-07-10 22:11:58 231

原创 使括号串有效的最少修改次数

字符串中只包含’(‘、’)‘、’[‘、’]‘、’{‘、’}'这6种字符,将此括号串修改为。匹配的情况需要的次数,然后就可以将整个问题分解为两个更小的问题。示例:{[)[,输出为2;之间的字符修改为有效括号串的最少修改次数。(1)将中间某一字符修改为和。(2)将中间某一字符修改为和。思路: 采用动态规划的思想。

2023-07-03 15:04:02 281

原创 数据库操作执行

(2)如果是Secondary Indices,虽然各叶子节点中的数据对应不同的物理block,但其实也可以进行优化,就是对叶子节点每个record_id先不去获取其在物理block,先记录下来其page_id,最后一起获取,从而避免多次随机读取的情况。根据哈希函数可以将JoinAttrs属性值映射为整数,因此就能对各关系进行划分,有相同属性值的被划分到同一个区域,相当于桶排序的思想。crab算法提出了安全节点的概念,在父节点处会获得子结点的锁,如果子结点是安全结点,则可以释放父结点的锁。

2023-06-25 16:45:13 94

原创 CMU 15-445 (2023 Spring)数据库实验p2记录

因此采用了多个读写锁的方式,在project 1中也能获得2w多分,与简单的大锁方式有显著提升,但在P3中,还没有大锁得分高,比较奇怪。,假设我就强行指定原节点就保留一个key,剩下的都给新节点,只要向上层插入的key是正确的就可以保证有正确的行为。(1) 这里按照书中伪代码来写即可,在进行split时,书中伪代码首先将原先节点读入内存(作为局部变量),进行插入后,再进行分配。,因为其使用的是线性搜索的策略,比较慢。中实现写回磁盘的操作,也可以避免这种情况的发生,但感觉会造成多次的写入,因为。

2023-06-24 21:05:13 350

原创 二叉树序列化和反序列化

其左孩子在完全二叉树中的位置为$2*(i + cur_total) + 1 $, 但其需要去掉这些补全的东西,找到其真实位置。若想对其进行补全,我们需要统计null出现次数,由于null对不同层的补全效果不同,需要对前面层出现的null进行统计。关于层数的统计,使用的是第一层为1,第二层为2,第三层为4,依次类推。想象一下,如果我们可以对这个二叉树补全为完全二叉树,那么就很容易得到根和孩子节点之间的关系,反序列化就很容易。序列化时的终止条件为:如果当前层的孩子节点都为null时则结束,避免不必要的遍历。

2023-06-15 17:14:47 118

原创 CMU 15-445 (2023 Spring)数据库实验p0及p1记录

这样代表着调用这两个函数是仍能进行读的操作,这两个操作都是通过复制实现,因此在修改时,不会改变原先根结点的内容,所有可以处理读的操作,当修改完成后,再更新根结点.目标是能够并发的实现多读和单写,这里只是加锁,调用上述实现的函数即可.获取根结点时注意要加锁。

2023-06-04 22:08:29 1023

原创 数据库存储管理

例如,查询q1需要扫描表t1(假设其包含6个page),当其扫描到page3时,来了一个新查询,那么新查询的游标也被置为page3,然后读取page3后,这两个查询都可以使用其中的数据,新旧查询共享3~5,新查询只需再额外找到0 ~ 2即可。之后也可以进行压缩存储,例如对温度变化小的屋子,刚开始的初始值存储完整的值,后续的值只需存储变化的幅度即可。插入时,视数据库的实现方式,一般是直接在后面插入tuple,不会重用之前删除的空间,若想重用之前删除的空间,需要调用专门函数进行调整。因此可能需要重建哈希表。

2023-06-02 14:54:45 298

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除