Paging

​ 此篇是在我在OSTEP中看到内存虚拟化分页这一章时所遇到的。需要注意的是,此篇写时我还有点感冒后遗症,脑袋不大清晰,有些地方逻辑会存在混乱,谅解吧。

Read more »

系统调用的本质解析

1. 为什么系统调用看起来像过程调用?

在《OSTEP》一书中,提到了一个有趣的问题:为什么系统调用在高级语言层面上看起来像普通的过程调用?

要理解这个问题,需要认识到计算机程序的本质:无论是操作系统(OS)还是用户程序,它们在运行时都是对数据的处理,而数据的处理依赖于 CPU 执行的底层指令。因此,我们可以从 数据指令 这两个维度来分析系统调用的特殊性。


Read more »

Storage

Tuple-Oriented Storage

​ 在前面,我们初步了解了一种数据在底层的组织形式,在这里我们考虑一个问题,即使我们知道了一个数据的存在,我们需要怎么去找到这个数据呢?

Read more »

储存管理

前情回顾

​ 接下来,我将跟着15445的进度跳过中间的中级SQL和高级SQL和其他一些对于数据库的优化操作,直接跳到书籍的第三章节中来。正如15445在课程中所说的,这门课程主要是为了让我们了解一个数据库系统到底是什么,而不是了解数据库系统怎么来进行使用。

Read more »

数据修改

​ 在此前的几个文档中,我们都专注于对于数据库数据的抽取,接下来可以进入对于数据库数据的增删改了。这也基本是modernSQL的尾声了。

Read more »

函数对象

​ 函数对象其实本身并不神秘,简单来说,一个函数对象就是能够被以函数调用形式来进行调用的任意对象。可以想到,函数对象就应该包括函数名,函数指针以及重载了()运算符的类对象。

Read more »

窗口函数

​ 接下来看一些DBMS中存在的一些窗口函数。

![image-20250225092345760](./1.3-Modern SQL(function)/image-20250225092345760.png)

​ 上面那句话其实就是说一个窗口函数是对于输出序列中的一个特定窗口范围内的数据进行操作的函数。这个函数于聚合函数相似,都是对于一系列的元组执行操作的函数,但是这个函数于聚合函数最大的不同就是窗口函数并不会对输出结果进行合并,而是每个输入元组都能获得一个窗口函数的一个输出属性。

​ 没意思,润

Read more »

字符串

​ 在SQL中,自然也存在字符串这种元素。一般来说,SQL使用单引号**’ ‘**来标识这是一个字符串,同时在SQL标准中,数据库对于字符串大小写应该是一个敏感的状态。但是,很多数据库系统中,包括但不限于MySQL和SQL Server中,对于这些个标准都是存在一些选择的。例如在MySQL中,其对于字符串的大小写就是不敏感的,当然,你可以在MySQL中去使用对于的标准设置语句去进行调整。不过种种这些,都是一些小玩意,在使用具体的数据库时去进行适当的调整即可,没必要去进行一个个的深入了解。

Read more »

嵌套查询

​ 有一说一,modernSQL的内容是真的多,甚至于我都不想继续了,不过这些其实都还无所谓,毕竟现在也还只是停留在理论阶段,还没有开始真正的上手。

​ 在之前我们接触到的都是一些单个查询语句的情况,但是有时候这种单层的结构不能满足我们的需求。自然而然,多层也就是嵌套查询也就出现了。这种查询方式其实很好理解。就是将一个查询语句的输出作为另外一个查询语句的一个子句的输入。在格式上表现出来的其实就是一个查询中包含着另外的查询。通常情况下,这种架构下的查询语句很难优化。而且一般来说,这种嵌套查询,可以出现在任何一个子句中,只要你这样做存在着抽象价值。

Read more »

前情提醒,在本次学习中,我使用的代码将会是llfc大佬的代码,因为实在是懒的敲,这段博客可以视为是我个人的一个笔记。具体的可以去看llfc大佬的个人博客喵

终端节点

​ 在网络编程中,联系端对端的基础单位是一个套接字,对于asio来说,其实现了一层自己的框架,或者说规则。其对于使用其来开发的网络编程中进行了一系列的封装。在这其中,终端该概念,就是基于套接字进行的封装。但是需要注意的是,终端节点本身并不是一个套接字,只有对其进行进一步的包装,其才能成为一个合格的套接字。

​ 我们来看到对应的创建终端节点的代码。正如在之前的tinyweb去创建一个套接字的前置工作一样,我们这里也需要对于终端节点的构造进行一些前置准备。简单来说,为了生成一个终端节点,我们需要先去包装一个ip地址以及对应的窗口。类比对应的getaddrinfo系统调用即使前俩个参数的信息。那么对于ip地址的构建,其又存在着什么规则呢,请看看下面源码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int client_end_point()
{
std::string raw_ip_address = "127.4.8.1";
unsigned short port_num=3333;
boost::system::error_code ec;
asio::ip::address ip_address = asio::ip::make_address(raw_ip_address,ec);
if(ec.value()!=0)
{
std::cout<<"Failed to parse the IP adderss,Error code = "<<ec.value()<<".Message is "<<ec.message();
return ec.value();
}

asio::ip::tcp::endpoint ep(ip_address,port_num);
}

​ 这里以客户端的终端节点创建为例,在创建节点前,我们需要优先知道所需要连接的服务器端的ip地址。有了这个ip地址,再配合我们自己声明的一个用于储存错误代码的boost::system::error_code成员,我们可以进行make_address函数的调用。该函数位于asio::ip域下,使用一个ip地址和一个错误储存码来构建一个在asio中合格意义的ip地址。

​ 前面的传入ip地址只是一个字符串,直接使用其来进行通信具有太多的风险,使用类来对其进行包装能使得程序更加健壮。

​ 对于第二个参数,顾名思义,其是一个错误储存码,储存着在该次创建过程中的状态信息,当且仅当在函数正常返回时返回0.对于这种简单的错误处理,之后将不再进行赘述。

​ 在创建完一个封装完毕的ip地址之后,我们可以使用其来构建我们的ip地址。在asio中,相对于之前直接使用c系统调用来进行创建的最大不同点是,我们在这里不必再对其进行一些属性信息在传递参数上的设置。更简单的。C++实现的asio通过类作用域来进行一个区分,这样既显式的指出了我们在创建一个终端节点时的繁琐,而且大大提高了使用的连接的可读性。

1
asio::ip::tcp::endpoint ep(ip_address,port_num);

​ 在该类对象创建中,通过传入一个ip地址和对应的端口号,我们可以对其进行一个绑定,由于这是一个客户端,所以这里指定的其实就是对应的服务器端的服务提供位置。除此之外,还可以看到,在该类成员构造之前,我们使用了一系列的类作用域限定符。通过ip::tcp::endpoint这种层次上的逻辑,我们不难推断出在该终端节点中我们使用的协议以及该成员变量的用处。

​ 接下来来看到对应与客户端节点的服务器端节点的创建,正如一般的网络编程的服务器端设置比客户端设置简单一样。对应的服务器端由于使用的端口地址被固定为了本地地址,所以这里的终端节点的创建也更加简单。但是,这是基于简单的实现的。在asio或者更加现代的网络库中,对于机器监听的设置更加灵活。对于一个进程所请求的监听设置,其可能不再局限于一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int  server_end_point(){
// Step 1. Here we assume that the server application has
//already obtained the protocol port number.
unsigned short port_num = 3333;

// Step 2. Create special object of asio::ip::address class
// that specifies all IP-addresses available on the host. Note
// that here we assume that server works over IPv6 protocol.
asio::ip::address ip_address = asio::ip::address_v6::any();

// Step 3.
asio::ip::tcp::endpoint ep(ip_address, port_num);

// Step 4. The endpoint is created and can be used to
// specify the IP addresses and a port number on which
// the server application wants to listen for incoming
// connections.
return 0;
}

​ 在这里,我们需要对于一个计算机上的ip地址再进行一下分析。在很多情况下,我们其实都认为一个计算机存在一个自己唯一的ip地址。事实上也确实如此,但是!这是相对于整个互联网网络来说的。对于一个计算机本身,其还存在着一系列的用于本身的测试等作用的地址,就比如我们很熟悉的本地回环地址localhost。这个回环地址与计算机在公网上的地址是不一样的。

​ 回到我们这里的服务器端的地址的构建,这里其实本质上是将所有的本地使用的地址都绑定到了对应的类结构上了。这个可以去查看对应的asio::ip::address源码去了解。对应的,一但使用any进行对应的服务器ip地址的构建,其将能够接受来自本机上所有不同属性的请求。就比如,来自本地的IPV6协议网络请求,来自局域网和公网的网络请求等。但是,这并不意味着使用any绑定后该进程能够拦截所有来自外部的请求。对应的请求还是只能传输给对应的端口。这里也就是不必关心出现问题的原因。

​ 在创建出对应的IP地址之后,接下来的终端节点创建工作与客户端无异,这里就直接跳过了。