深度解析RocketMq源码-持久化组件(二) MappedFileQueue

1.绪论

MappedFileQueue是commitLog中最核心的主组件。前面讲解commitLog的时候也曾说过,MappedFileQueue本质上就是一个MappedFile队列,而commitLog操纵Mmapped读写的时候,也是通过MappedFileQueue来实现的。

commitlog和mappedfilequeue和mappedfile的关系如图所示:

所以我们需要分析一下mappedfilequeue的具体作用。

2.MappedFileQueue

2.1 组成

public class MappedFileQueue implements Swappable {private static final Logger log = LoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME);private static final Logger LOG_ERROR = LoggerFactory.getLogger(LoggerName.STORE_ERROR_LOGGER_NAME);protected final String storePath;//mappedfile的大小protected final int mappedFileSize;//mappedfile的队列protected final CopyOnWriteArrayList<MappedFile> mappedFiles = new CopyOnWriteArrayList<>();//mappedFile分配服务protected final AllocateMappedFileService allocateMappedFileService;//刷新和commit的指针protected long flushedWhere = 0;protected long committedWhere = 0;//存储时间戳,主要是删除过期的mappedfile使用protected volatile long storeTimestamp = 0;
}

2.2 检查每个commitfile是否损坏

其实就是遍历前n-1个commitfile的大小,判断是否为mappedFileSize,如果不是,便认为文件已经损坏。

//检查每个commitfile是否损坏public void checkSelf() {List<MappedFile> mappedFiles = new ArrayList<>(this.mappedFiles);if (!mappedFiles.isEmpty()) {Iterator<MappedFile> iterator = mappedFiles.iterator();MappedFile pre = null;//遍历每个mappedfilewhile (iterator.hasNext()) {MappedFile cur = iterator.next();if (pre != null) {//计算出每个commitfile的大小看是否为mappedFileSize(1gb)if (cur.getFileFromOffset() - pre.getFileFromOffset() != this.mappedFileSize) {LOG_ERROR.error("[BUG]The mappedFile queue's data is damaged, the adjacent mappedFile's offset don't match. pre file {}, cur file {}",pre.getFileName(), cur.getFileName());}}pre = cur;}}}

2.2 根据时间戳获取大于该时间戳或者小于时间戳的消息的时间

可以看出mappedfile中的startTimestamp为第一条消息的写入时间,stopTimestamp为最后一条消息的写入时间。并且该方法根据boundaryType进行判断:

如果boundaryType传参为LOWER,表示获取最后一条消息写入时间大于等于传入时间的mappedfile;如果boundaryType传参为UPPER,表示获取第一条消息写入时间小于等于传入时间的mappedfile
  //根据时间戳,获取一段数据public MappedFile getConsumeQueueMappedFileByTime(final long timestamp, CommitLog commitLog,BoundaryType boundaryType) {//获取commitfile数组Object[] mfs = copyMappedFiles(0);if (null == mfs) {return null;}//从后往前遍历m每个mappedfilefor (int i = mfs.length - 1; i >= 0; i--) {DefaultMappedFile mappedFile = (DefaultMappedFile) mfs[i];// Figure out the earliest message store time in the consume queue mapped file.if (mappedFile.getStartTimestamp() < 0) {//从commitlog的持久化文件中获取到该commitlog开始写入数据的时间戳并且设置到commitlogfile中SelectMappedBufferResult selectMappedBufferResult = mappedFile.selectMappedBuffer(0, ConsumeQueue.CQ_STORE_UNIT_SIZE);if (null != selectMappedBufferResult) {try {ByteBuffer buffer = selectMappedBufferResult.getByteBuffer();long physicalOffset = buffer.getLong();int messageSize = buffer.getInt();long messageStoreTime = commitLog.pickupStoreTimestamp(physicalOffset, messageSize);if (messageStoreTime > 0) {mappedFile.setStartTimestamp(messageStoreTime);}} finally {selectMappedBufferResult.release();}}}// Figure out the latest message store time in the consume queue mapped file.//从commitlog的持久化文件中获取到该commitlog最后一条消息的写入的时间戳并且设置到commitlogfile中if (i < mfs.length - 1 && mappedFile.getStopTimestamp() < 0) {SelectMappedBufferResult selectMappedBufferResult = mappedFile.selectMappedBuffer(mappedFileSize - ConsumeQueue.CQ_STORE_UNIT_SIZE, ConsumeQueue.CQ_STORE_UNIT_SIZE);if (null != selectMappedBufferResult) {try {ByteBuffer buffer = selectMappedBufferResult.getByteBuffer();long physicalOffset = buffer.getLong();int messageSize = buffer.getInt();long messageStoreTime = commitLog.pickupStoreTimestamp(physicalOffset, messageSize);if (messageStoreTime > 0) {mappedFile.setStopTimestamp(messageStoreTime);}} finally {selectMappedBufferResult.release();}}}}switch (boundaryType) {//如果boundaryType传参为LOWER,表示获取最后一条消息写入时间大于等于传入时间的mappedfilecase LOWER: {for (int i = 0; i < mfs.length; i++) {DefaultMappedFile mappedFile = (DefaultMappedFile) mfs[i];if (i < mfs.length - 1) {long stopTimestamp = mappedFile.getStopTimestamp();if (stopTimestamp >= timestamp) {return mappedFile;}}// Just return the latest one.if (i == mfs.length - 1) {return mappedFile;}}}//如果boundaryType传参为UPPER,表示获取第一条消息写入时间小于等于传入时间的mappedfilecase UPPER: {for (int i = mfs.length - 1; i >= 0; i--) {DefaultMappedFile mappedFile = (DefaultMappedFile) mfs[i];if (mappedFile.getStartTimestamp() <= timestamp) {return mappedFile;}}}}return null;}

2.3 获取修改时间大于等于传入时间的mappedfile

    //获取修改时间大于等于传入时间的mappedfilepublic MappedFile getMappedFileByTime(final long timestamp) {Object[] mfs = this.copyMappedFiles(0);if (null == mfs)return null;for (int i = 0; i < mfs.length; i++) {MappedFile mappedFile = (MappedFile) mfs[i];if (mappedFile.getLastModifiedTimestamp() >= timestamp) {return mappedFile;}}return (MappedFile) mfs[mfs.length - 1];}

2.4 根据offset,删除大于传入offset后面的所有数据

    //根据offset,删除大于传入offset后面的所有数据public void truncateDirtyFiles(long offset) {List<MappedFile> willRemoveFiles = new ArrayList<>();for (MappedFile file : this.mappedFiles) {long fileTailOffset = file.getFileFromOffset() + this.mappedFileSize;if (fileTailOffset > offset) {//如果offset在对应的mappedfile中,需要重置写指针、flsuh指针和commit指针if (offset >= file.getFileFromOffset()) {file.setWrotePosition((int) (offset % this.mappedFileSize));file.setCommittedPosition((int) (offset % this.mappedFileSize));file.setFlushedPosition((int) (offset % this.mappedFileSize));} else {//删除小于offset的mappedfile,主要包括关闭niochannel,删除磁盘文件和利用buffer的clean方法清除bufferfile.destroy(1000);willRemoveFiles.add(file);}}}this.deleteExpiredFile(willRemoveFiles);}

2.5 从mappedfilequeue中删除对应的文件

   //从mappedfilequeu中删除过期的文件(传入的files)void deleteExpiredFile(List<MappedFile> files) {if (!files.isEmpty()) {Iterator<MappedFile> iterator = files.iterator();while (iterator.hasNext()) {MappedFile cur = iterator.next();if (!this.mappedFiles.contains(cur)) {iterator.remove();log.info("This mappedFile {} is not contained by mappedFiles, so skip it.", cur.getFileName());}}try {if (!this.mappedFiles.removeAll(files)) {log.error("deleteExpiredFile remove failed.");}} catch (Exception e) {log.error("deleteExpiredFile has exception.", e);}}}

2.6 broker初始化的时候,如何将磁盘文件与内存建立映射关系

其实在构建mappedfile的时候,会调用mappedfile的init方法,该方法会见了mappedByteBuffer和磁盘文件的映射关系。

  //在broker重启时,需要从磁盘中将mappedfile读取到内存中public boolean doLoad(List<File> files) {//根据名称排序,mappedfile的名称其实就是文件的物理偏移量files.sort(Comparator.comparing(File::getName));for (int i = 0; i < files.size(); i++) {File file = files.get(i);if (file.isDirectory()) {continue;}if (file.length() == 0 && i == files.size() - 1) {boolean ok = file.delete();log.warn("{} size is 0, auto delete. is_ok: {}", file, ok);continue;}if (file.length() != this.mappedFileSize) {log.warn(file + "\t" + file.length()+ " length not matched message store config value, please check it manually");return false;}try {//新建一个mappedfile,这里会调用mappedfile的init方法,他会新建一个mappedbytebuffer,并且与文件建立映射关系MappedFile mappedFile = new DefaultMappedFile(file.getPath(), mappedFileSize);//初始化文件的写指针、flush指针、commit指针mappedFile.setWrotePosition(this.mappedFileSize);mappedFile.setFlushedPosition(this.mappedFileSize);mappedFile.setCommittedPosition(this.mappedFileSize);//加入到mappedfilequeue中this.mappedFiles.add(mappedFile);log.info("load " + file.getPath() + " OK");} catch (IOException e) {log.error("load file " + file + " error", e);return false;}}return true;}

2.7 根据起始偏移量获取到最后一块mappedfile

在获取到最后一块mappedfile的时候,可以根据needcreate参数判断:如果超过内存范围,是否需要重新构建一个mappedfile。

   //重要,根据起始偏移量获取到最后一块mappedfile,并且根据needcreate参数判断如果超过内存范围,是否需要重新构建一个mappedfilepublic MappedFile getLastMappedFile(final long startOffset, boolean needCreate) {long createOffset = -1;//获取到mappedfilequeue中的最后一个mappedfileMappedFile mappedFileLast = getLastMappedFile();//如果最后一块mappedfile为空,表示此时为初始化,获取到新的mapperfile的起始位置if (mappedFileLast == null) {createOffset = startOffset - (startOffset % this.mappedFileSize);}//如果不为空,但是最后一块mappedfile已经满了,也需要新建一块mappedfileif (mappedFileLast != null && mappedFileLast.isFull()) {createOffset = mappedFileLast.getFileFromOffset() + this.mappedFileSize;}if (createOffset != -1 && needCreate) {//新建mappedfilereturn tryCreateMappedFile(createOffset);}return mappedFileLast;}

根据代码可以看出,mappedfile其实是在tryCreateMappedFile这个方法中创建出来的。我们仔细研究一下mappedfile的创建。

2.8 mappedfile的创建

2.8.1 mappedfile的创建分析

创建其实分成两种形式,一是同步创建,即直接调用new方法创建mappedfile文件,另一种是调用allocateMappedFileService进行异步创建。

 public MappedFile tryCreateMappedFile(long createOffset) {String nextFilePath = this.storePath + File.separator + UtilAll.offset2FileName(createOffset);String nextNextFilePath = this.storePath + File.separator + UtilAll.offset2FileName(createOffset+ this.mappedFileSize);return doCreateMappedFile(nextFilePath, nextNextFilePath);}protected MappedFile doCreateMappedFile(String nextFilePath, String nextNextFilePath) {MappedFile mappedFile = null;//创建包含两种形式:一是直接创建 二是交给allocateMappedFileService进行异步创建。if (this.allocateMappedFileService != null) {//可以看出本质上还是调用的allocateMappedFileService的putRequestAndReturnMappedFile方法来进行创建的,并且创建的时候会//创建两个mappedfile,其实预热的思想,在mappedfile的基础上会创建两个mappedfile文件mappedFile = this.allocateMappedFileService.putRequestAndReturnMappedFile(nextFilePath,nextNextFilePath, this.mappedFileSize);} else {try {mappedFile = new DefaultMappedFile(nextFilePath, this.mappedFileSize);} catch (IOException e) {log.error("create mappedFile exception", e);}}if (mappedFile != null) {if (this.mappedFiles.isEmpty()) {mappedFile.setFirstCreateInQueue(true);}//将创建结果加入到mqppedqueu中this.mappedFiles.add(mappedFile);}return mappedFile;}

2.8.2 mappedfile异步创建服务-AllocateMappedFileService

其核心就是将分配请求加入到一个队列中,然后启动线程来进行消费并且分配mappedfile。

1.基本组成
public class AllocateMappedFileService extends ServiceThread {private static final Logger log = LoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME);private static int waitTimeOut = 1000 * 5;//存储mappedfile分配请求的queueprivate ConcurrentMap<String, AllocateRequest> requestTable =new ConcurrentHashMap<>();private PriorityBlockingQueue<AllocateRequest> requestQueue =new PriorityBlockingQueue<>();private volatile boolean hasException = false;private DefaultMessageStore messageStore;
}
2.如何进行分配的
   public void run() {log.info(this.getServiceName() + " service started");while (!this.isStopped() && this.mmapOperation()) {}log.info(this.getServiceName() + " service end");}
  private boolean mmapOperation() {boolean isSuccess = false;AllocateRequest req = null;try {//取出分配mappedfile的请求req = this.requestQueue.take();AllocateRequest expectedRequest = this.requestTable.get(req.getFilePath());if (null == expectedRequest) {log.warn("this mmap request expired, maybe cause timeout " + req.getFilePath() + " "+ req.getFileSize());return true;}if (expectedRequest != req) {log.warn("never expected here,  maybe cause timeout " + req.getFilePath() + " "+ req.getFileSize() + ", req:" + req + ", expectedRequest:" + expectedRequest);return true;}if (req.getMappedFile() == null) {long beginTime = System.currentTimeMillis();MappedFile mappedFile;//判断是否开启了瞬时存储技术if (messageStore.isTransientStorePoolEnable()) {try {mappedFile = ServiceLoader.load(MappedFile.class).iterator().next();//如果开启了瞬时存储技术,调用mappedflile中支持瞬时存储技术的init方法mappedFile.init(req.getFilePath(), req.getFileSize(), messageStore.getTransientStorePool());} catch (RuntimeException e) {log.warn("Use default implementation.");mappedFile = new DefaultMappedFile(req.getFilePath(), req.getFileSize(), messageStore.getTransientStorePool());}} else {//如果没有开启,便调用mappedflile中不支持瞬时存储技术的init方法mappedFile = new DefaultMappedFile(req.getFilePath(), req.getFileSize());}long elapsedTime = UtilAll.computeElapsedTimeMilliseconds(beginTime);if (elapsedTime > 10) {int queueSize = this.requestQueue.size();log.warn("create mappedFile spent time(ms) " + elapsedTime + " queue size " + queueSize+ " " + req.getFilePath() + " " + req.getFileSize());}// pre write mappedFile//进行mappedfile的预热if (mappedFile.getFileSize() >= this.messageStore.getMessageStoreConfig().getMappedFileSizeCommitLog()&&this.messageStore.getMessageStoreConfig().isWarmMapedFileEnable()) {mappedFile.warmMappedFile(this.messageStore.getMessageStoreConfig().getFlushDiskType(),this.messageStore.getMessageStoreConfig().getFlushLeastPagesWhenWarmMapedFile());}req.setMappedFile(mappedFile);this.hasException = false;isSuccess = true;}}
}

可以看出AllocateMappedFileService本质上就是调用mappedfile的init方法,来对mappedfile的构造和初始化。

2.9 flush mappedfile

即找到上次flsuh的位置,调用mappedfile的flush方法,将mappedbytebuffer中的文件flush到磁盘中去。

    //将mappedfile flush到磁盘中去public boolean flush(final int flushLeastPages) {boolean result = true;//找到上一次flush的位置MappedFile mappedFile = this.findMappedFileByOffset(this.getFlushedWhere(), this.getFlushedWhere() == 0);if (mappedFile != null) {long tmpTimeStamp = mappedFile.getStoreTimestamp();//调用flush方法刷新磁盘文件int offset = mappedFile.flush(flushLeastPages);long where = mappedFile.getFileFromOffset() + offset;result = where == this.getFlushedWhere();this.setFlushedWhere(where);if (0 == flushLeastPages) {this.setStoreTimestamp(tmpTimeStamp);}}return result;}

2.10 commit mappedfile

 public synchronized boolean commit(final int commitLeastPages) {boolean result = true;//找到上一次commit的位置MappedFile mappedFile = this.findMappedFileByOffset(this.getCommittedWhere(), this.getCommittedWhere() == 0);if (mappedFile != null) {//调用mappedfile的commit方法commitint offset = mappedFile.commit(commitLeastPages);long where = mappedFile.getFileFromOffset() + offset;result = where == this.getCommittedWhere();this.setCommittedWhere(where);}return result;}

2.11 根据offset返回所在的mappedfile

//返回对应offset在的那个mappedfilepublic MappedFile findMappedFileByOffset(final long offset, final boolean returnFirstOnNotFound) {try {MappedFile firstMappedFile = this.getFirstMappedFile();MappedFile lastMappedFile = this.getLastMappedFile();if (firstMappedFile != null && lastMappedFile != null) {if (offset < firstMappedFile.getFileFromOffset() || offset >= lastMappedFile.getFileFromOffset() + this.mappedFileSize) {LOG_ERROR.warn("Offset not matched. Request offset: {}, firstOffset: {}, lastOffset: {}, mappedFileSize: {}, mappedFiles count: {}",offset,firstMappedFile.getFileFromOffset(),lastMappedFile.getFileFromOffset() + this.mappedFileSize,this.mappedFileSize,this.mappedFiles.size());} else {int index = (int) ((offset / this.mappedFileSize) - (firstMappedFile.getFileFromOffset() / this.mappedFileSize));MappedFile targetFile = null;try {targetFile = this.mappedFiles.get(index);} catch (Exception ignored) {}if (targetFile != null && offset >= targetFile.getFileFromOffset()&& offset < targetFile.getFileFromOffset() + this.mappedFileSize) {return targetFile;}for (MappedFile tmpMappedFile : this.mappedFiles) {if (offset >= tmpMappedFile.getFileFromOffset()&& offset < tmpMappedFile.getFileFromOffset() + this.mappedFileSize) {return tmpMappedFile;}}}if (returnFirstOnNotFound) {return firstMappedFile;}}} catch (Exception e) {log.error("findMappedFileByOffset Exception", e);}return null;}

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

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

相关文章

git下载路径

第一步 1进入官网&#xff1a;Git - Downloading Package 第二步 根据自己的系统选择对应版本下载

局域网内怎么访问另一台电脑?(2种方法)

案例&#xff1a;需要在局域网内远程电脑 “当我使用笔记本电脑时&#xff0c;有时需要获取保存在台式机上的文件&#xff0c;而两者都连接在同一个局域网上。我的台式机使用的是Windows 10企业版&#xff0c;而笔记本电脑则是Windows 10专业版。我想知道是否可以通过网络远程…

OpenCV计算形状之间的相似度ShapeContextDistanceExtractor类的使用

操作系统&#xff1a;ubuntu22.04OpenCV版本&#xff1a;OpenCV4.9IDE:Visual Studio Code编程语言&#xff1a;C11 1.功能描述 ShapeContextDistanceExtractor是OpenCV库中的一个类&#xff0c;主要用于计算形状之间的相似度或距离。它是基于形状上下文&#xff08;Shape Co…

26.1 WEB框架介绍

1. Web应用程序 1.1 应用程序有两种模式 应用程序的架构模式主要分为两种: C/S (客户端/服务器端)和B/S(浏览器/服务器端). * 1. C/S模式, 即客户端/服务器模式(Client/Server Model): 是一种分布式计算模式.它将应用程序的功能划分为客户端和服务器端两部分.在这种模式下, 客…

码住!详解时序数据库不同分类与性能对比

加速发展中的时序数据库&#xff0c;基于不同架构&#xff0c;最流行的类别是&#xff1f; 作为管理工业场景时序数据的新兴数据库品类&#xff0c;时序数据库凭借着对海量时序数据的高效存储、高可扩展性、时序分析计算等特性&#xff0c;一跃成为物联网时代工业领域颇受欢迎的…

C++升级软件时删除老版本软件的桌面快捷方式(附源码)

删除桌面快捷方式其实是删除桌面上的快捷方式文件,那我们如何去删除桌面快捷方式文件呢?软件可能已经发布过多个版本,其中的一些版本的快捷方式文件名称可能做了多次改动,程序中不可能记录每个版本的快捷方式名称,没法直接去删除快捷方式文件。本文就给出一种有效的处理办…

【GO-OpenCV】go-cv快速配置

最近对golang实现目标检测心血来潮&#xff0c;尝试在没有sudo权限的平台配置go-cv,有所发现&#xff0c;索性多个平台都做尝试 安装Go语言&#xff08;Golang&#xff09; 通过包管理器安装&#xff08;适用于Debian/Ubuntu&#xff09;(有点慢) 更新包列表&#xff1a; sud…

Linux命令2

文章目录 移动文件或目录mv格式 查找命令/文件存放位目录置which格式 查找文件或目录find格式查找类型多个查找条件逻辑运算符 移动文件或目录 mv 将文件或者目录移动到指定的位置 如果目标的位置和源位置相同&#xff0c;相当于改名操作 跨目录移动相当于window的剪切 格式…

C++ 算法教程

归并排序 #include<iostream> using namespace std; template <class T> void Merge(T data[],int start,int mid,int end) {int len1 mid - start 1, len2 end - mid;int i, j, k;T* left new int[len1];T* right new int[len2];for (i 0; i < len1; i)…

TF-IDF(Term Frequency-Inverse Document Frequency)

TF-IDF&#xff08;Term Frequency-Inverse Document Frequency&#xff09;是一种常用于信息检索和文本挖掘的统计方法&#xff0c;用以评估一个词语对于一个文件集或一个语料库中的其中一份文件的重要程度。它的重要性随着词语在文本中出现的次数成正比增加&#xff0c;但同时…

【SOEM主站】EtherCAT主站时钟偏移补偿

在进行EtherCAT主从通讯测试时&#xff0c;比较容易在DC配置出现错误&#xff0c;特别是使用到从站DC模式时&#xff0c;有时会报同步错误&#xff0c;有时即使没报错误伺服从站运行过程中也会出现电机轴的抖动。引起同步错误其中一个原因就是主站发送数据帧时间存在较大的抖动…

Hadoop+Spark大数据技术(微课版)总复习

图1 Hadoop开发环境 图2 HDFS 图3 MapReduce 图4 HBase 图5 Scala 图6 Spark 图7 Spark RDD 图8 &#xff08;不考&#xff09; 图9 Spark SQL 图10 Spark Streaming 图11 Spark GraphX 第一章 Hadoop大数据开发环境 hadoop是什么&#xff1f; &#xff08;判断题&#…

二维数组与指针【C语言】

二维数组与指针 一维数组一维数组与指针二维数组二维数组与指针总结补充判断以下方式是否正确打印二维数组一维数组 int arr[] = {11, 22, 33, 44};arr:首地址(第一个元素的地址) 一维数组与指针 int arr[] = {11, 22, 33, 44};因为,arr表示的是首地址,等价于 int* p =…

基于springboot实现交通管理在线服务系统项目【项目源码+论文说明】

基于springboot实现交通管理在线服务系统演示 摘要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装交通管理在线服…

Linux常用操作大全(上)

Linux常用操作 文章目录 Linux常用操作一、各类小技巧**1.ctrl c 强制停止****2.ctrl d 退出或登出**3.历史命令搜索4.光标移动快捷键5.清屏6.复制Ctrlshiftc7.粘贴Ctrlshiftv 二、软件安装1.概念2.yum与apt 三、systemctl控制服务四、软链接ln五、日期时区1.date查看日期2.修…

【算法】某赛车游戏中的组合计数问题及其扩展。推导思路:层层合并

文章目录 引言所有人都能完成可能有人未完成扩展问题参考资料 引言 在某款人称赛车界原神的赛车游戏中有组队竞速赛。共有n个人&#xff0c;n为偶数&#xff0c;分为人数相等的红队和蓝队进行比赛。结果按排名得分的数组为pts&#xff0c;单调递减且均为正整数。比如pts [10,…

【LeetCode】LCR 124. 推理二叉树

题目链接&#xff1a; 题目描述&#xff1a;某二叉树的先序遍历结果记录于整数数组 preorder&#xff0c;它的中序遍历结果记录于整数数组 inorder。请根据 preorder 和 inorder 的提示构造出这棵二叉树并返回其根节点。 注意&#xff1a;preorder 和 inorder 中均不含重复数字…

Stable Diffusion3 开源!一文教你玩转 Stable Diffusion3

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备面试攻略、面试常考点等热门话题进行了深入的讨论。 汇总合集…

[C++]使用yolov10的onnx模型结合onnxruntime和bytetrack实现目标追踪

【官方框架地址】 yolov10yolov10框架&#xff1a;https://github.com/THU-MIG/yolov10 bytetrack框架&#xff1a;https://github.com/ifzhang/ByteTrack 【算法介绍】 Yolov10与ByTetrack&#xff1a;目标追踪的强大组合 Yolov10和ByTetrack是两种在目标追踪领域具有显…

OceanBase 金融项目优化案例

领导让我帮忙支持下其他项目的SQL优化工作&#xff0c;呦西&#xff0c;是收集案例的好机会。&#x1f60d; 下面SQL都是在不能远程的情况下&#xff0c;按照原SQL的逻辑等价改写完成发给现场同学验证。 案例一 慢SQL&#xff0c;4.32秒&#xff1a; SELECT MY_.*, RM FROM (SE…