当前位置: 首页 > news >正文

P2 B+树索引

文章目录

    • Task1 B+树页
      • B+树页
      • B+树内部结点
      • B+树叶子结点
    • Task2 B+树操作
      • Task2 B+树插入和搜索的单一值
        • 插入单一值
        • 搜索单一值
      • Task2 B+树删除
    • Task3 叶子扫描的迭代器
    • Task4 并行索引

Task1 B+树页

B+树页

实际上是每个B+树页面的标题部分,包含叶子页面和内部页面共享的信息。

报头格式(大小以字节为单位,共12字节):
| PageType (4) | CurrentSize (4) | MaxSize (4) |// define page type enum
enum class IndexPageType { INVALID_INDEX_PAGE = 0, LEAF_PAGE, INTERNAL_PAGE };
// 成员变量,内部页和叶页共享的属性
IndexPageType page_type_ __attribute__((__unused__));
int size_ __attribute__((__unused__));      // 键值对的数量,内部页的第一个键为无效值
int max_size_ __attribute__((__unused__));  // 键值对的容量

B+树内部结点

在内部页面中存储n个索引键和n+1个子指针(page_id)。

指针PAGE_ID(i)指向一个子树,其中所有键K满足:K(i) <= K < K(i+1)。

注意:由于键的数量不等于子指针的数量,所以第一个键总是无效的。也就是说,任何搜索/查找都应该忽略第一个键。

内部页面格式(键按递增顺序存储):
| HEADER | KEY(1)+PAGE_ID(1) | KEY(2)+PAGE_ID(2) | ... | KEY(n)+PAGE_ID(n) |#define MappingType std::pair<KeyType, ValueType>
//key -> page_id 的映射
MappingType array_[0];

B+树叶子结点

只支持唯一键。

叶页格式(键按顺序存储):
| HEADER | KEY(1) + RID(1) | KEY(2) + RID(2) | ... | KEY(n) + RID(n)HEADER格式(大小为字节,共16字节):
| PageType (4) | CurrentSize (4) | MaxSize (4) |  NextPageId (4)page_id_t next_page_id_;  // 先定位到一个叶子,再顺序向后扫描
//key->record_id 的映射,record id = page id combined with slot id
MappingType array_[0];

Task2 B+树操作

大部分操作在b_plus_tree.cpp实现

Context类用于记录操作B+树过程中需要记忆的路径、读写保护等

class Context {public:// 当您插入/删除B+树时,将头页的写保护存储在这里。// 当您想要解锁所有内容时,请记住取消标题页保护并将其设置为空值,即header_page.reset()std::optional<WritePageGuard> header_page_{std::nullopt};//在这里保存根页面id,以便更容易地知道当前页面是否是根页面。page_id_t root_page_id_{INVALID_PAGE_ID};// 要修改的页面的写保护的队列。std::deque<WritePageGuard> write_set_;// 读保护队列std::deque<ReadPageGuard> read_set_;auto IsRootPage(page_id_t page_id) -> bool { return page_id == root_page_id_; }
};

Task2 B+树插入和搜索的单一值

插入单一值

BPLUSTREE_TYPE::Insert()实现,若BPLUSTREE_TYPE::header_page_id_属性标识的根节点的页(BPlusTreeHeaderPage)的根节点页id无效,说明没有根页面,调用缓冲区的NewPage()新建root页,然后强转为BPlusTreeLeafPage类型,此时根节点就是叶子节点,然后BPlusTreeLeafPage::InsertAtLast()根叶后插k-v,标识正在使用该页,清空header_page_(检查header_page_id_标识的根节点页时,页就存在这里)。若有根节点就获取根节点页id,调用InsertIntoLeaf()

BPLUSTREE_TYPE::InsertIntoLeaf()开头就调用了BPLUSTREE_TYPE::FindLeaf(),此函数的作用是为插入/删除结点操作寻找目标叶,结果存在B+树类的Context类成员的write_set_中。回到函数,取出查找到的页,强转为BPlusTreeLeafPage后直接调用BPlusTreeLeafPage::Insert()插入k-v,若插入失败说明是重复键值对,清空header_page_write_set_后退出,并且若叶页大小没超过叶子最大容量则此插入是安全插入,清空header_page_write_set_后退出,剩下的情况就是叶页满了,需要分裂,调用Split()进行分裂,返回的新页引用是满页分裂出的兄弟叶页,之后调用InsertIntoParent()修改父结点结构。

BPLUSTREE_TYPE::InsertIntoParent()是个直接递归,在函数开头有个判断write_set_内的锁有一个时,这些锁是在InsertIntoLeaf()中调用FindLeaf()时产生的,表示修改该叶子会导致write_set_中的这些结点页被修改,即最接近叶子的安全结点到叶子节点这一路径上的所有结点的锁。在write_set_中只剩一个页时,NewPage()新建一个页,当作新根节点,然后旧根节点和分裂出的新结点做新根的子节点,返回。通过write_set_获取父结点,然后调用BPlusTreeInternalPage::InsertAfterValue()将分裂后产生的新节点插入父节点,write_set_弹出旧结点(原来不安全的结点)。当父节点的大小超过了最大容量,则父节点不安全,调用Split()分裂并调用InsertIntoParent()递归,若是安全结点,则清理header_page_write_set_,结束。

BPLUSTREE_TYPE::Split()分裂结点,返回新的兄弟页。NewPage()创建新页,叶子节点分裂就将新页和待分裂的页强转为叶页,初始化新叶页后旧叶页调用BPlusTreeLeafPage::SplitLeafTo(),取出旧叶页的后一半数据给新叶页,并且设置旧叶页和新叶页的next_page_id。最后设置正在使用新叶页,然后返回。若分裂内部节点,将新页和待分裂的页强转为内部结点页,新结点页初始化后旧结点页调用BPlusTreeInternalPage::SplitInternalTo()取内部节点的最大容量加一的一半(后半段)的内容给新内部节点,限定结点大小。设置新结点页正在使用后返回。

这里我不理解的是在InsertIntoParent()中仅仅用if (ctx.write_set_.size() == 1)就确定是根节点分裂

搜索单一值

BPLUSTREE_TYPE::GetValue()实现,获取头部页的写锁header_page_,通过它获得根节点id,将根节点读锁加入read_set_然后强转为BPlusTreePage,清空header_page_,强转结点为BPlusTreeInternalPage,调用BPlusTreeInternalPage::FindInternelKey()按key二分查找中间节点的子节点引用,查到的页加读锁,加入read_set_然后将原先在read_set_中的父页弹出,这样就实现了读锁的"下沉",之后进入循环直到页是叶页。循环出来后将页强转为BPlusTreeLeafPage类,之后调用BPlusTreeLeafPage::FindKey()二分查找叶子节点的值,找到后组装传参vector。

Task2 B+树删除

BPLUSTREE_TYPE::Remove()实现,获取头部页写锁并得到根节点id,调用FindLeaf()查找key,获取查到的页强转成BPlusTreeLeafPage,调用BPlusTreeLeafPage::DeleteKey()先二分查找叶子结点key,若没有调用DeleteKeyAt()删除数组中对应的k-v,删除失败就清理header_page_write_set_并退出,若删除的k-v所在的叶页大小大于等于最小容量(叶子结点是max_size_/2,内部节点是(max_size_+1)/2)时,即为安全删除,清空write_set_并退出,若根节点时叶子,叶子根节点有一个键值对就能退出。最后都没有退出的就是需要非安全删除情况,可能会有修改父节点key、小于最小尺寸需从兄弟节点处拿甚至兄弟节点也不足直接合并,调用DealNode()合并或删除叶页。

BPLUSTREE_TYPE::DealNode()是个间接递归,它调用Merge()Merge()调用它。处理借取键值对或合并节点,write_set_的最后一个值是这个函数体需要处理的不安全的节点(已进行删除工作)。

  • 若是根节点

    • 根叶:清理write_set_header_page_
    • 不是叶:强转为内部节点,取第0个的引用做根节点id(header_page_强转为BPlusTreeHeaderPage可取root_page_id_

    返回

  • 不是根

    write_set_取出该页的父页,强转为内部节点

    • 是叶
      强转为叶页,父页调用FindInternelKey()二分查找叶子key获得index

      左边有值,有左兄弟(index > 0):取左兄弟(父页的index-1)的写锁存入write_set_,强转为叶页后保存变量

      右边有值,有右兄弟(index < 父页容量-1):取右兄弟(父页的index+1)的写锁存入write_set_,强转为叶页后保存变量

      • 左右兄弟都在(左叶页变量 && 右叶页变量):
        • 两个兄弟都不足(兄弟大小 <= 最小容量):调用Merge()与右节点合并,返回
        • 右边有剩余(右兄弟大小 > 最小容量):清空header_page_,向兄弟节点借键值对表示父页是安全节点,释放write_set_中父页的祖先节点及根的锁,叶页调用LendFromBrother()向右兄弟借,之后父页调用SetKeyAt()更新父页中的右兄弟结点在父页的索引,然后清理write_set_
        • 左边有剩余(else):清空header_page_,释放write_set_中父页的祖先节点及根的锁,叶页调用LendFromBrother()向左兄弟借,父页调用SetKeyAt()更新父页中的右兄弟结点在父页的索引,然后清理write_set_
      • 只有左兄弟(左叶页变量):
        • 左兄弟不足(左兄弟大小 <= 最小容量):调用Merge()与左兄弟合并,返回
        • 左边有剩余:清空header_set_,释放write_set_中父页祖先节点及根的锁,叶页调用LendFromBrother()向左兄弟借,父页调用SetKeyAt()更新父页中的左兄弟结点在父页的索引,然后清理write_set_
      • 只有右兄弟(右叶页变量):
        • 右兄弟不足(右兄弟大小 <= 最小容量):调用Merge()与右兄弟合并,返回
        • 右边有剩余:清空header_set_,释放write_set_中父页祖先节点及根的锁,叶页调用LendFromBrother()向右兄弟借,父页调用SetKeyAt()更新父页中的右兄弟结点在父页的索引,然后清理write_set_
    • 是内部结点

      强转为内部结点页,父页调用FindInternelKey()二分查找内部结点获得index

      左边有值,有左兄弟(index > 0):取左兄弟(父页的index-1)的写锁存入write_set_,强转为内部结点页后保存变量

      右边有值,有右兄弟(index < 父页容量-1):取右兄弟(父页的index+1)的写锁存入write_set_,强转为内部结点后保存变量

      • 左右兄弟都在(左结点页变量 && 右结点页变量):
        • 两个兄弟都不足(兄弟大小 <= 最小容量):调用Merge()与右节点合并,返回
        • 右边有剩余(右兄弟大小 > 最小容量):清空header_page_,释放write_set_中父页的祖先节点及根的锁,内部结点页调用LendFromBrother()向右兄弟借,之后父页调用SetKeyAt()更新父页中的右兄弟结点在父页的索引,然后清理write_set_
        • 左边有剩余(else):清空header_page_,释放write_set_中父页的祖先节点及根的锁,叶页调用LendFromBrother()向左兄弟借,父页调用SetKeyAt()更新父页中的右兄弟结点在父页的索引,然后清理write_set_
      • 只有左兄弟(左结点页变量):
        • 左兄弟不足(左兄弟大小 <= 最小容量):调用Merge()与左兄弟合并,返回
        • 左边有剩余:清空header_set_,释放write_set_中父页祖先节点及根的锁,叶页调用LendFromBrother()向左兄弟借,父页调用SetKeyAt()更新父页中的左兄弟结点在父页的索引,然后清理write_set_
      • 只有右兄弟(右结点页变量):
        • 右兄弟不足(右兄弟大小 <= 最小容量):调用Merge()与右兄弟合并,返回
        • 右边有剩余:清空header_set_,释放write_set_中父页祖先节点及根的锁,叶页调用LendFromBrother()向右兄弟借,父页调用SetKeyAt()更新父页中的右兄弟结点在父页的索引,然后清理write_set_

BPLUSTREE_TYPE::Merge()总是把右边节点的键值对转移给左边,再删除右边节点,这样方便更新NextPageId,若传入的经删除操作的页是叶子节点,将该页和兄弟页强转为叶页后,判断是右兄弟,兄弟结点就调用BPlusTreeLeafPage::MoveAllTo()将自己的k-v顺序插入该页的末尾,将该页的NextPageId设置为右兄弟的,设置删除结点索引为右兄弟索引(该页索引+1)。若判断是左兄弟,该页调用BPlusTreeLeafPage::MoveAllTo()将自己的k-v顺序插入左兄弟的尾部,左兄弟的NextPageId设置为该页的,设置删除节点索引为该页索引。若进行删除操作的页是内部结点,强转该页和兄弟页为内部节点页,判断是右兄弟就把兄弟k-v插入该页末尾,设置删除索引为兄弟,反之同理。之后将write_set_中该页父页的孩子出栈解锁,只剩父页和其祖先节点,把父页强转为内部节点页,调用DeleteKeyAt()将删除结点索引指定的结点页删除。若父页大小大于等于最小容量(安全删除),清理write_set_后就可返回,若是根结点,内部根节点右两个键值对(容量大于1)就行,返回,其他情况就是不安全删除,调用DealNode()进行间接递归。

BPlusTreeLeafPage::LendFromBrother()从brother移动一个键值对过来,兄弟调用KeyAt()ValueAt(),针对传入是否是左兄弟,将k-v插入结点的头或尾并设置兄弟的大小或删除k-v,最后返回新key。

Task3 叶子扫描的迭代器

必须添加一个c++迭代器,以有效地支持对叶页中的数据进行有序扫描。基本思想是存储兄弟指针,这样就可以有效地遍历叶页,然后实现一个迭代器,按顺序遍历每个叶页中的每个键值对。

Begin()End()函数在b_plus_true.cpp中,而迭代器类在index_iterator.cpp中实现

//索引迭代器类的私有属性
BPlusTreeLeafPage<KeyType, ValueType, KeyComparator> *leaf_page_{nullptr};  // 此迭代器指向的叶子
int index_{-1};  // 表示此迭代器现在指向leaf_page_中某叶页的第几个键值对
page_id_t my_page_id_;//表示迭代器指向的leaf_page_中某叶页的页id
BufferPoolManager *bpm_{nullptr};

重载了* ++ == !=四个符号来对索引迭代器进行操作

BPLUSTREE_TYPE::Begin()有重载,分别对应处理没给key和给了key的情况。没给就直接调用FindLeafPage()传入空key并指定找最左边的k-v,这样就返回了叶页链表首页,然后强转为叶页,构造索引迭代器后返回。传入key的Begin()多加了一层检测传回的页是否真的有key,没有说明FindLeafPage()没有找到,返回空索引迭代器。

BPLUSTREE_TYPE::End()同无参Begin()只不过指定找的是最右边的k-v(即index=internal_page->GetSize()-1

BPLUSTREE_TYPE::FindLeafPage()无锁获取根节点,根据传入的indextype判断需要的是最左/右的页还是进行k-v查找。

Task4 并行索引

见Task 2

相关文章:

P2 B+树索引

文章目录 Task1 B树页B树页B树内部结点B树叶子结点 Task2 B树操作Task2 B树插入和搜索的单一值插入单一值搜索单一值 Task2 B树删除 Task3 叶子扫描的迭代器Task4 并行索引 Task1 B树页 B树页 实际上是每个B树页面的标题部分&#xff0c;包含叶子页面和内部页面共享的信息。 …...

爬虫知识之BeautifulSoup库安装及简单介绍

一. 前言 在前面的几篇文章中我介绍了如何通过Python分析源代码来爬取博客、维基百科InfoBox和图片,其文章链接如下: 其中核心代码如下: # coding=utf-8 import urllib import re #下载静态HTML网页 url=http://www.csdn.net/ content = urllib.urlopen(url).read…...

如何有效取代FTP来帮助企业快速传输大文件

在互联网的发展历史上&#xff0c;FTP是一种具有里程碑意义的协议&#xff0c;它最早出现在1971年&#xff0c;是实现网络上文件传输的基础。FTP的优点是简单、稳定、兼容性强&#xff0c;可以在不同的操作系统和平台之间进行文件交换。然而&#xff0c;时代在进步&#xff0c;…...

免登陆积分商城原理

有客户需要免登陆积分商城&#xff0c;研究了一下发现免登陆用途广泛&#xff0c;实现原理也很简单。如果是浏览器无非就是使用fingerprintjs2之类的扩展来实现获取浏览器指纹ID&#xff0c;如果是APP就获取设备唯一标识&#xff0c;然后在使用cryptojs加密来传递到php&#xf…...

muduo源码学习base——Atomic(原子操作与原子整数)

Atomic(原子操作与原子整数&#xff09; 前置知识AtomicIntegerTget()getAndAdd()getAndSet() 关于原子操作实现无锁队列(lock-free-queue) 前置知识 happens-before&#xff1a; 用来描述两个操作的内存可见性 如果操作 X happens-before 操作 Y&#xff0c;那么 X 的结果对于…...

最短路相关笔记

Floyd Floyd 算法&#xff0c;是一种在图中求任意两点间最短路径的算法。 Floyd 算法适用于求解无负边权回路的图。 时间复杂度为 O ( n 3 ) O(n^3) O(n3)&#xff0c;空间复杂度 O ( n 2 ) O(n^2) O(n2)。 对于两点 ( i , j ) (i,j) (i,j) 之间的最短路径&#xff0c;有…...

Web前端-Vue2+Vue3基础入门到实战项目-Day5(自定义指令, 插槽, 案例商品列表, 路由入门)

自定义指令 基本使用 自定义指令: 自己定义的指令, 可以封装一些dom操作, 扩展额外功能全局注册// 1. 全局注册指令 Vue.directive(focus, {// inserted 会在 指令所在的元素, 被插入到页面中时触发inserted (el) {// el 就是指令所绑定的元素// console.log(el)el.focus()} …...

mysql json数据类型 相关函数

创建JSON文本的函数 1.JSON_ARRAY&#xff08;转换json数组&#xff09; 2.JSON_OBJECT&#xff08;转换json对象&#xff09; 3.JSON_QUOTE&#xff08;转义字符串&#xff09; 搜索JSON文本的函数 1.JSON_CONTAINS&#xff08;json当中是否包含指定value&#xff09; 2.J…...

如何实现前端实时通信(WebSocket、Socket.io等)?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…...

使用 SSSD 进行网络用户身份验证

文章目录 使用 SSSD 进行网络用户身份验证SSSD和Active Directory先决条件、假设和要求软件安装加域 SSSD配置自动创建HOME目录 检查和验证 Kerberos票证已知的问题参考 使用 SSSD 进行网络用户身份验证 SSSD 代表系统安全服务守护程序&#xff0c;它实际上是处理来自各种网络…...

紫光展锐携中国联通完成RedCap芯片V517孵化测试

近日&#xff0c;紫光展锐携手中国联通5G物联网OPENLAB开放实验室&#xff08;简称“OPENLAB实验室”&#xff09;共同完成RedCap芯片V517创新孵化&#xff0c;并实现在联通5G全频段3.5GHz、2.1GHz、900MHz下的端到端业务验证测试。 V517是一款基于紫光展锐5G成熟平台设计与研发…...

算法通关村第十一关青铜挑战——移位运算详解

大家好&#xff0c;我是怒码少年小码。 计算机到底是怎么处理数字的&#xff1f; 数字在计算机中的表示 机器数 一个数在计算机中的二进制表示形式&#xff0c;叫做这个数的机器数。 机器数是带符号的&#xff0c;在计算机用一个数的最高位存放符号&#xff0c;正数为0&am…...

2023年面试测试工程师一般问什么问题?

面试和项目一起&#xff0c;是自学路上的两大拦路虎。面试测试工程师一般会被问什么问题&#xff0c;总结下来一般是下面这4类&#xff1a; 1.做好自我介绍 2.项目相关问题 3.技术相关问题 4.人事相关问题 接下来&#xff0c;主要从以上四个方向分别展开介绍。为了让大家更有获…...

2023年中国汽车覆盖件模具竞争格局、市场规模及行业需求前景[图]

汽车覆盖件模具是汽车车身生产的重要工艺装备&#xff0c;其设计和制造时间约占汽车开发周期的 2/3&#xff0c;是汽车换型的重要制约因素之一。汽车覆盖件模具具有尺寸大、工作型面复杂、技术标准高等特点&#xff0c;属于技术密集型产品。汽车覆盖件模具按以其冲压的汽车覆盖…...

vue3项目运行报错import zhCn from “element-plus/lib/locale/lang/zh-cn“

解决办法 import zhCn from "element-plus/lib/locale/lang/zh-cn";修改为 import zhCn from "element-plus/dist/locale/zh-cn.mjs";...

读书笔记:Effective C++ 2.0 版,条款26(歧义)、条款27(禁止部分隐式生成的函数)

条款26: 当心潜在的歧义 即使cpp支持潜在二义性/歧义&#xff0c;也不要使用。 void f(int); void f(char); double d 6.02; f(d); //需要明确转换多继承充满了潜在二义性/歧义的可能。 class Base1 {public: int doIt();}; class Base2 {public: void doIt();}; class Deri…...

MySQL基本操作之数据库设计理论

1、数据的设计准则 1)糟糕的数据库设计表现在以下几个方面: 访问数据效率低下存在大量的数据冗余,浪费存储空间更新和检索数据时会出现许多问题2)良好的数据库设计表现在以下几方面: 访问效率高减少数据冗余,节省存储空间便于进一步扩展可以使应用程序的开发变得更容易…...

SpringBoot的日志系统(日志分组、文件输出、滚动归档)

[toc](目录) > SpringBoot3需要jdk17 # 1. 简介 1. Spring5及以后Spring自己实现了commons-logging&#xff0c;来作为内部的日志。日志的jar包是org.springframework:spring-jcl:6.0.10。查看org.apache.commons.logging.LogAdapter Java package org.apache.commons.log…...

一种基于HTTPS实现的Web账号登录Linux桌面系统的实现方案

问题由来 客户需求计划列入支持第三方帐号系统&#xff0c;包括Web账号。需求来源是用户想要用它们的帐号直接登录Linux Deepin操作系统。一个失败的实现方案是用户以较小的成本改造帐号管理系统发布HTTP服务&#xff0c;我们开发一个PAM模块与Web服务器交互&#xff0c;数据格…...

【Linux】psplash制作Linux开机动画

1. 下载psplash软件 下载psplash源码到ubuntu中&#xff1a; 下载地址&#xff1a;https://git.yoctoproject.org/psplash/commit/安装依赖环境 sudo apt-get install libgdk-pixbuf2.0-dev2. 准备图片 开机动画静态图片&#xff1a;psplash-poky.png开机动画进度条图片&…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

Go 并发编程基础:通道(Channel)的使用

在 Go 中&#xff0c;Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式&#xff0c;用于在多个 Goroutine 之间传递数据&#xff0c;从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

WebRTC调研

WebRTC是什么&#xff0c;为什么&#xff0c;如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...

从零开始了解数据采集(二十八)——制造业数字孪生

近年来&#xff0c;我国的工业领域正经历一场前所未有的数字化变革&#xff0c;从“双碳目标”到工业互联网平台的推广&#xff0c;国家政策和市场需求共同推动了制造业的升级。在这场变革中&#xff0c;数字孪生技术成为备受关注的关键工具&#xff0c;它不仅让企业“看见”设…...

CppCon 2015 学习:REFLECTION TECHNIQUES IN C++

关于 Reflection&#xff08;反射&#xff09; 这个概念&#xff0c;总结一下&#xff1a; Reflection&#xff08;反射&#xff09;是什么&#xff1f; 反射是对类型的自我检查能力&#xff08;Introspection&#xff09; 可以查看类的成员变量、成员函数等信息。反射允许枚…...

Linux操作系统共享Windows操作系统的文件

目录 一、共享文件 二、挂载 一、共享文件 点击虚拟机选项-设置 点击选项&#xff0c;设置文件夹共享为总是启用&#xff0c;点击添加&#xff0c;可添加需要共享的文件夹 查询是否共享成功 ls /mnt/hgfs 如果显示Download&#xff08;这是我共享的文件夹&#xff09;&…...

Redis上篇--知识点总结

Redis上篇–解析 本文大部分知识整理自网上&#xff0c;在正文结束后都会附上参考地址。如果想要深入或者详细学习可以通过文末链接跳转学习。 1. 基本介绍 Redis 是一个开源的、高性能的 内存键值数据库&#xff0c;Redis 的键值对中的 key 就是字符串对象&#xff0c;而 val…...

基于 HTTP 的单向流式通信协议SSE详解

SSE&#xff08;Server-Sent Events&#xff09;详解 &#x1f9e0; 什么是 SSE&#xff1f; SSE&#xff08;Server-Sent Events&#xff09; 是 HTML5 标准中定义的一种通信机制&#xff0c;它允许服务器主动将事件推送给客户端&#xff08;浏览器&#xff09;。与传统的 H…...

代理服务器-LVS的3种模式与调度算法

作者介绍&#xff1a;简历上没有一个精通的运维工程师。请点击上方的蓝色《运维小路》关注我&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 我们上一章介绍了Web服务器&#xff0c;其中以Nginx为主&#xff0c;本章我们来讲解几个代理软件&#xff1a…...

视觉slam--框架

视觉里程计的框架 传感器 VO--front end VO的缺点 后端--back end 后端对什么数据进行优化 利用什么数据进行优化的 后端是怎么进行优化的 回环检测 建图 建图是指构建地图的过程。 构建的地图是点云地图还是什么信息的地图&#xff1f; 建图并没有一个固定的形式和算法…...