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

leveldb源码分析 #1 Slice WriteBatch WriteBatchInternal 【work记录】

日期:2025.9.6(凌晨)

个人总结:

perface

是这样的,本来是打算写完之后再整理的,但是感觉自己貌似会懒癌犯了,所以决定还是自己看了哪些内容就都发了吧。

如果自己真的会想整理的话,那就算之前写个过半成品应该也会有心去整理好好总结吧。

为了自己的数据库的水平可以再提高一些,所以准备阅读leveldb源码 (绝不是因为想看别的数据库源码,但是发现自己屁都看不懂

关于编译运行前的若干情况

clone下来后发现有可能编译不过,如果有这种情况,就在cmakelists里面加上一个set(CMAKE_CXX_STANDARD 17)就好了。

发现googletest的版本过低,请自行升级。(去clone一个最新版本的,然后替换掉thirdparty里面的gtest就好了。

前置声明:

由于本人的水平也并不高,对于源码的阅读是第一次,所以是有一些没有框架的逻辑在的,说人话就是自己是读到哪看到哪写到哪的。

并不专业,但是尽量会说出自己的理解,让个人听懂。

本人最后会把自己对于leveldb的中文注释放到仓库上去。

Slice

首先其实最先上来,去看有关db的文件了,然后发现有一个类出现的非常多,Slice。发现内容不长,所以先来拜读一下。

然后发现其内部主要是对const char * data 和 size_t size的一个封装,里面有一些有的比较多的函数,例如remove_prefix去除前n个字节。

看了看设计,发现这个主要是对资源获取他的指针,然后访问。我们不需要去一直传递资源从而浪费性能,直接传递Slice就好了,而且对他拷贝也并没有什么损耗,毕竟就一个指针和一个size_t。

值得注意的一点是,我们是需要确保资源没有被析构,否则会造成段错误。

//这个类并不需要得到资源,只是得到资源的指针用来方便访问而已。
// 所以也没有析构函数
class LEVELDB_EXPORT Slice {public:// Create an empty slice.Slice() : data_(""), size_(0) {}// Create a slice that refers to d[0,n-1].Slice(const char* d, size_t n) : data_(d), size_(n) {}// Create a slice that refers to the contents of "s"Slice(const std::string& s) : data_(s.data()), size_(s.size()) {}// Create a slice that refers to s[0,strlen(s)-1]Slice(const char* s) : data_(s), size_(strlen(s)) {}// Intentionally copyable.Slice(const Slice&) = default;Slice& operator=(const Slice&) = default;// Return true iff the length of the referenced data is zerobool empty() const { return size_ == 0; }const char* begin() const { return data(); }const char* end() const { return data() + size(); }//....此处省略	// Drop the first "n" bytes from this slice.void remove_prefix(size_t n) {assert(n <= size());data_ += n;size_ -= n;}private:const char* data_;size_t size_;
};

WriteBatch

后来接着顺序,看到了

// Default implementations of convenience methods that subclasses of DB
// can call if they wish
Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) {WriteBatch batch;batch.Put(key, value);return Write(opt, &batch);
}

这是db的put操作,这里有一个没有接触的类是WriteBatch

来翻看一下writebatch.h

/*
这就是一个写操作的集合,有点对标事务吧?*/
class LEVELDB_EXPORT WriteBatch {public://定义了一个基础操作类,有插入和删除两个操作class LEVELDB_EXPORT Handler {public:virtual ~Handler();virtual void Put(const Slice& key, const Slice& value) = 0;virtual void Delete(const Slice& key) = 0;};WriteBatch();// Intentionally copyable.WriteBatch(const WriteBatch&) = default;WriteBatch& operator=(const WriteBatch&) = default;~WriteBatch();void Put(const Slice& key, const Slice& value);void Delete(const Slice& key);void Clear();size_t ApproximateSize() const;void Append(const WriteBatch& source);Status Iterate(Handler* handler) const;private:friend class WriteBatchInternal;/*所以就现在来看,这个WriteBatch里的rep_里的前8个字节(uint64)代表返回这个写集合里的第一个队列的编号* 第8到第12字节(uint32)是代表count的个数,也就是目前存的个数。*/std::string rep_;  // See comment in write_batch.cc for the format of rep_
};

首先先来讲解一下,这个其实是一个写操作的集合,在leveldb里面,每一个操作都会有一个队列编号,其实也可以理解成操作编号,(主要是在并发控制的时候派上用场),然后这个操作会用WriteBatch维护起来,这个维护的具体方式是用一个字符串rep_去记录下来操作的内容。

首先是规定了rep_的前8个字节代表的是这个操作集合的第一个队列的编号,为什么说是第一个队列的编号,是因为leveldb对于这个writebatch有一个小优化,就是如果有很多的操作,如果我们对于每一个操作单独处理,空间上会有一些浪费,例如每一个writebatch都要开前12个字节去记录,还有一点就是落盘操作会慢一些,一次性批量的写入完会更快一些。所以优化就是会把很多个操作都放到同一个writebatch里面,在这里面他们的队列编号其实是单调递增且连续的。所以我们记录下来第一个队列的编号就好了。

对于第9到12个字节(uint32_t),代表的是队列里面放的操作的个数。(这也是static const size_t kHeader = 12;的原因)后续就是存放具体的操作了。

然后我们来看一下writebatch的put操作:

// 这里就是,每一次put的时候,我们把key和value追加到rep_里面去。
// 首先是count个数要+1,然后放进去
// 关于rep的内容,首先是用一个char类型(也就是一个字节)去区分类型,如果是kTypeValue,那么就是Put操作。
// 然后就会进行两次长度+内容的解析,也就是先读取长度,然后读取对应长度的字节去转换过来。
// 这样就搞出来了key和value。
// 下面的delete也是这样的操作。
void WriteBatch::Put(const Slice& key, const Slice& value) {WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);rep_.push_back(static_cast<char>(kTypeValue));PutLengthPrefixedSlice(&rep_, key);PutLengthPrefixedSlice(&rep_, value);
}

对于每一个操作,我们会用一个字节去存放这个操作的类型,如果是kTypeValue就是put,也就是update或者insert操作,这里没有做更进一步的区分,因为其实无论如何都是insert,并不会有概念上的update操作,关于这里先暂且不详谈,等到将table的时候再说。

如果是kTypeValue就是put,那么我们再跟上key和value。这里的函数实现:

//追加了一个长度,然后还有对应长度的数据。
void PutLengthPrefixedSlice(std::string* dst, const Slice& value) {PutVarint32(dst, value.size());dst->append(value.data(), value.size());
}

我们肯定是要先存放key的长度,然后再放进去key。value我们也是这样的处理。 (PutVarint32这个内容我们以后会说到)

如果是删除操作,也是和put类似的内容。

void WriteBatch::Delete(const Slice& key) {WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);rep_.push_back(static_cast<char>(kTypeDeletion));PutLengthPrefixedSlice(&rep_, key);
}

这里的PutLengthPrefixedSlice函数,是关于coding.h的内容,我们等会会详说。先接着把WriteBatch的内容说完。

还有一个关于WriteBatch的稍微重要一些的内容:

就是其实我们并不会直接面向WriteBatch(大多数),而是用WriteBatchInternal。

这个WriteBatchInternal其实是一个辅助我们,给我们提供了一些操作WriteBatch的一些接口。我们如果有一些想要对于WriteBatch实现的函数,那么就是在这个WriteBatchInternal里面先写好接口,然后在WriteBatch里面实现好具体的功能。

但以上的两个put和delete函数的内容,则主要是面向于对于一个WriteBatch初始化的时候我们做的内容,例如我们想要put一对{key,value},我们会创建一个WriteBatch,然后调用put函数,之后的事情就交给WriteBatchInternal了,其实我觉得可以把最开始的put和delete操作也交给WriteBatchInternal来做,也不知道为什么把put和delete给单独交给WriteBatch来搞了。

这里直接贴上了WriteBatchInternal的类的代码了,附带中文注释。关于这些函数内容,我们接下来会谈到。


namespace leveldb {class MemTable;// WriteBatchInternal provides static methods for manipulating a
// WriteBatch that we don't want in the public WriteBatch interface.
class WriteBatchInternal {public:// Return the number of entries in the batch.static int Count(const WriteBatch* batch);// Set the count for the number of entries in the batch.static void SetCount(WriteBatch* batch, int n);// Return the sequence number for the start of this batch.// 获得队列编号static SequenceNumber Sequence(const WriteBatch* batch);// Store the specified number as the sequence number for the start of// this batch.//设置队列编号static void SetSequence(WriteBatch* batch, SequenceNumber seq);//返回一个Slice,用来访问内部数据的static Slice Contents(const WriteBatch* batch) { return Slice(batch->rep_); }//返回rep_里的具体的长度static size_t ByteSize(const WriteBatch* batch) { return batch->rep_.size(); }//赋值操作static void SetContents(WriteBatch* batch, const Slice& contents);//插入操作,把batch的内容写到memtable里面static Status InsertInto(const WriteBatch* batch, MemTable* memtable);//合并操作,直接把src合并到dst上去static void Append(WriteBatch* dst, const WriteBatch* src);
};}  // namespace leveldb

关于前面的Count,SetCount等函数我们就不说了,就是简单的返回一个值的操作。

比较重要的有两个,一个是InsertInto函数,另一个是Append函数。

//虽然是InsertInto操作,但是这里确切将是开始执行写操作(包括插入删除)
Status WriteBatchInternal::InsertInto(const WriteBatch* b, MemTable* memtable) {MemTableInserter inserter;inserter.sequence_ = WriteBatchInternal::Sequence(b);inserter.mem_ = memtable;return b->Iterate(&inserter);
}

关于这个InsertInto函数,我们会声明一个插入器,把队列的编号和memtable给他,然后调用 b->Iterate(&inserter);,我们现不管这个,而是去考虑一个基础的操作类。

//定义了一个基础操作类,有插入和删除两个操作class LEVELDB_EXPORT Handler {public:virtual ~Handler();virtual void Put(const Slice& key, const Slice& value) = 0;virtual void Delete(const Slice& key) = 0;};

这个Handler定义了基础的put和delete操作,MemTableInserter就是基于这个来的。关于这些抽象的接口我们可以先不管,而是去看看Iterate函数。

这个内容其实比较简单,就是把我们存到WriteBatch里的操作给逐一解析出来,解析出来之后根据那个一个字节的type来选择调用put还是delete操作。

/*
这一段写的比较简单
就如把存起来的操作给依次实现出来,用一个handler去做Put,Delete操作等
*/
Status WriteBatch::Iterate(Handler* handler) const {Slice input(rep_);if (input.size() < kHeader) {return Status::Corruption("malformed WriteBatch (too small)");}//注意这里input的remove不是真的remove,只是指针前移了而已。//实际的内容在rep_里input.remove_prefix(kHeader);Slice key, value;int found = 0; //已经搞了的操作数while (!input.empty()) {found++; //操作数+1,然后开始解析这次的操作char tag = input[0]; //取出来标记符,看看是kTypeValue还是kTypeDeletioninput.remove_prefix(1);switch (tag) {case kTypeValue:if (GetLengthPrefixedSlice(&input, &key) &&GetLengthPrefixedSlice(&input, &value)) {handler->Put(key, value);} else {return Status::Corruption("bad WriteBatch Put");}break;case kTypeDeletion:if (GetLengthPrefixedSlice(&input, &key)) {handler->Delete(key);} else {return Status::Corruption("bad WriteBatch Delete");}break;default:return Status::Corruption("unknown WriteBatch tag");}}//最后的found应该和我们Count出来的结果一致if (found != WriteBatchInternal::Count(this)) {return Status::Corruption("WriteBatch has wrong count");} else {return Status::OK();}
}

这里中间有一个函数GetLengthPrefixedSlice,是用来把input开头存放的数字放到len里面,然后依据len来解析出来后续的key或者value,把内容放到result里面,input会去除开头的数字和内容。

//这里是把input开头解析的数字放到了result里面,input会去除result的部分。
// 按照这里的写法,Slice的开头存放的是长度。
// 如果返回的false,有种情况会是解析的数字过大,而Slice的实际长度却不够。
// 但是如果Slice设置的没有问题的情况下,应该不会发生这种问题。
// 成功了返回true,否则返回false
bool GetLengthPrefixedSlice(Slice* input, Slice* result) {uint32_t len;if (GetVarint32(input, &len) && input->size() >= len) {*result = Slice(input->data(), len);input->remove_prefix(len);return true;} else {return false;}
}

里面有个函数GetVarint32我们下一节会去讲它。

另外关于WriteBatchInternal的另一个函数Append,内容也比较简单,注释在里面了。

void WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) {SetCount(dst, Count(dst) + Count(src));assert(src->rep_.size() >= kHeader);// 这里就是直接把src的内容(去掉了header)给加了进来。上面的assert就是纯防止第二个参数搞成了负数罢了。dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader);
}

关于WriteBatch的test

其实对于这一块部分,我初步的理解也算是一个写操作的集合,后来深入了解其实不是先看源码,而是先去看了test。

其实在做CMU的时候对于自己不太了解的内容除了问AI以外,看test是一个比较方便的东西,可以比较简洁直观的看出来在做什么。

TEST(WriteBatchTest, Multiple) {WriteBatch batch;batch.Put(Slice("foo"), Slice("bar"));batch.Delete(Slice("box"));batch.Put(Slice("baz"), Slice("boo"));WriteBatchInternal::SetSequence(&batch, 100);ASSERT_EQ(100, WriteBatchInternal::Sequence(&batch));ASSERT_EQ(3, WriteBatchInternal::Count(&batch));ASSERT_EQ("Put(baz, boo)@102""Delete(box)@101""Put(foo, bar)@100",PrintContents(&batch));
}

比如这一段,我们可以看到里面放了三个操作,然后利用WriteBatchInternal去搞了一些操作。

当然这里最开始的时候也没看懂(bushi,因为这里是从memtable用迭代器去读取,所以会有一个key的顺序从小到大,这都是后话了。

postscript

这里又开了新坑,之前的CMU没有在搞了,因为感觉之前打了数据库的比赛,做CMU可能对我的帮助没有那么大了,于是选择开始看源码了,先从一个简单的开始,但愿这次不会弃坑。

相关文章:

leveldb源码分析 #1 Slice WriteBatch WriteBatchInternal 【work记录】

日期:2025.9.6(凌晨) 个人总结: perface 是这样的,本来是打算写完之后再整理的,但是感觉自己貌似会懒癌犯了,所以决定还是自己看了哪些内容就都发了吧。 如果自己真的会想整理的话,那就算之前写个过半成品应该也会有心去整理好好总结吧。 为了自己的数据库的水平可以再提…...

欧拉安装

因为 openEuler 22.03 LTS 使用的内核版本是 5.10,所以选择 5.x 内核的选项是最匹配的。...

2025实测:6款主流公众号编辑器大比拼,解决你的排版难题!

在新媒体运营的日常工作中,公众号排版是一项耗时又费力的任务。写作慢、排版耗时、跨平台排版不统一、跨平台发文琐碎、热点跟不动不及时、配图难/侵权风险等问题,常常困扰着我们这些新媒体人。为了找到一款好用的公众号编辑器,我亲测了多款市面上的主流产品。在本文中,我将…...

devc学C语言

之前用的是VS,现在开始用 devc,兼容性更强...

HarmonyOS 5.1手势事件详解

大家好,我是 V 哥。手势事件由绑定手势方法和绑定的手势组成,绑定的手势可以分为单一手势和组合手势两种类型,根据手势的复杂程度进行区分。本文跟着 V 哥一起来探讨手势事件处理。 想要考取鸿蒙认证的小伙伴,请加入V 哥班级获取辅导: https://developer.huawei.com/consu…...

Vue3项目中集成AI对话功能的实战经验分享

ai-suspended-ball-chat组件使用体验摘要 本文分享了Vue3项目中使用ai-suspended-ball-chat组件集成AI对话功能的实践经验。该组件提供悬浮球和独立面板两种模式,支持流式响应、图片上传、语音交互等功能,显著提升了用户体验。通过实际案例展示了在客服系统和代码助手场景中的…...

gulimall出现服务间调用org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.choose 问题

java.lang.AbstractMethodError: org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.choose(Ljava/lang/String;Lorg/springframework/cloud/client/loadbalancer/Request;)Lorg/springframework/cloud/client/ServiceInstance;A调用B模块出现上面这个问题,…...

Java02课前问题列表

Java02课前问题列表1.方法相关问题 public class Main {static void changeStr(String x) {x = "xyz";}static void changeArr(String[] strs) {for (int i = 0; i < strs.length; i++) {strs[i] = strs[i]+""+i;}}public static void main(String[] ar…...

达梦数据库安装和使用

1、达梦数据库安装地址 https://eco.dameng.com/document/dm/zh-cn/start/install-dm-windows-prepare.html 2、 点击下载3、4、 现在版本只需要点击exe文件56 点击【下一步】如图所示7、 接受授权协议8 如果没有key文件可跳过 如果有点击浏览找到key文件系统自动校验9建议典型…...

CSP 赛前周记

初赛前 - 第一周(末) 这学期的第一周,据说是本学期第二长的假期,故开始摸摸。 Day1 - 周五 晚上回来开了把信奥大联赛,发现比你谷月赛还烂,IOI 赛制,风格跟 CSP 三不沾,每周有时间打打玩玩吧(结果被打爆了,只有 230pts)。总结Day2 - 周六 由于作业多得一批,白天在疯…...

Day16对数组的基本认识

数组的定义package array;public class ArrayDemo1 {//变量类型 变量名称 = 变量的值//数组类型 同上public static void main(String[] args) {int [] nums;//声明一个数组nums = new int [10];//创建一个数组int [] nums1 =new int [10];//两种写法都可,初学建议拆分避免…...

Ubuntu 界面变为 Mac

sudo apt install gnome-tweaks...

今日随笔

今天完成了社会实践调查作业...

Day16

数组的定义package array;public class ArrayDemo1 {//变量类型 变量名称 = 变量的值//数组类型 同上public static void main(String[] args) {int [] nums;//声明一个数组nums = new int [10];//创建一个数组int [] nums1 =new int [10];//两种写法都可,初学建议拆分避免…...

PVE9环境下飞牛OS安装vGPU驱动

1.安装过程# 切换root权限 sudo su -# 屏蔽nouveau echo "blacklist nouveau" >> /etc/modprobe.d/blacklist-nouveau.conf# 更新initramfs update-initramfs -u# 安装组件 apt update && apt install build-essential dkms linux-headers-generic lib…...

02020304 .NET Core核心基础组件04-配置系统、Json文件配置、选项方式读取、扁平化环境变量其它配置源

02020304 .NET Core核心基础组件04-配置系统、Json文件配置、选项方式读取、扁平化&环境变量&其它配置源 1. 配置系统入门(视频2-32)传统Web.config配置的缺点,之前DI讲过。 为了兼容,仍然可以使用web.config和ConfigurationManage类,但不推荐。 .NET中的配置系统…...

md格式

markdown # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题*斜体* **粗体** ***粗斜体*** ~~删除线~~ `print("hello world)` ==高亮== 一级标题 二级标题 三级标题 四级标题 斜体 粗体 粗斜体 删除线 print("hello world) 高亮>一层嵌套引用 >>二层嵌套…...

CSP-S模拟20

前言: 一场通过乱搞获得如下成绩的比赛。\(T1:\) 思路: 一场情况超级复杂(bushi)的大模拟(应该可以这么叫吧?)直接先这样这样,在那样那样,最后在叽里呱啦就好了。 嘿嘿,开个玩笑嘛。首先,我们知道一定至少从\(S\)跳到\(S\)到\(T\)的那条链上,这样我们可以就\(S\)跳…...

第7篇、Kafka Streams 与 Connect:企业级实时数据处理架构实践指南

Kafka Streams 与 Kafka Connect:企业级实时数据处理架构实践指南 技术背景与适用场景 在现代数据架构中,实时数据处理已成为企业数字化转型的核心能力。Apache Kafka作为分布式流处理平台,提供了两个关键组件:Kafka Streams:轻量级流处理库,支持有状态实时计算 Kafka Co…...

Day16编写一个计算机程序

package method; import java.util.Scanner; public class Demo6 {/**作业:*1 写四个方法,加减乘除*2 利用循环+switch进行用户交互*3 传递需要操作的两个数*4 输出结果*/public static void main(String[] args) {Scanner scanner = new Scanner(System.in);boolean sco…...

迷宫最短路径

2025.9.11 曹立 题目内容 给定一个迷官的地图,地图是一个二维矩阵,其中0表示通道,1表示墙壁,S表示起点,E表示终点。你需要从起点S出发,通过最路径到达终点E,返回最短路径的步数,如果无法到达终点,则返回-1,迷宫中会有虫洞,用数字2表示,成对出现,你走入虫洞可以穿越…...

千靶日记-0003

day-3 今天事情不多,继续打靶,这个靶机关键点不多 Hommie靶机复盘 https://t.bilibili.com/1111299672388927491?share_source=pc_native...

COMSOL 6.3 下载+安装教程+激活教程:一站式下载安装激活操作说明

COMSOL 6.3 作为主流多物理场仿真软件,是工程设计与科研的重要工具。不少用户在下载安装时会遇权限不足、许可证无效等问题。本教程围绕安全下载渠道、 step-by-step 安装步骤、常见问题解决展开,还附入门实操,助你高效完成安装,快速上手软件。目录一、先搞懂:COMSOL 6.3 …...

20231427-田泽航-Linux命令实践

1...

202207_BUGKU_二维码GIF

GIF分离,QRCODE,ZXING库Tags:GIF分离,QRCODE,ZXING库 0x00. 题目0x01. WP 01 分离GIF工具路径:https://pan.baidu.com/s/1GyH7kitkMYywGC9YJeQLJA?pwd=Zmxh#list/path=/CTF附件/Tools 工具名称:风二西_GIF图片分离工具.zip 02 使用脚本批量扫描 exp.py #将指定文件夹下的文件…...

20250910NOIP模拟赛

20250910NOIP模拟赛 A 题意: 有 \(n\) 个小球分为红、蓝两种颜色排成一排,现在你可以进行若干次操作,每次操作选择任意 \(R+B\) 个小球,使其有 \(R\) 个红球,\(B\) 个蓝球,把这些小球全部染为白色,且在该选择序列中,最左侧的球到最右侧的球之间不得存在已经被染为白色的…...

分治 NTT 一则

le0n 太强大!1...

U604938 你不准卡 O(n sqrt n log L) 其中 L log L = sqrt n

U604938 你不准卡 O(n sqrt n log L) 其中 L log L = sqrt n 如题目所言,这道题的出现就是为此,所以不要说什么 wyy。 首先是空间上卡掉了 \(n\sqrt n\) 空间的做法,然后因为值域限制卡掉了回滚莫队(也许只是我菜才不会写?)。总之再有什么我也没法了,就这样。 如果你要卡…...

20250906

20250906T1 推倒骨牌 多维护几个东西就能直接倍增了。不要开 long long。代码 #include <iostream> #include <algorithm> #include <string.h> #define lowbit(x) ((x) & (-(x))) using namespace std; int n, q; struct BIT {pair<int, int> bi…...

【2025最新推荐】AI大模型API中转站 | 国内直连ChatGPT/Claude/Gemini全系API接口服务

作为一名开发者,你是否曾为了使用ChatGPT、Claude等AI模型而苦恼?网络问题、支付困难、成本昂贵...这些痛点让很多国内开发者望而却步。今天给大家推荐简易API中转站,解决这些问题。 1.什么是API中转站? API中转站是专为国内开发者打造的AI模型API中转服务平台。简单来说,…...

在用灵魂去感受另一个灵魂的震颤

【用灵魂去感受另一个灵魂的震颤】...

html怎么写

html 1. 基本结构 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title></title> <bod…...

谁拿了谁的伞?

我:要去上课了,哎,不想去上课,我想在工位带着。算了,还是去吧。我的伞放在工位门口左边,光线很黑,拿错了雨伞,拿成了学长的雨伞去上课。一到教室,刚坐下,老师就开始说,不让坐最后一排啊,你们几个快做前面去,然后我就拿着我的伞坐到了前面。这课是真无聊,我准备上…...

NSSCTF-misc

签到 用emoji-aes解码,key为GAME ☀☺⏩☺⌨☂☃✅ 得到flag{10ve_4nd_Peace} GIF有点大GETwbStego4open 隐写 首先,wbStego4open会把插入数据中的每一个ASCII码转换为二进制形式 然后,把每一个二进制数字再替换为十六进制的20或09,20代表0,09代表1 最后,将这些被转换后的…...

百粉粉福

应机房某人要求,说要搞一个百粉粉福,决定先做一个 \(Q&A\) ,其它的请各位想想可以做什么别的粉福。 \(Q&A\) 可以直接回复这篇帖子或直接私信我,到时候会发到你谷主页,文章跟博客园,支持一下呗QwQ \(Q&A\)Q:瑞平我 @Misty_PostA:感觉是非常可爱的学弟,平时…...

lc1024-视频拼接

难度:中等(中期)题目描述给定一些区间和一个数字 time,找到能覆盖 [0, time] 的最少区间数示例 输入:clips = [[0,2],[4,6],[8,10],[1,9],[1,5],[5,9]], time = 10 输出:3 解释:选 [0,2], [8,10], [1,9]输入:clips = [[0,1],[1,2]], time = 5 输出:-1 解释:找不到返回…...

多元统计分析1

多元统计分析1 大三开始学习多元统计分析,首先使一些预备知识,基本是就是一些高代,数分,概率论的有些难度的知识。我个人觉得这些知识还是有难度的,尤其是距离高代已经过去了一年时间了。 概率论这里就是一些随机变量的均值,方差的性质。由于涉及到了多变量的协方差矩阵一…...

OI界的梗

%%% 在C++“%”是取模的意思,简称模,是膜拜大佬的意思(%越多,语气越强) 蒟蒻 他本是一种可以吃的植物(就是魔芋),可是因为他谐音“巨弱”,所以,他被用作自嘲,但没人会说别人是蒟蒻的,这是一种基础礼仪 神犇(读ben(第一声))、巨佬 神犇是大牛的升级版 巨佬是大佬…...

202404_QQ_ZIP嵌套

ZIP,嵌套Tags:ZIP,嵌套 0x00. 题目 附件路径:https://pan.baidu.com/s/1GyH7kitkMYywGC9YJeQLJA?pwd=Zmxh#list/path=/CTF附件 附件名称:202404_QQ_ZIP嵌套.zip 0x01. WP打开txt文件发现文件头为504b0304 导入到010Editor另存为tmp.zip 打开tmp.zip发现里面是另一个txt 打开…...

无重复字符的最长子串-leetcode

题目描述给定一个字符串 s ,请你找出其中不含有重复字符的 最长 的长度。 示例 1: 输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。示例 2: 输入: s = "bbbbb" 输出: 1 解释: 因为无重复字符的最长子…...

两个常见的 计数问题 trick

两个非常有用的计数 trick,虽然感觉比较典。 计数转 01 有一件事情:\(v=\sum_{i=1}^V [v \geq i]\),\(V\) 为值域。看着好像没有什么突破性的转变,但是当我们对很多东西进行统计的时候,如果对于 有多少个大于等于 某个值 \(v\) 是好做的话,那么我们就可以做这个转化:\(\…...

搜维尔科技:Xsens人形机器人拟人动作AI训练,提升机器人工作精度与效率

随着人工智能与机器人技术的深度融合,人形机器人正从实验室走向工业制造、医疗护理、公共服务等真实场景。然而,要让机器人真正"像人类一样工作",其动作的流畅性、精准度与环境适应性仍是技术突破的关键。Xsens动作捕捉系统通过创新的拟人化动作AI训练方案,为机器…...

文件轮转机制

文件轮转机制 基于文件的持久化队列(File-based Persistent Queue),利用 双文件切换(Double Buffering / File Rotation) 来保证批处理、高效写入、并发安全。 方法主要实现的机制双文件切换(Double Buffering / File Rotation) • 通过 inputFile(正在写的新数据) 和…...

202110_绿盟杯_隐藏的数据

ZIP,伪加密,密码爆破,DOCX文件Tags:ZIP,伪加密,密码爆破,DOCX文件 0x00. 题目 附件路径:https://pan.baidu.com/s/1GyH7kitkMYywGC9YJeQLJA?pwd=Zmxh#list/path=/CTF附件 附件名称:202110_绿盟杯_隐藏的数据.zip 0x01. WP 01 打开压缩包,发现有word文件和zip文件,得到flag1…...

【初赛】图 - Slayer

欧拉图 在图论中,欧拉路径是经过图中每条边恰好一次的路径,欧拉回路是经过图中每条边恰好一次的回路。 如果一个图中存在欧拉回路,则这个图被称为欧拉图;如果一个图中不存在欧拉回路但是存在欧拉路径,则这个图被称为半欧拉图。 对于连通图 G,以下三个性质是互相等价的: …...

线上课

反射反射就是在程序运行时 获取到类的信息(成员变量 成员方法 构造方法) 并操作对象的属性和方法 获取class对象就可以拿到类的信息 获取class对象Class.forName(全类名) 类名.class 对象.getClass字节码是唯一的 无论哪种方式获取 都是同一个class对象当通过反射拿到的构造…...

弹窗、抽屉、当前页和新开页,到底怎么选? - 智慧园区

弹窗、抽屉、当前页、新开页,看似只是交互容器的选择,实则关乎信息密度、操作路径与用户心智的精准匹配。本文从B端产品的真实场景出发,拆解四种容器的使用逻辑与适配原则,帮助产品经理构建更清晰的设计判断框架。在B端产品的设计实践中,你是否曾面临过以下的灵魂拷问?你…...

POJ 2566 Bound Found

题面描述: 美国航空航天局(该机构似乎正经历叛逆期:"我就要用英尺,才不用米呢!")接收并数字化了极可能来自地外文明的信号。每个信号包含两部分:一个由n个整数值组成的序列和一个非负整数t。虽然细节不便透露,但研究人员发现信号编码了两个整数值。这两个值可…...

搜维尔科技:Haption触觉力反馈系统,沉浸式远程呈现、数字孪生、混合现实和移动远程机器人

为您的项目提供技术和经验 自2001年以来,HAPTION力反馈设备已被用于广泛的研究应用。 您是否希望在您的项目中使用HAPTION力反馈设备 您是否正在寻找国内厂商来申请新项目 增强人机交互-远程操作,实现人机交互 图片 图片 通过最先进的社交、视觉、触觉、音频和嗅觉技术的出色…...

飞书免费企业邮箱推荐

1、品牌背书:成长技术最快的企业,稳定性拉满 对于中小企业而言,一款稳定、安全且免费的企业邮箱,不仅能降低运营成本,更能提升团队沟通效率。飞书作为字节跳动旗下的协同办公平台,其推出的免费企业邮箱服务,凭借 “零成本、强协同、高安全” 的特点,成为越来越多企业的…...