IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 阅读redis持久化RDB源码的时候一些c知识 -> 正文阅读

[大数据]阅读redis持久化RDB源码的时候一些c知识

在rdb的时候使用了fork()函数来创建子进程,详细了解下相关的知识点。

smaps

凡是程序运行过程中可能需要用到的指令或者数据都必须在虚拟内存空间中,为了让程序在物理机器上运行,必须有得让虚拟内存空间映射到物理内存空间。操作系统中页映射表(page table)就是干的这事。内核为每个一个进程维护一份相互独立的页映射表。

通过top命令我们已经能看出进程的虚拟空间大小(VIRT)、占用的物理内存(RES)以及和其他进程共享的内存(SHR)。

Linux 通过proc文件系统为每个进程都提供一个smaps文件。

smapsb包含以下字段:

  • Size: 表示该映射区域在虚拟内存空间中的大小。

  • Rss: 表示该映射区域当前在物理内存中占用了多少空间

  • Shared_Clean: 和其他进程共享的未被改写的page的大小

  • Shared_Dirty: 和其他进程共享的被改写的page的大小

  • Private_Clean: 未被改写的私有页面的大小。

  • Private_Dirty: 已被改写的私有页面的大小。

  • Swap: 表示非mmap内存(也叫anonymous memory,比如malloc动态分配出来的内存)由于物理内存不足被swap到交换空间的大小。

  • Pss: 该虚拟内存区域平摊计算后使用的物理内存大小(有些内存会和其他进程共享,例如mmap进来的)。比如该区域所映射的物理内存部分同时也被另一个进程映射了,且该部分物理内存的大小为1000KB,那么该进程分摊其中一半的内存,即Pss=500KB。

了解了smaps后,咱们接着了解下fork()

fork()

作用:fork 为子进程创建了虚拟地址空间,仍与父进程共享同样的物理空间,当父子进程某一方发生写操作时,系统才会为其分配物理空间,并复制一份副本以供其修改。

我们先了解下fork()函数。

fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值

  • 在父进程中,fork返回新创建子进程的进程ID;
  • 在子进程中,fork返回0;
  • 如果出现错误,fork返回一个负值;

所以fork()成功,以后会执行两次

  • == 0 的时候,是子进程执行
  • == 1 的时候,是父进程执行

在rdb执行的时候,有一段代码。

int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) {    pid_t childpid;    if ((childpid = fork()) == 0) {        //关闭自己不使用的父进程的资源(验证了父子进程共用一套物理存储)        closeClildUnusedResourceAfterFork();        //执行备份        retval = rdbSave(filename,rsi);        //获取子进程修改的部分大小,相当于rdb耗费的内存        size_t private_dirty = zmalloc_get_private_dirty(-1);    }else {        //主进程执行自己的逻辑    }}size_t zmalloc_get_private_dirty(long pid) {    //获取smap中的Private_Dirty,这里就是在smaps中讲解的概念    return zmalloc_get_smap_bytes_by_field("Private_Dirty:",pid);}

创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。fork 把当前进程的页映射表(page table)拷贝了一份,两个进程使用的变量虽然名字一样,但是内存地址指向的不同(最终物理地址一样)

Fork()成功后,可以通过下面的函数进行操作

  • getpid() -获取当前进程的pid

  • getppid() -获取当前进程的父进程的pid

  • 进程终止后会向父进程发送SIGCHLD信号,可以通过wait系列接收

  • wait() waitpid() waittid() 如果子进程都在在运行,则阻塞,有一个终止就返回一个,没有子进程报错返回

  • wait3 wait4 额外能获取子进程使用的资源汇总

  • WIFEXITED 子进程正常结束,则为非0值

  • WEXITSTATUS 获取子进程返回的结束代码,一般先用WIFEXITED判断是否正常结束才用这个

  • WIFSIGNALED 如果子进程是否因为信号而结束,是返回true

  • WTERMSIG 取得子进程是否因信号而中止的信号代码

  • WIFSTOPPED 获取子进程是否处于暂停执行状态

  • WSTOPSIG 获取引发子进程暂停的信号代码

pid_t wait (int * status);
/**
 * wait3 等待所有子进程,wait4指定等待子进程
 * statloc: 保存着子进程退出时的一些状态,它是一个指向int类型的指针,设置为null,直接kill掉子进程
 * options:选项
 *    WNOHANG  如果没有结束的子进程,马上返回,不等待
 *    WUNTRACED 如果子进程进入暂停执行状态,则马上返回,不理会结束状态
 *    也可以WNOHANG | WUNTRACED 没有任何已结束了的子进程或子进程进入暂停执行的状态,则马上返回不等待
 */
pid_t wait3(int *statloc, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage);

在serverCron中

   if (server.rdb_child_pid != -1 || server.aof_child_pid != -1 ||ldbPendingChildren()){
        /**
         * 获取终止的进程id
         * statloc: 保存着子进程退出时的一些状态,它是一个指向int类型的指针,设置为null,直接kill掉子进程
         * options:选项
         *    WNOHANG  如果没有结束的子进程,马上返回,不等待
         *    WUNTRACED 如果子进程进入暂停执行状态,则马上返回,不理会结束状态
         *    也可以WNOHANG | WUNTRACED 没有任何已结束了的子进程或子进程进入暂停执行的状态,则马上返回不等待
         */

        if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
            //获取子进程的结束代码
            int exitcode = WEXITSTATUS(statloc);
            int bysignal = 0;
            //如果子进程因为信号而结束,获取信号代码
            if (WIFSIGNALED(statloc)) bysignal = WTERMSIG(statloc);

         }
    }

snprintf()

作用:将一个格式化的字符串输出到一个目的字符串中

语法:

int sprintf(char *str, char * format [, argument, ...]);
  • str 要写入的字符串
  • format为格式化字符串,与printf()函数相同
  • argument为变量。

在redis持久化的时候使用案例

snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());

pipe()

作用:创建一个管道,必须在fork中调用pipe,否则子进程不会继承文件描述符,两个进程不共享祖先进程,就不能使用pipe。

int  pipe(int fd[2]);

返回值:成功,返回0,否则返回-1,参数是pipe使用的两个文件描述符。

fd[0] 对应的参数是读管道,fd[1]对应的是写管道

什么是管道? 管道是一种把两个进程之间的标准输入和标准输出连接起来的机制,从而提供一种让多个进程间通信的方法。

在rdb中

int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) {
   //创建一个pip管道,用于父子进程进行通信
    openChildInfoPipe();    
}

//在server.c中
    
if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
    //获取子进程的结束代码
    int exitcode = WEXITSTATUS(statloc);
    int bysignal = 0;
    //如果子进程因为信号而结束,获取信号代码
    if (WIFSIGNALED(statloc)) bysignal = WTERMSIG(statloc);

    if (pid == -1) {
    } else if (pid == server.rdb_child_pid) {
        //是rdb子进程,说明rdb执行完了,执行后续的事件
        backgroundSaveDoneHandler(exitcode,bysignal);
        //不是因为信号中断的,接收子进程信息
        if (!bysignal && exitcode == 0) receiveChildInfo();
    } else if (pid == server.aof_child_pid) {
        backgroundRewriteDoneHandler(exitcode,bysignal);
        if (!bysignal && exitcode == 0) receiveChildInfo();
    } else {
        //无法识别的子进程,,直接移除
        if (!ldbRemoveChild(pid)) {
            serverLog(LL_WARNING,
                      "Warning, detected child with unmatched pid: %ld",
                      (long)pid);
        }
    }
    updateDictResizePolicy();
    //关闭子进程管道
    closeChildInfoPipe();
}   

参考:

https://www.cnblogs.com/bravery/archive/2012/06/27/2560611.html

https://www.cnblogs.com/jeakon/archive/2012/05/26/2816828.html

https://www.cnblogs.com/tongye/p/9558320.html

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-03-15 22:37:16  更:2022-03-15 22:38:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:50:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码