自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(80)
  • 收藏
  • 关注

原创 C语言static和inline

如果一些源文件要使用该函数,由于static函数仅在当前源文件作用域可见,那么必须在每一个要使用该函数的源文件中都有函数实现,如果仅在一个源文件中实现,其他源文件使用则会编译错误,因为这个实现对于其他源文件是不可见的。static变量的作用域只限制与定义它的源文件中,其他源文件不能访问。如果头文件中有static变量,由于不同源文件中的static变量可以同名,那么在所有包含该头文件的源文件中都定义了仅自己可见的static变量,不同源文件中使用的也是仅属于自己的static变量,绝不是同一个。

2023-04-23 10:15:44 1121 1

原创 README

简单易用的vim配置,熟练后可大大提高开发效率(VS Code的两倍以上)。

2023-02-28 12:08:34 485

原创 EasyVim:简单强大的VIM配置

简单易用的vim配置,熟练后可大大提高开发效率(VS Code的两倍以上)。

2023-01-12 11:30:43 765

原创 30天自制C++服务器day16-重构服务器、使用智能指针

至此,本教程进度已经过半,在前15天的学习和开发中,相信大家对服务器的开发原则、核心模块的组织有了一个初步的了解,也有能力写出一个“乞丐”版本的服务器。包括内存相关的,如内存泄漏、野指针、悬垂引用等,还有网络编程相关的,如无效socket、连接意外终止、TCP缓冲区满等,还有事件相关的,如epoll、kqueue返回其他错误情况,等等。重构的另一个重点,就是避免资源的复制操作,尽量使用移动语义来进行所有权的转移,这对提升程序的性能有十分显著的帮助,这也是为何rust语言性能如此高的原因。

2022-11-04 23:05:35 372

翻译 事务的隔离性

SQL标准规定了四个隔离级别。这些级别是由在并发事务执行过程中可能或不可能发生的异常所定义的。因此,在谈论隔离级别时,我们必须从异常入手。我们应该记住,标准是一个理论性的构造:它影响着实践,但实践仍然在很多方面与它相背离。这也是为什么这里所有的例子都是假设性的。在处理银行账户的交易时,这些例子是一目了然的,但我不得不承认,它们与真正的银行业务没有任何联系。有趣的是,实际的数据库理论也与标准相背离:它是在标准被采用后才发展起来的,而实践已经远远领先。

2022-09-16 12:28:32 117

原创 csblog: 一站式秃头孵化基地

学习计算机过程中,有很多高质量博客,但资源分散,许多资源不被人所知,经常漫无目全网查找。csblog网站是对全网优质计算机相关资源的整理,可以让初学者少走弯路。只需要知道这个网站,就可以学好计算机并找到满意的工作。30天自制C++服务器。...

2022-08-30 09:53:12 630

原创 PostgreSQL自定义文本检索分词规则

由于是为文本检索而设计,所以默认的分词规则和字典都是按照自然语言的规则来实现。但对于以上需求,已经不是文本检索,而是为了使用文本检索+倒排索引实现自己的查询需求,所以分词器也需要自定义。PostgreSQL提供了丰富的字典自定义方法,可以很轻松地对字典的规则进行自定义。,仅使用了空格作为token的分割符,所有token都是一种类型,完成了需求。,将会影响到正常文本检索的分词逻辑,所以使用插件的方式新增一个分词规则。接下来自定义一个分词器,实现自定义规则拆分token的功能。......

2022-08-18 17:32:01 777

原创 PostgreSQL文本搜索(七)——自定义配置

有几个预定义的文本搜索配置可用,你也可以很容易地创建自定义配置。为了便于管理文本搜索对象,有一组SQL命令可用,还有几个psql命令可以显示文本搜索对象的信息。所需的所有选项:使用词法分析器将文本分解为token,以及使用词典将每个token转化为lexeme。指定了默认配置的名称,如果省略了一个明确的配置参数,文本搜索函数就会使用这个配置。我们将使用一个PostgreSQL专用的同义词列表,并将其存储在。的调用都需要一个文本搜索配置来执行其处理。下一步是设置会话使用新的配置,该配置是在。...

2022-08-18 16:19:52 594

原创 PostgreSQL文本搜索(六)——词典

词典用于消除在搜索中不应考虑的词(停顿词),并使词规范化,以便同一词的不同派生形式能够匹配。一个成功规范化的词被称为lexeme(词位、词素)。除了提高搜索质量之外,规范化和删除停顿词可以减少文档的tsvector的大小,从而提高性能。规范化并不总是具有语言学意义,通常取决于实际应用决定的语义。TSL_FILTERPostgreSQL为许多语言提供预定义的词典。也有几个预定义的模板,可以用来创建带有自定义参数的新词典。下文描述了每个预定义的词典模板。...

2022-08-18 11:39:38 511

原创 PostgreSQL文本搜索(五)——词法分析器

文本搜索词法分析器负责将原始文档文本分割成token,并确定每个token的类型,其中可能的类型集合由词法分析器本身定义。注意分析器根本不修改文本,它只是识别合理的词的边界。由于这种有限的范围,对特定应用的自定义分析器的需求比对自定义字典的需求要少。目前PostgreSQL只提供了一个内置的分析器,它已经被发现对广泛的应用很有用。仅包含基本ASCII字母的词被报告为一个单独的token类型,因为有时区分它们是很有用的。分析器对"字母"的概念是由数据库的区域设置决定的,特别是。内置的分析器被命名为。...

2022-08-18 09:14:46 180

原创 PostgreSQL文本搜索(二)——表和索引

上一节的例子说明了使用简单的常量字符串进行全文匹配。本节展示了如何搜索表数据,或选择使用索引。

2022-08-17 10:41:56 405

原创 PostgreSQL文本搜索(一)——简介

文档是全文检索系统中的检索单位,例如一篇杂志文章或一封电子邮件。文本搜索引擎必须能够解析文档并存储词位(关键词)与它们的父文档的关联。之后,这些关联被用来搜索包含查询词的文档。对于PostgreSQL中的搜索,一个文档通常是数据库表中的一行文本字段,或者可能是这种字段的组合(连接),可能存储在几个表中或动态地获得。换句话说,一个文档可以由不同的部分构成索引,它可能不会作为一个整体存储在任何地方。......

2022-08-15 14:09:12 1323

原创 PostgreSQL内存上下文

内存的访问速度至少是磁盘的数十万倍,所以通常读写磁盘所用的时间决定了数据库操作的总时间,而内存的访问时间可以忽略不计。除此之外,内存管理还是整个数据库系统的桥梁,每一个模块都会使用到内存进行函数运行、缓冲、消息传递等,内存管理对于数据库来说十分重要。一个内存上下文就相当于一个进程的内存环境,每个进程的内存上下文组成一个树行结构,其根节点为。在每个内存块中可以进一步分配内存,产生的内存片段叫做内存片(AllocChunk),包括一个头部和数据区域,为内存片的头部,数据区域则紧跟在头部信息之后分配,通过。...

2022-08-09 16:29:26 463

原创 PostgreSQL插件开发

PostgreSQL中许多控制信息都是以系统表的形式来管理,这个特点决定了PostgreSQL比其他数据库更容易进行内核扩展。PostgreSQL还提供了丰富的数据库内核编程接口,允许开发者以插件的形式将自己的代码融入内核。PostgreSQL插件开发非常简单,下面举一个例子,开发一个随机测试数据生成器。...

2022-08-01 14:18:16 943

原创 PostgreSQL可见性映射表(VM)和VACUUM操作

VM文件仅在快速清理中被用到,对于FULLVACUUM,由于要执行跨页清理等复杂操作,还是需要扫描整个表文件,此时VM作用不大。当前VM文件是一个提示(hint)来加快VACUUM的速度,即使损坏了VM文件,仅仅会导致VACUUM忽略那些需要清理的页面,但元组的可见性依然不变,所以对数据不会产生任何影响。当页中所有的元组对于当前事务都是可见的,VM中对应的位为1,表示没有无效元组。当页在VM中对应的标志为是1时,VACUUM会忽略对应的页,大大提高VACUUM的效率。每个VM文件的页中,可用的字节为。...

2022-08-01 10:25:19 550

原创 PostgreSQL 空闲空间映射表(FSM)

当我们需要插入新的元组时,需要优先将元组放到已有页内的空闲空间内,以节约存储空间。但我们怎么知道哪个页中有空闲空间、空闲空间的大小是否足够存放新的元组呢?如果没有其他任何技术,则需要遍历页、直到找到足够的空闲空间用于插入新元组,这样开销将会非常大。为了解决这个问题,PostgreSQL使用了空闲空间映射表(FSM)来记录所有表文件的空闲空间信息。为了更快的查找,FSM文件也不是使用数组存储每个页的空闲空间,而是使用了一个三层树结构。第0层和第1层是辅助层,第2层用于实际存放各表页中的空闲空间字节位。...

2022-08-01 10:04:23 307

原创 PostgreSQL插入大量数据:pg_testgen插件

在进行数据库开发、测试时,新建表之后,时常想自己插入数据,但十分麻烦。pg_testgen插件可以产生大量随机数据,方便进行数据库开发测试。

2022-07-28 18:39:21 558

原创 openGauss列存数据压缩实验

float值为0到100的随机浮点数,timestamp值为日期相同、一日中时间不同的随机事件戳(日期相同是为了更符合时序场景)。对于时序场景,float和timestamp类型占比较大,需要重点关注,较高的压缩率可以降低磁盘空间的使用。本次实验针对float和timestamp类型,测试了openGauss列存储引擎的数据压缩率。openGauss版本为3.0.0,表大小为50万条数据。......

2022-07-27 17:09:18 325

原创 openGauss源码解析——列存压缩算法

如果字典压缩失败或者没有允许使用字典压缩,则直接对于LOW和MIDDLE级别使用lz4压缩,对于HIGH级别使用zlib压缩。如果是IntLike(类整型)char类型则由IntegerCoder类完成,先使用Delta压缩,如果开启了RLE则使用RLE压缩,如果压缩级别为MIDDLE或HIGH,则还需要进行lz4或zlib压缩。对于IntegerCoder类的压缩,会先进行Delta压缩,如果使用RLE的话再使用RLE压缩,然后对压缩级别为MIDDLE和HIGH的情况分别使用lz4和zlib压缩。....

2022-07-27 10:55:06 378

原创 PostgreSQL VFD——虚拟文件描述符

VFD的原理类似于进程池、内存池等池化技术,当进程申请打开一个文件时,总能分配一个虚拟的文件描述符,是真实文件描述符的一个上层封装。VFD使用LRU(最近最少使用)池来管理所有已经打开文件,当进程打开的文件个超过操作系统限制时,也可以申请一个新的VFD,从LRU链表中替换最长时间未使用的VFD并关闭相应的实际文件描述符。VFD也会管理一个空闲VFD链表,方便获取当前空闲的VFD。在操作系统中,每当一个进程打开一个文件,系统就会为该文件分配一个唯一的文件描述符,在Linux系统中是一个。...

2022-07-18 09:49:58 242

原创 PostgreSQL表和元组的组织方式

每一个tuple存储一条数据记录,从数据页底部开始向前依次存储,这些堆元组的地址由一个4B大小的行指针所指向。这些行指针内还保存了堆元组的长度,并形成一个简单的数组,扮演元组索引的角色。如需要定位某数据表中的一条记录,只需要知道该记录在堆文件中的页号和页面内的行指针偏移号即可。除此之外,每个页面的起始位置有大小为24B的页头,保存页面相关的元数据。行指针和尾部的tuple之间是该页面的空闲空间...

2022-07-15 15:42:16 395

原创 行存与列存——数据表的存储方式

行存与列存——数据表的存储方式

2022-07-14 14:29:07 1007

原创 页大小——数据库文件IO的基本单位

页大小——数据库文件IO的基本单位

2022-07-14 14:27:39 895

原创 wheelib: 一个为编程学习而生的C语言轮子库

wheelib: 一个为编程学习而生的C语言轮子库

2022-06-02 17:07:44 147

原创 开箱即用的Makefile

开箱即用的Makefile

2022-06-02 17:06:06 77

原创 30天自制C++服务器day15-macOS支持、完善业务逻辑自定义

day15-macOS、FreeBSD支持作为程序员,使用MacBook电脑作为开发机很常见,本质和Linux几乎没有区别。本教程的EventLoop中使用Linux系统支持的epoll,然而macOS里并没有epoll,取而代之的是FreeBSD的kqueue,功能和使用都和epoll很相似。Windows系统使用WSL可以完美编译运行源代码,但MacBook则需要Docker、云服务器、或是虚拟机,很麻烦。在今天,我们将支持使用kqueue作为EventLoop类的Poller,使网络库可以在macO

2022-02-06 17:34:09 1399 1

原创 Flash-DBSim 用于进行闪存技术研究的仿真工具

Flash-DBSim Simulation SystemFlash-DBSim is a simulation tool for evaluating Flash-based database algorithms used for flash-based researches, we’d like to make Flash-DBSim useful for all researchers in their researches and experiments.Original paper by S

2022-01-18 16:14:37 852

原创 30天自制C++服务器day14-支持业务逻辑自定义、完善Connection类

回顾之前的教程,可以看到服务器Echo业务的逻辑在Connection类中。如果我们需要不同的业务逻辑,如搭建一个HTTP服务器,或是一个FTP服务器,则需要改动Connection中的代码,这显然是不合理的。Connection类作为网络库的一部分,不应该和业务逻辑产生联系,业务逻辑应该由网络库用户自定义,写在server.cpp中。同时,作为一个通用网络库,客户端也可以使用网络库来编写相应的业务逻辑。今天我们需要完善Connection类,支持业务逻辑自定义。首先来看看我们希望如何自定义业务逻辑,这是

2022-01-09 16:00:13 2006

原创 30天自制C++服务器day13-C++工程化、代码分析、性能优化

在之前的教程里,我们已经完整开发了一个主从Reactor多线程的服务器的核心架构,接下来的开发重心应该从架构转移到细节。在这之前,将整个项目现代化、工程化是必要的,也是必须的。C++项目工程化的第一步,一定是使用CMake。目前将所有文件都放在一个文件夹,并且没有分类。随着项目越来越复杂、模块越来越多,开发者需要考虑这座屎山的可读性,如将模块拆分到不同文件夹,将头文件统一放在一起等。对于这样复杂的项目,如果手写复杂的Makefile来编译链接,那么将会相当负责繁琐。我们应当使用CMake来管理我们的项目,

2022-01-04 22:45:34 857

原创 30天自制C++服务器day12-将服务器改写为主从Reactor多线程模式

在上一天的教程,我们实现了一种最容易想到的多线程Reactor模式,即将每一个Channel的任务分配给一个线程执行。这种模式有很多缺点,逻辑上也有不合理的地方。比如当前版本线程池对象被EventLoop所持有,这显然是不合理的,线程池显然应该由服务器类来管理,不应该和事件驱动产生任何关系。如果强行将线程池放进Server类中,由于Channel类只有EventLoop对象成员,使用线程池则需要注册回调函数,十分麻烦。更多比较可以参考陈硕《Linux多线程服务器编程》第三章今天我们将采用主从Reac

2022-01-04 22:44:31 833

原创 30天自制C++服务器day11-完善线程池,加入一个简单的测试程序

在昨天的教程里,我们添加了一个最简单的线程池到服务器,一个完整的Reactor模式正式成型。这个线程池只是为了满足我们的需要构建出的最简单的线程池,存在很多问题。比如,由于任务队列的添加、取出都存在拷贝操作,线程池不会有太好的性能,只能用来学习,正确做法是使用右值移动、完美转发等阻止拷贝。另外线程池只能接受std::function<void()>类型的参数,所以函数参数需要事先使用std::bind(),并且无法得到返回值。为了解决以上提到的问题,线程池的构造函数和析构函数都不会有太大变化,

2022-01-04 22:43:55 264

原创 30天自制C++服务器day10-加入线程池到服务器

今天是本教程的第十天,在之前,我们已经编码完成了一个完整的单线程服务器,最核心的几个模块都已经抽象出来,Reactor事件驱动大体成型(除了线程池),各个类的生命周期也大体上合适了,读者应该完全理解之前的服务器代码后再开始今天的学习。观察当前的服务器架构,不难发现我们的Reactor模型少了最关键、最重要的一个模块:线程池。当发现socket fd有事件时,我们应该分发给一个工作线程,由这个工作线程处理fd上面的事件。而当前我们的代码是单线程模式,所有fd上的事件都由主线程(也就是EventLoop线程)

2022-01-04 22:43:10 673

原创 30天自制C++服务器day09-缓冲区-大作用

在上一天,我们分离了用于接受连接的Acceptor类,并把新建连接的逻辑放在了Server类中。在上一天我们还提到了Acceptor类最主要的三个特点:类存在于事件驱动EventLoop类中,也就是Reactor模式的main-Reactor类中的socket fd就是服务器监听的socket fd,每一个Acceptor对应一个socket fd这个类也通过一个独有的Channel负责分发到epoll,该Channel的事件处理函数handleEvent()会调用Acceptor中的接受连接函数来

2021-12-27 17:12:45 139

原创 30天自制C++服务器day08-一切皆是类,连TCP连接也不例外

在上一天,我们分离了用于接受连接的Acceptor类,并把新建连接的逻辑放在了Server类中。在上一天我们还提到了Acceptor类最主要的三个特点:类存在于事件驱动EventLoop类中,也就是Reactor模式的main-Reactor类中的socket fd就是服务器监听的socket fd,每一个Acceptor对应一个socket fd这个类也通过一个独有的Channel负责分发到epoll,该Channel的事件处理函数handleEvent()会调用Acceptor中的接受连接函数来

2021-12-27 01:24:35 1274

原创 30天自制C++服务器day07-为我们的服务器添加一个Acceptor

在上一天,我们分离了服务器类和事件驱动类,将服务器逐渐开发成Reactor模式。至此,所有服务器逻辑(目前只有接受新连接和echo客户端发来的数据)都写在Server类里。但很显然,Server作为一个服务器类,应该更抽象、更通用,我们应该对服务器进行进一步的模块化。仔细分析可发现,对于每一个事件,不管提供什么样的服务,首先需要做的事都是调用accept()函数接受这个TCP连接,然后将socket文件描述符添加到epoll。当这个IO口有事件发生的时候,再对此TCP连接提供相应的服务。在这里务必先理

2021-12-27 00:33:12 1459

原创 30天自制C++服务器day06-服务器与事件驱动核心类登场

在上一天,我们为每一个添加到epoll的文件描述符都添加了一个Channel,用户可以自由注册各种事件、很方便地根据不同事件类型设置不同回调函数(在当前的源代码中只支持了目前所需的可读事件,将在之后逐渐进行完善)。我们的服务器已经基本成型,但目前从新建socket、接受客户端连接到处理客户端事件,整个程序结构是顺序化、流程化的,我们甚至可以使用一个单一的流程图来表示整个程序。而流程化程序设计的缺点之一是不够抽象,当我们的服务器结构越来越庞大、功能越来越复杂、模块越来越多,这种顺序程序设计的思想显然是不能满足

2021-12-26 17:19:26 175

原创 30天自制C++服务器day05-epoll高级用法-Channel登场

day05-epoll高级用法-Channel登场在上一天,我们已经完整地开发了一个echo服务器,并且引入面向对象编程的思想,初步封装了Socket、InetAddress和Epoll,大大精简了主程序,隐藏了底层语言实现细节、增加了可读性。让我们来回顾一下我们是如何使用epoll:将一个文件描述符添加到epoll红黑树,当该文件描述符上有事件发生时,拿到它、处理事件,这样我们每次只能拿到一个文件描述符,也就是一个int类型的整型值。试想,如果一个服务器同时提供不同的服务,如HTTP、FTP等,那么就

2021-12-23 17:12:47 1170 1

原创 30天自制C++服务器day04-来看看我们的第一个类

day04-来看看我们的第一个类在上一天,我们开发了一个支持多个客户端连接的服务器,但到目前为止,虽然我们的程序以.cpp结尾,本质上我们写的仍然是C语言程序。虽然C++语言完全兼容C语言并且大部分程序中都是混用,但一个很好的习惯是把C和C++看作两种语言,写代码时需要清楚地知道自己在写C还是C++。另一点是我们的程序会变得越来越长、越来越庞大,虽然现在才不到100行代码,但把所有逻辑放在一个程序里显然是一种错误的做法,我们需要对程序进行模块化,每一个模块专门处理一个任务,这样可以增加程序的可读性,也可

2021-12-23 16:28:37 1137

原创 30天自制C++服务器day03-高并发还得用epoll

在上一天,我们写了一个简单的echo服务器,但只能同时处理一个客户端的连接。但在这个连接的生命周期中,绝大部分时间都是空闲的,活跃时间(发送数据和接收数据的时间)占比极少,这样独占一个服务器是严重的资源浪费。事实上所有的服务器都是高并发的,可以同时为成千上万个客户端提供服务,这一技术又被称为IO复用。IO复用和多线程有相似之处,但绝不是一个概念。IO复用是针对IO借口,而多线程是针对CPU。IO复用的基本思想是事件驱动,服务器同时保持多个客户端IO连接,当这个IO上有可读或可写事件发生时,表示这个I

2021-12-13 15:49:12 1182

原创 30天自制C++服务器day02-不要放过任何一个错误

day02-不要放过任何一个错误github:day02-不要放过任何一个错误在上一天,我们写了一个一个客户端发起socket连接和一个服务器接受socket连接。然而对于socket,bind,listen,accept,connect等函数,我们都设想程序完美地、没有任何异常地运行,而这显然是不可能的,不管写代码水平多高,就算你是林纳斯,也会在程序里写出bug。在《Effective C++》中条款08讲到,别让异常逃离析构函数。在这里我拓展一下,我们不应该放过每一个异常,否则在大型项目开发中一定

2021-12-01 11:36:16 990

空空如也

空空如也

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

TA关注的人

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