谈谈BlueStore的BitmapAllocator

news2024/9/19 11:12:03

背景

BlueStore在ceph里面承担了数据在底层磁盘上的读写任务,那它的功能里自然就有一块是管理磁盘空间使用的。说白了,就是记录&管理磁盘里哪些空间已经使用了,哪些空间还没有被使用。
目前官方的ceph里使用BitmapAllocator来管理磁盘空间使用。
简单的说就是用一个二进制bit来表面一个磁盘区间是否被使用了。
咱们先说几个关键术语:

bdev_block_size:磁盘块大小,IO的最小单元,默认4K。
min_alloc_size:最小分配单元,SSD默认16K,HDD默认64K。
max_alloc_size:最大分配单元,默认0不限制,即一次连续的分配结果只包含一个extent。
alloc_unit:分配单元(AU),一般设置为min_alloc_size。

一次allocate的单元就是alloc_unit,咱们就按64KB计算。这个二进制就只需要1个Bit。1个字节的bit位就可以表示512KB。那这么来说一个1TB的磁盘就需要2MB的内存空间。每次allocate平均就需要遍历整个2MB内存的一半(一共2MB,平均一次就取一半计算)。效率略低。
后面就有了改良版的BitmapAllocator。
初始版的BitmapAllocator是使用一个字节序列来标识整个磁盘空间。改良版是使用3个字节序列来标识磁盘空间。
如下:
在这里插入图片描述
分别有3个字节序列,分别是L0,L1,L2,其中L0最接近磁盘。
记住下面这些概念

每一层自己都有slot,每个slot的大小都是64Bit,每个slot里面有children。
L2和L0层1个slot管理自己slot里面的64个children,L1层1个slot管理32个children L2 L0
一个children是1个bit;L1层一个children是2个bit 每个children管理下层8个slot
一个L0的children就是1个AU(Alloc_Unit),默认64KB(HDD)
一个L1的children,管理L0里8个slot,L0里1个slot管理64个children,也就是说L1的一个children对应L0
864个children
一个L2的children,管理L1里8个slot,L1层1个slot管理32个children,也就是说L2的一个children对应L1
8
32个children

1个L0的childre 对应 64KB 1个L1的solt对应4MB
1个L1的children 对应 86464KB=32MB 1个L1的solt对应1G
1个L2的children 对应 83232MB = 8G 1个L2的solt 对应 512GB
如果4TB的磁盘,在L2层就需要8个slot

生命周期&使用sample

// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * In memory space allocator test cases.
 * Author: Ramesh Chander, Ramesh.Chander@sandisk.com
 */
#include <iostream>
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>

#include "common/Cond.h"
#include "common/errno.h"
#include "include/stringify.h"
#include "include/Context.h"
#include "os/bluestore/Allocator.h"

using namespace std;

typedef boost::mt11213b gen_type;

class AllocTest : public ::testing::TestWithParam<const char*> {

public:
  boost::scoped_ptr<Allocator> alloc;
  AllocTest(): alloc(0) { }
  void init_alloc(int64_t size, uint64_t min_alloc_size) {
    std::cout << "Creating alloc type " << string(GetParam()) << " \n";
    alloc.reset(Allocator::create(g_ceph_context, GetParam(), size,
				  min_alloc_size));
  }

  void init_close() {
    alloc.reset(0);
  }
};

TEST_P(AllocTest, mytest)
{

    uint64_t block = 64*1024;
    //4TB
    uint64_t size = 4L*1024*1024*1024*1024L;

    init_alloc(size, block);

    alloc->init_add_free(0, size);

    PExtentVector extents;

    alloc->allocate(512L*1024*1024*1024, block, 0, (int64_t)0, &extents);
    std::cout<<"-------"<<std::endl;
    alloc->allocate( block*3, block, 0, (int64_t)0, &extents);

    std::cout<<"xxxxxxxxxxxx"<<std::endl;
    alloc->allocate( block*4, block, 0, (int64_t)0, &extents);
}


INSTANTIATE_TEST_SUITE_P(
  Allocator,
  AllocTest,
  ::testing::Values("stupid", "bitmap", "avl", "hybrid", "btree"));

以上代码参考在src/test/objectstore/Allocator_test.cc

相关类图

AllocatorLevel是基础类,磁盘分配器需要实现这个类

class AllocatorLevel01Loose : public AllocatorLevel01
class AllocatorLevel01 : public AllocatorLevel
class AllocatorLevel02 : public AllocatorLevel

class BitmapAllocator : public Allocator,
  public AllocatorLevel02<AllocatorLevel01Loose> 

分配原理

在构造函数里

BitmapAllocator::BitmapAllocator(CephContext* _cct,
					 int64_t capacity,
					 int64_t alloc_unit,
					 std::string_view name) :
    Allocator(name, capacity, alloc_unit),
    cct(_cct)
{
  _init(capacity, alloc_unit, false);
}

static const slot_t all_slot_set = 0xffffffffffffffff;
static const slot_t all_slot_clear = 0;

在_init里面会把L2,L1,L0的每个solt(8个字节,64个bit,刚好是一个long long 无符号整数)都置成0。
之后
init_add_free 的时候
又把L2,L1,L0层的每个槽位都置成为0xffffffffffffffff

每次分配空间的时候,就先从L2找,
如果L2的槽位是0,就说明这个槽位已经完全都分配了,查找下一个槽位
如果L2的槽位是上0xffffffffffffffff,就说明整个槽位都还没有分配过任何空间,完全是空闲的,把free_pos设为0,然后去L1查找
如果L2的槽位既不是0也不是0xffffffffffffffff,说明这个槽位分配过数据,但是又没有完全分配,计算出free_pos后,传递给L1进行allocate
上面的逻辑是我从代码里分析来的,但是我感觉很疑惑,为什么

如果L2的槽位是上0xffffffffffffffff,就说明整个槽位还完全没有分配

0xffffffffffffffff不是all_slot_set 么?它不应该代表已经完全都分配了么??!!
希望熟悉这块的小伙伴不吝赐教。
第一次进入_allocate_l1之后,第一个槽位是0xffffffffffffffff,在上面进行分配空间,这部分逻辑可以参考:https://zhuanlan.zhihu.com/p/643938193
另外l1._allocate_l1 的返回值如果是true,就说明在L1对应的8个solt都已经分配完全了。如果真的返回true,那就需要修改L2上对应pos的bit为0。代表已经分配过了。

我任务这里面最麻烦的就是不知道什么时候0代表已经分配,什么时候1代表已经分配。

参考资料

https://zhuanlan.zhihu.com/p/643938193

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1704281.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

冯喜运:5.27黄金短线看震荡,今日黄金原油走势分析

【黄金消息面分析】&#xff1a;黄金作为传统的避险资产&#xff0c;在经济不确定性中扮演着至关重要的角色。近期&#xff0c;国际黄金价格经历了显著的波动。从5月9日的低点2325.19美元/盎司反弹至2340美元/盎司以上&#xff0c;尽管金价曾一度触及2449.89美元/盎司的历史高点…

C++ 数据结构算法 学习笔记(33) -查找算法及企业级应用

C 数据结构算法 学习笔记(33) -查找算法及企业级应用 数组和索引 日常生活中&#xff0c;我们经常会在电话号码簿中查阅“某人”的电话号码&#xff0c;按姓查询或者按字母排 序查询&#xff1b;在字典中查阅“某个词”的读音和含义等等。在这里&#xff0c;“电话号码簿”和…

高弹性架构的微服务设计模式

长期以来&#xff0c;开发人员一直使用单片架构&#xff0c;而且长期以来&#xff0c;这种架构一直有效。不幸的是&#xff0c;这些架构使用的部件较少&#xff0c;但体积较大&#xff0c;这意味着如果一个部件发生故障&#xff0c;它们更有可能整体失效。通常&#xff0c;这些…

《书生·浦语大模型实战营》第1课 学习笔记:书生·浦语大模型全链路开源体系

文章大纲 1. 简介与背景智能聊天机器人与大语言模型目前的开源智能聊天机器人与云上运行模式 2. InternLM2 大模型 简介3. 视频笔记&#xff1a;书生浦语大模型全链路开源体系内容要点从模型到应用典型流程全链路开源体系 4. 论文笔记:InternLM2 Technical Report简介软硬件基础…

HR招聘面试测评,哪些工作岗位需要测评创新能力?

什么是创新能力&#xff1f; 创新能力指在现有的物质基础上&#xff0c;通过某些特定的条件&#xff0c;促成满足未来社会发展的新事物。无论是个人还是国家都需要巨大的创新能力&#xff0c;因为创新是一切发展的根基&#xff0c;离开了创新&#xff0c;所有的发展都是原地踏…

Windows安全基础——Windows WMI详解

Windows安全基础——WMI篇 1. WMI简介 WMI&#xff08;Windows Management Instrumentation, Windows管理规范&#xff09;是Windows 2000/XP管理系统的核心&#xff0c;属于管理数据和操作的基础模块。设计WMI的初衷是达到一种通用性&#xff0c;通过WMI操作系统、应用程序等…

设计模式16——策略模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用&#xff0c;主要是下面的UML图可以起到大作用&#xff0c;在你学习过一遍以后可能会遗忘&#xff0c;忘记了不要紧&#xff0c;只要看一眼UML图就能想起来了。同时也请大家多多指教。 策略模式&#xff08;Strategy…

计算机的存储体系

计算机的存储分为内存和硬盘两大类。其中内存属于非持久化的存储设备&#xff0c;用于临时存储数据&#xff0c;设备掉电后数据会丢失&#xff1b;硬盘属于持久化的存储设备&#xff0c;设备掉电后数据不会丢失。 实际上在计算机领域存储的种类是非常多的&#xff0c;业界有时…

linux网卡MAC地址

1、ifconfig命令查看网卡MAC地址 1.1 通过HWaddr或ether字段过滤mac地址 ifconfig | grep HWaddr ifconfig | grep ether [rootlocalhost ~]# /sbin/ifconfig | grep ether 注&#xff1a;有些Linux发行版本的MAC地址字段为HWaddr&#xff0c;有些Linux发行版本的MAC地址字段…

SkyWalking 介绍及部署

1、SkyWalking简介2、SkyWalking的搭建 2.1 部署Elasticsearch2.2 部署SkyWalking-Server2.3 部署SkyWalking-UI3、应用接入 3.1 jar包部署方式3.2 dockerfile方式3.3 DockerFile示例4、SkyWalking UI 界面说明 4.1 仪表盘 4.1.1 APM &#xff08;1&#xff09;全局维度&#x…

clickhouse——ck目录介绍

一、ck目录 1、/etc/clickhouse-server: 服务端的配置文件目录&#xff0c;包括全局配置config.xml和用户配置users.xml等。 2、/var/lib/clickhouse 默认的数据存储目录&#xff08;通常会修改默认路径配置&#xff0c;将数据保存到大容量磁盘挂载的路径&#xff09; 3、/var…

电脑不能远程桌面连接不上,电脑无法建立远程桌面连接如何解决?

电脑无法建立远程桌面连接的问题&#xff0c;通常涉及到多个层面的因素&#xff0c;包括但不限于网络设置、系统配置、防火墙设置以及服务状态等。以下是一些专业性的解决方案&#xff0c;以帮助您解决这一问题。 首先&#xff0c;我们需要检查网络连接。远程桌面连接需要稳定的…

【数据库】通过一个实例来认识数据流图DFD

导读&#xff1a;通过一个实例&#xff08;数据中台&#xff09;说明数据流图DFD的作用、介绍了常见的数据流图元素及其标准符号以及如何画数据流图。数据流图主要被分析师、系统设计师、流程优化专家、系统管理员以及与系统开发和维护相关的人员查看和使用。对于刚考完2024年5…

怎样在网上赚点零花钱?推荐十个正规的赚钱兼职平台

今天要和大家探讨一个激动人心的话题——网络赚钱。在这个互联网日新月异的时代&#xff0c;网络赚钱已经变成了触手可及的现实。如果你正打算在网上赚取一些额外收入&#xff0c;那么这篇文章绝对值得一读&#xff01; 在这个信息泛滥的时代&#xff0c;网络赚钱的机遇随处可…

redis数据操作相关命令

1.list操作 1.1 rpush rpush&#xff1a;新的元素添加到list最右边 #从右边依次往List添加1,2,3 RPUSH name 1 RPUSH name 2 RPUSH name 3#查看列表&#xff1a;返回 1,2,3 LRANGE name 0 -1结果如下&#xff1a; 1.2 lpush lpush&#xff1a;新加的元素在list最左边 #从…

U8G2移植到STM32,SSD13XXXOLED(硬件SPI DMA通讯)

文章目录 一、前言1.1 U8g2的特点1.2 U8G2的优势1.3 U8G2的下载地址1.4 U8g2支持的显示控制器 二、STM32Cubexm SPI DMA配置2.1 SPI设置为半双工模式2.2 SPI DMA设置2.3 oled其他引脚配置 三、移植U8G2框架3.1 精简U8G2库文件3.2 去掉csrc文件夹中无用的驱动文件3.3 文件移动到…

【Java reentrantlock源码解读】

今天学习一下Java中lock的实现方式aqs 直接上图这是lock方法的实现类、分为公平锁和非公平锁两种。 先看非公平的实现方法、很暴力有木有&#xff0c;上来直接CAS&#xff08;抢占锁的方法&#xff0c;是一个原子操作&#xff0c;没有学过的同学自行百度哦&#xff09;&#…

香橙派 Kunpeng Pro使用教程:从零开始打造个人私密博客

一、引言 在这个日益互联的世界中&#xff0c;单板计算机已经成为创新和个性化解决方案的重要载体。而在单板计算机领域&#xff0c;香橙派 Kunpeng Pro凭借其强大的性能和灵活的应用潜力&#xff0c;正逐渐吸引着全球开发者和技术爱好者的目光。 作为一款集成了华为的鲲鹏处…

蓝牙模块、WiFi模块等无线通信模块使用规范

在当今的科技时代&#xff0c;无线通信模块已经广泛应用于各类电子设备中。特别是蓝牙模块、WiFi模块等无线模块&#xff0c;它们为设备间的通信提供了便利&#xff0c;使得我们的生活更加便捷和高效。然而&#xff0c;为了确保这些无线模块正常工作并避免可能的安全隐患&#…

I.MX6ULL的蜂鸣器实验-GPIO输出实验

系列文章目录 I.MX6ULL的蜂鸣器实验 I.MX6ULL的蜂鸣器实验 系列文章目录一、前言二、有源蜂鸣器简介三、硬件原理分析四、程序编写4.1程序编写前提工作4.2程序编写 五、编译下载验证5.1编写 Makefile 和链接脚本5.2编译下载 一、前言 在 I.MX6U-ALPHA 开发板上有一个有源蜂鸣器…