<Linux内核学习>文件系统

2023-10-30

环境:Linux 0.11 / Linux 3.4.2

参考书籍:Linux内核完全剖析基于0.11内核-赵炯

一、Linux中使用文件系统的部分

1.1关于Linux中高速缓冲区的管理程序

1.2文件系统的底层通用函数(对于硬盘的读写,分配释放等,对于目录节点inode的管理,以及内存和磁盘的映射

1.3文件数据进行读写的操作模块(vfs:虚拟文件系统 硬件驱动和文件系统的关系)

1.4文件系统与其他程序接口的实现(fopen fclose等等)

二、文件系统的基本概念

对于一个硬盘设备,通常都会划分出几个盘片,每个盘片存放着一个不同的文件系统。比如下图将一个硬盘分成了4个分区,包含了4个不同的文件系统。其中主引导扇区中存放着磁盘引导程序和分区表信息(指明硬盘上的每个分区的类型)。

对于Linux0.11内核采用的文件系统是MINIX文件系统,它的分布如下图哦所示:

① 引导块:用来引导设备的,通常在上电时由BIOS自动读入运行的数据。对于非引导设备的盘引导块内容为空。

② 超级快:相当于文件系统的描述符,定义如下:

struct super_block {
    unsigned short s_ninodes;
    unsigned short s_nzones;
    unsigned short s_imap_blocks;
    unsigned short s_zmap_blocks;
    unsigned short s_firstdatazone;
    unsigned short s_log_zone_size;
    unsigned long s_max_size;
    unsigned short s_magic;
/* These are only in memory */
    struct buffer_head * s_imap[8];
    struct buffer_head * s_zmap[8];
    unsigned short s_dev;
    struct m_inode * s_isup;
    struct m_inode * s_imount;
    unsigned long s_time;
    struct task_struct * s_wait;
    unsigned char s_lock;
    unsigned char s_rd_only;
    unsigned char s_dirt;
};

s_ninode表示当前块设备的inode节点数。每个inode代表一个文件。
s_nzones表示当前块设备上以逻辑块为大小 (1KB)的逻辑块数。
s_imap_blocks与s_zmap_blocks分别表示当前块设备的inode节点位图和逻辑块位图所占用的逻辑块数。
    逻辑块位图用于描述当前设备每个磁盘块的使用情况。如果为0,表示对应的磁盘块是空闲的,可以分配使用。当一个磁盘块被分配占用后,对应的逻辑块位图的比特位被置1
    根据超级块数据结构中定义,s_zmap是一个数组,它占用了8块磁盘块大小,每个块大小 是1024字节,因此总共可以管理8192*8个比特位,每个比特位分别对应一个数据磁盘块,总计这8个磁盘块大小可以管理655356数据磁盘块。
    inode节点位图是用来标记iNode节点的使用情况。与逻辑块位图 类似,当创建一个文件时候,我们分配一个iNode数据结构,并且些iNode实例对应的inode位图数组对应的位需要被置1。

s_firstdatazones表示当前块设备上数据区开始位置占用的第一个逻辑块的块号。
s_max_size表示当前块设备上,以字节为单位的最大文件 的长度。
s_magic表示文件系统的魔数,标示了文件系统的类型。

④ i节点位图:类似逻辑块位图。

③ 逻辑块位图:每一位对应于逻辑块的使用情况,如果对应逻辑块使用了,则逻辑块位图的位置1.

⑤ i节点:是目录与磁盘的桥接, 文件的属性描述。

⑥ 逻辑块:用来存储数据的逻辑单元。

对于i节点定义在文件/include/linux/fs.h中,如下所示:

struct m_inode {
    unsigned short i_mode;    //文件的类型和属性
    unsigned short i_uid;    //宿主用户id
    unsigned long i_size;    //文件的大小
    unsigned long i_mtime;    //文件的修改时间
    unsigned char i_gid;    //用户组id
    unsigned char i_nlinks;    //硬链接数
    unsigned short i_zone[9];    //表示文件和磁盘的映射关系
//i_zone[6]如果你的文件大小只只用了7个逻辑块大小以内,那么这个数组每一个单源存储了一个逻辑块号
//i_zone[7]一次间接块号,如果占用的逻辑块大小大于7,小于512+7则占用一次逻辑块号
//i_zone[8]二次间接块号, 如果占用的逻辑块大小大于512 + 7,小于512 * 512 + 7则启动二次逻辑块号

/* these are in memory also */
    struct task_struct * i_wait;
    unsigned long i_atime;
    unsigned long i_ctime;
    unsigned short i_dev;
    unsigned short i_num;
    unsigned short i_count;
    unsigned char i_lock;
    unsigned char i_dirt;
    unsigned char i_pipe;
    unsigned char i_mount;
    unsigned char i_seek;
    unsigned char i_update;
};

i_mode是一个us类型的变量,用来保存文件的类型和属性,具体定义如下所示:

1、高速缓冲区(buffer.c)

高速缓冲区是文件系统访问块设备数据的桥梁也是必经之道。如果内核对块设备进行数据读写,每次读写的I/O操作的时间与cpu自身的处理速度相比是非常慢的。因此内核会在内存中开辟一块高速缓冲区,并将其分成一个个与磁盘数据块大小相同的缓冲块进行管理。

在高速缓冲区中会存放着最近使用过的块设备中的数据块。当内核需要读取块设备上的数据块的时候,会先在高速缓冲区进行查找,如果相应数据已经在缓冲中,就无需从块设备上读。如果数据不在缓冲区中,就会发出读块设备的命令,将数据读到高速缓冲区中。当需要把数据写到块设备中时,内核会在高速缓冲区中申请一块空闲缓冲块临时存放这些数据,当执行设备数据同步命令的时候,才会真正的写入到块设备之中。

高速缓冲区的结构如下图所示:

对于linux 0.11内核,每个缓冲块的大小都是1024字节,与磁盘上的逻辑块大小相同。缓冲头结构的定义在文件/include/linux/fs.h中

struct buffer_head {
    char * b_data;            //指向缓冲块的指针
    unsigned long b_blocknr;    //块号
    unsigned short b_dev;        //数据源的设备号(0==free)
    unsigned char b_uptodate;    //表示数据是否被更新
    unsigned char b_dirt;        //0-未修改,1-已修改
    unsigned char b_count;        //使用该数据块的用户数
    unsigned char b_lock;        //缓冲区是否被锁定
    struct task_struct * b_wait;    //如果缓冲区被锁定,有新的进程想访问该数据块就会加入此链表
    struct buffer_head * b_prev;    //hash队列前一块
    struct buffer_head * b_next;    //hash队列后一块
    struct buffer_head * b_prev_free;    //空闲表上前一块
    struct buffer_head * b_next_free;    //空闲表上后一块
};

缓冲区的维护依靠的是一个hash列表和一个free_list空闲列表。在buffer.c程序中定义了一个有307个buffer_head指针的hash数组。hash数组的hash函数是由(设备号^逻辑块号)% 307得到。

在buffer_head中定义的b_prev和b_next指针就是用于散列在同一个hash表项时用于双向链接的。而b_prev_free和b_next_free指针就是用于维护一个所有缓冲块的双向链表。

某一时刻的hash表和free_list状态如下图所示:

内核程序在使用高速缓冲区的缓冲块时,需要指定设备号(dev)和访问设备数据的逻辑块号(block),然后调用函数bread()、bread_page()和breada()操作,这三个函数的本质都是调用缓冲区搜索函数getblk()来搜索缓冲块中最为空闲的缓冲块。

getblk()函数代码如下:

//用来判断缓冲区的修改和锁定标志
#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)

//传入参数dev和block
struct buffer_head * getblk(int dev,int block)
{
    struct buffer_head * tmp, * bh;

repeat:
    if (bh = get_hash_table(dev,block))    //搜索哈希表,如果对应缓冲块已经存在在哈希表中,直接返回该指针。
        return bh;
    //tmp指向空闲队列
    tmp = free_list;
    do {
        //如果缓冲区的b_count不等于0表示在使用,直接跳过
        //即使一个缓冲区的b_count=0也不一定是未使用过。
        //比如一个进程执行breada()函数读取几个块,在执行完ll_rw_block()命令后就会释放b_count,但此时读取的操作还在进行,因此b_count=0,b_lock=1.
        if (tmp->b_count)
            continue;
        //找到一个BADNESS值最小的缓冲区
        if (!bh || BADNESS(tmp)<BADNESS(bh)) {
            bh = tmp;
            if (!BADNESS(tmp))
                break;
        }
/* and repeat until we find something good */
    } while ((tmp = tmp->b_next_free) != free_list);
    //如果所有的缓冲区都被使用,则进入睡眠状态等待唤醒。
    if (!bh) {
        sleep_on(&buffer_wait);
        goto repeat;
    }
    //此时已经找到了一个BADNESS最小的缓冲块,等待该缓冲区解锁
    wait_on_buffer(bh);
    //解锁完后如果由被占用则重复
    if (bh->b_count)
        goto repeat;
    //如果缓冲区已经被修改,先进行数据同步。
    while (bh->b_dirt) {
        sync_dev(bh->b_dev);
        wait_on_buffer(bh);
        if (bh->b_count)
            goto repeat;
    }
/* NOTE!! While we slept waiting for this block, somebody else might */
/* already have added "this" block to the cache. check it */
    //在本进程睡眠的过程中,其他进程有可能吧该数据块加入到哈希表中,因此需要先寻找判断。
    if (find_buffer(dev,block))
        goto repeat;
/* OK, FINALLY we know that this buffer is the only one of it's kind, */
/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */
    //最后得到的缓冲块b_count=0,b_dirt=0,b_uptodate=0,
    //因此需要占用该缓冲块
    bh->b_count=1;
    bh->b_dirt=0;
    bh->b_uptodate=0;
    //从哈希列表和空闲队列移除,指定新的设备号和块号,再插入
    remove_from_queues(bh);
    bh->b_dev=dev;
    bh->b_blocknr=block;
    insert_into_queues(bh);
    return bh;
}

2、文件系统底层操作函数(super.c,bitmap.c,truncate.c,inode.c和namei.c)

bitmap.c

free_block(int dev, int block)

释放设备dev上数据区的逻辑块block,复位逻辑块block对应的逻辑块位图比特位

new_block(int dev)

向设备申请一个逻辑块,该函数会在获取该其超级块,并在超级块中的逻辑位图寻找第一个值为0的bit,然后在对应逻辑块位图置位该bit。为该逻辑块取得在高速缓冲区取得一个对应缓冲块,并更新标志,最后返回逻辑块号。

free_inode(struct m_inode* inode)

释放指定inode节点

new_inode(int dev)

为指定设备创建一个Inode节点

truncate.c

truncate(struct m_inode* inode)

将节点对应的文件长度截为0,主要调用free_ind和free_dind释放一次和二次间接块。

inode.c

wait_on_inode(struct m_inode * inode)

等待一个inode节点空闲

lock_inode(struct m_inode * inode)

锁定一个inode节点

unlock_inode(struct m_inode * inode)

解锁一个inode节点,并唤醒等待队列

invalidate_inodes(int dev)

扫描inode表数组,如果是指定设备使用的i节点就释放

sync_inodes(void)

把i节点表上的所有节点写入到高速缓冲区等待同步

bmap

文件数据块映射到盘块的处理操作,该函数把指定的文件数据块block对应到设备上逻辑块上,并返回逻辑块号。如果创建标志 置位,则在设备上对应逻辑块不存在时就申请新磁盘块,返回文件数据块block对应在设备上的逻辑块号(盘块号)。

iput、iget

iput 释放一个inode节点。

主要是对i_count引用次数进行操作,把i节点引用数值减1并且若是管道i节点,则唤醒等待进程若是块设备文件i节点则刷新设备若i节点的链接计数为0,则释放该i节点占用的所有磁盘逻辑块,并释放该节点

iget 获得一个inode节点。

从设备上读取指定节点号的i节点到内存i节点表中,并返回该i节点指针首先在位于高速缓冲区的i节点表中寻找,若找到指定节点号的i节点则再经过一些判断处理后返回i节点指针否则通过设备号和指定i节点号,从设备中读取的i节点信息,放入在i节点表中申请的空闲节点中,并返回该i节点指针

read_inode write_inode

找到指定的设备,通过设备号找到他的超级块,超级块计算要读写的块号,调用bread将其读写入高速缓冲区中,读的话将高速缓冲区的b_data读到内存,释放高速缓冲区。写的话将数据写到高速缓冲区的b_data并设置dirt置位,等待系统sys_sync进行写盘,释放高速缓冲区。

super.c

此文件中主要存放这对文件系统超级块的管理函数。

get_super()函数在指定了设备号的情况下,返回对应的超级块的指针

put_super()函数用于释放超级块,在调用函数umount()函数的会调用此函数

read_super()函数用于把指定设备的文件系统超级块读入缓冲区,并登记到超级块数组,最后返回该超级块的指针

sys_umount()系统调用用于卸载一个设备文件名的文件系统

sys_mount()用于往一个目录上挂载一个文件系统

mount_root()用于挂载根文件系统

namei.c

实现了根据目录名或文件名寻找对应i节点的函数namei(),以及关于目录的建立和删除、目录项的建立和删除等操作和系统调用

3、文件数据进行读写的操作模块

本部分是文件系统的第三个部分,主要包含对块设备,字符设备,管道文件,普通文件的读写函数(用作给系统调用提供读写接口)以及系统调用sys_read()和sys_write()。关系如下图所示:

block_dev.c

block_write(int dev, long *pos, char *buf, int count)

int block_write(int dev, long * pos, char * buf, int count)
{
    int block = *pos >> BLOCK_SIZE_BITS;
    int offset = *pos & (BLOCK_SIZE-1);
    int chars;
    int written = 0;
    struct buffer_head * bh;
    register char * p;

    while (count>0) {
        chars = BLOCK_SIZE - offset;
        if (chars > count)
            chars=count;
        if (chars == BLOCK_SIZE)
            bh = getblk(dev,block);
        else
            bh = breada(dev,block,block+1,block+2,-1);
        block++;
        if (!bh)
            return written?written:-EIO;
        p = offset + bh->b_data;
        offset = 0;
        *pos += chars;
        written += chars;
        count -= chars;
        while (chars-->0)
            *(p++) = get_fs_byte(buf++);
        bh->b_dirt = 1;
        brelse(bh);
    }
    return written;
}

数据块写函数,向指定设备dev的偏移量pos处,从buf缓冲区开始写入count字节的数据。返回成功写入的字节数。

写数据流程:

① 根据偏移量pos会计算出开始写的盘号block,和在第一个数据块中的偏移量offset。

② 针对要写入的字节数count开始循环进行写操作。

2.1首先计算当前数据块剩余可写入数据的大小chars。如果剩余大小chars大于需要写入的数据count,则chars = count。

2.2 如果剩余可写入数据大小为一块数据的内容,则直接申请1块高速缓冲块。

2.3 否则就需要读入将被写入的数据的数据块,并预读取下两块数据,然后将块号递增1,为循环写入做准备。

block_read(int dev, unsigned long *pos, char *buf, int count)

数据块读函数,从指定设备dev的pos处读取数据,和write函数流程类似。

file_dev.c

提供普通文件的读写函数,供系统调用read()和write()使用

file_read(struct m_inode * inode, struct file * filp, char * buf, int count)

int file_read(struct m_inode * inode, struct file * filp, char * buf, int count)
{
    int left,chars,nr;
    struct buffer_head * bh;

    if ((left=count)<=0)
        return 0;
    while (left) {
        if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) {
            if (!(bh=bread(inode->i_dev,nr)))
                break;
        } else
            bh = NULL;
        nr = filp->f_pos % BLOCK_SIZE;
        chars = MIN( BLOCK_SIZE-nr , left );
        filp->f_pos += chars;
        left -= chars;
        if (bh) {
            char * p = nr + bh->b_data;
            while (chars-->0)
                put_fs_byte(*(p++),buf++);
            brelse(bh);
        } else {
            while (chars-->0)
                put_fs_byte(0,buf++);
        }
    }
    inode->i_atime = CURRENT_TIME;
    return (count-left)?(count-left):-ERROR;
}

file文件读数据流程:

① 若要读取的字节数count <= 0直接返回,否则用left保存要读取的字节数开始循环读取。

② 利用bmap()函数获取该文件的读写指针所在位置的逻辑块号nr,若nr!=0则读取该逻辑块,若nr=0表示数据块不存在,缓冲块bh指向空。

③ 计算读写指针在该逻辑块中的偏移量nr,将该数据块剩余的数据BLOCK_SIZE-nr和剩余需要读取字节数left进行比较,如果BLOCK_SIZE-nr > left表示该快是最后一个数据块,反之还需要读取下一个数据块,调整文件指针后移。

file_write(struct m_inode * inode, struct file * filp, char * buf, int count)

和读函数类似

pipe.c

管道文件是多进程通信进行数据交互的一种基本方式,在本文件中提供了read_pipe(),write_pipe()同时实现了系统调用sys_pipe()。

在创建管道的时候,程序会专门申请一个管道i节点,并为管道分配一页缓冲区(4kb),i节点的i_size字段保存着管道缓冲区地址,管道数据头指针存放在i_zone[0]字段中,管道数据尾指针存放在i_zone[1]指针中,如下图所示:

char_dev.c

该文件包含字符设备的访问函数。主要包含rw_ttyx()串口中端设备读写函数,rw_tty()控制台终端读写函数,rw_memory()内存设备读写函数。以及rw_char()字符设备读写接口函数。

4.文件系统操作和管理部分

....

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

<Linux内核学习>文件系统 的相关文章

  • 在 vimrc 中切换匹配

    我的 vimrc 文件中有以下几行 hi ExtraWhitespace cterm NONE ctermbg green ctermfg green guibg green guifg green match ExtraWhitespac
  • 无法连接到 Azure Ubuntu VM - 公钥被拒绝

    我们在 Azure 上使用 Ubuntu VM 一段时间了 很少遇到任何问题 然而 其中一台虚拟机最近出现了问题 出乎意料的是 Ubuntu VM 开始拒绝公钥 ssh i azure key email protected cdn cgi
  • 有没有办法提高linux管道的性能?

    我正在尝试使用 64 位将超高速数据从一个应用程序传输到另一个应用程序CentOS http en wikipedia org wiki CentOS6 我使用以下方法进行了基准测试dd发现阻碍我的是管道而不是程序中的算法 我的目标是达到
  • BeagleBone Black 如何用作大容量存储设备?

    是否可以使用 BB 作为大容量存储设备 我希望将其连接到可以从 USB 连接 例如 USB 闪存驱动器 读取文件的音频播放器并充当包含一个特定文件夹的数据存储设备 及其子文件夹 从文件系统 如果可能 在连接到开发板的闪存驱动器上 正如设备规
  • 使用 Python 将阿拉伯语或任何从右到左书写系统的字符串打印到 Linux 终端

    非常简单的例子是 city print city 我期望输出是 但实际上输出是相反的字符串 字母看起来有点不同 因为它们有开始 中间和结束形式 我无法将其粘贴到此处 因为复制粘贴会再次更正字符串的顺序 如何在 Linux 终端上正确打印阿拉
  • 打印 STDOUT/STDERR 并将它们写入 Bash 中的文件?

    有没有办法让 Bash 将 STDOUT STDERR 重定向到文件 但仍然将它们打印到终端 这会将 STDOUT 和 STDERR 重定向到同一个文件 some command 2 gt 1 tee file log Example to
  • 使用 .htaccess 启用 PHP 短标签

    我在自己的 Centos 服务器上设置了 Apache 并具有多个虚拟 Web 服务器 并且我希望仅为位于以下位置的其中一个 Web 服务器启用 PHP 短标记 var www ostickets html 我可以通过添加成功启用短标签sh
  • PHP mail() 函数不发送邮件

    我有一个小问题 我正在使用一个工作脚本 在我的测试帐户 共享服务器上工作 使用 mail 函数通过 PHP 发送邮件 我刚刚得到了一个专用服务器 但我还无法让该功能发挥作用 在过去的 10 个小时左右的时间里 我阅读了有关 BIND 用于
  • 如何在C程序中直接改变显存映射来绘制像素(无需库函数)

    是否可以通过使用 C 程序更改 RAM 中屏幕 视频即监视器 内存映射中的值来显示黑点 我不想使用任何库函数 因为我的主要目标是学习如何开发简单的操作系统 我尝试访问起始屏幕内存映射 即 0xA0000 在 C 中 我尝试运行该程序 但由于
  • sudo pip install python-Levenshtein 失败,错误代码 1

    我正在尝试在 Linux 上安装 python Levenshtein 库 但每当我尝试通过以下方式安装它时 sudo pip install python Levenshtein 我收到此错误 命令 usr bin python c 导入
  • 如何从 Linux 命令行确定 LCD 显示器是否打开

    如何通过 Linux 命令行判断计算机的显示器是否打开 关闭 我传统上认为显示器是仅输出的设备 但我注意到 Gnome 显示器首选项对话框具有 检测显示器 功能 这可以推广到确定显示器是否物理关闭吗 VESA DDC 连接是I2C http
  • %config(noreplace) 文件上出现意外的 RPM 冲突

    我正在创建我自己的RPM using rpmbuild My RPM 包含配置文件哪个应该永远不会被覆盖 即使 RPM 包含这些配置文件的新版本 为了存档这个 我用以下标签标记了它们 config noreplace opt mypacka
  • C# - OPC-UA 服务器应用程序尚未在 Linux 计算机中创建 PKI 证书

    当我跑步时OPC UA serverWindows 机器中的 C 应用程序 然后 OPC UA 服务器已创建证书路径C ProgramData OPC Foundation pki own 并在此路径中生成一些证书 但是当我在中安装 OPC
  • 在Linux中将日期附加到文件名

    我想在文件名旁边添加日期 somefile txt 例如 somefile 25 11 2009 txt 或 somefile 25Nov2009 txt 或任何类似的内容 也许脚本或终端窗口中的某些命令可以执行 我正在使用Linux Ub
  • Linux mremap 不释放旧映射?

    我需要一种方法将页面从一个虚拟地址范围复制到另一个虚拟地址范围 而无需实际复制数据 范围很大 延迟很重要 mremap 可以做到这一点 但问题是它也会删除旧的映射 由于我需要在多线程环境中执行此操作 因此我需要旧映射能够同时使用 因此稍后当
  • 如何获取 bash 中从 Ping 接收到的数据包的百分比?

    当 ping 主机时 我希望输出仅显示收到的数据包 已发送 5 个 的百分比 我想我需要使用grep不知怎的 但我不知道如何 我是 bash 编程的新手 这是我所在的地方 ping c 5 q host grep grep 中应该包含什么
  • 为什么 proc/ID/maps 有多个共享库条目

    我正在查看嵌入式Linux下的proc ID maps 我注意到一些共享库在进程的内存映射中出现了几次 为什么会这样呢 40094000 400d9000 r xp 00000000 b3 09 723 system lib libc so
  • 动态加载库和共享全局符号

    由于我在动态加载的库中观察到全局变量的一些奇怪行为 因此我编写了以下测试 首先我们需要一个静态链接库 头文件test hpp ifndef BASE HPP define BASE HPP include
  • 我如何知道用户在使用 ncurses (Linux) 的控制台中按下了 ESC 键?

    I have a problem in detecting whether I just got a plain ESC key just code 27 or whether it was another special key such
  • 选择多个模式的 awk 代码

    这是我的输入文件 比如modified txt r4544 n479826 2012 08 28 07 12 33 0400 Tue 28 Aug 2012 1 line Changed paths M branches 8 6 0 con

随机推荐

  • 使用R语言绘制指数分布密度函数数据的可视化

    使用R语言绘制指数分布密度函数数据的可视化 指数分布是概率论和统计学中常见的连续概率分布之一 广泛应用于可靠性工程 风险分析和排队论等领域 在本文中 我们将使用R语言的plot函数来可视化指数分布密度函数的数据 首先 我们需要安装并加载R语
  • Pytorch并行计算(二): DistributedDataParallel介绍

    PyTorch并行计算 DistributedDataParallel 一 为什么要并行计算 二 基本概念 三 DistributedDataParallel的使用 1 torch distributed 2 torch multiproc
  • 三、Express

    目录 初识express Express 简介 Express 的基本使用 安装 基本使用 托管静态资源 express static 托管多个静态资源目录 挂载路径前缀 nodemon Express路由 路由的基本使用 为路由模块添加前
  • 使用容器搭建伪redis集群

    在一个主机上使用容器技术搭建一个redis集群 为什么说是伪集群 因为redis集群和分布式相互交叉 因为成本 在一台主机上部署一个三主三从的redis集群 redis版本 v 6 2 6 部署 运行六个节点 docker compose
  • 常见垃圾回收器

    CMS和G1是最重要的 新生代一般采用标记复制 老年代一般采用标记整理算法 Serial 垃圾回收线程只有一个 而且垃圾回收线程工作的时候其他用户线程要停下来 Parnew Serial的多线程版本 有多个垃圾回收线程 垃圾回收线程工作的时
  • 黎明觉醒火种测试服务器维护,黎明觉醒火种测试什么时候上线 黎明觉醒火种测试资格获取方式(图文)...

    黎明觉醒是腾讯旗下的多人开放世界生存手游 对标的就是网易旗下的明日之后 在之前的曙光测试之后 这款游戏长时间来都没有传出过新消息 下面game234就来介绍一下黎明觉醒最新的火种测试什么时候上线 怎么预约 game234将第一时间提供黎明觉
  • 区块链是怎么形成的,你究竟明白多少?

    区块链到底是啥 首先 不要把区块链想的很复杂 其实 区块链很简单 它本质上就是一套数据库存储系统 该系统分布在全球各地 并且能够协同运转 不过 与其他数据库存储系统不一样的是 这个系统的运行者可以是任何有能力架设服务器的人 过去 传统的数据
  • angular 12+NG-ZORRO -UI中使用Modal对话框时注意

    弹框的代码不能放在循环中不然就会出现黑屏了 当时我的代码是这样写的 当然这是我的错误写法 特此记录 div class pages div
  • 日志服务器搭建

    1 安装完系统后 配置网络 设置静态IP vi etc sysconfig network scripts ifcfg ens33 编辑模式下修改 i BOOTPROTO static 改为静态 ONBOOT YES IPADDR 192
  • DeFi新篇章

    随着原生去中心化中央限价订单簿 Central Limit Order Book CLOB DeepBook的推出 Sui上的DeFi开启了新篇章 DeepBook由一群Sui贡献者共同构建 为新一代DeFi应用提供了一个稳定的流动性层 通
  • win10无法访问smb共享文件夹的解决办法

    win10无法访问smb共享文件夹的解决办法 之前在linux的几个图形化界面都可以在文件夹中输入 smb ip share 直接访问Linux服务器上的共享文件夹 但是在win10上进行同样的操作会让我打开win10商店搜索应用程序 网上
  • java(条件分支语句)

    Java中的条件分支语句分两种 if else语句和switch语句 1 if 条件判断语句 代码A 当条件成立时执行代码A 如果条件不成立则不执行代码A 而是直接 执行if的下一句 if 条件 代码块1 else 代码块2 当条件成立时执
  • vscode git 源代码管理 无法自动更新显示变更

    最近vscode 远程写代码遇到问题 git的源代码管理不能自动罗列被修改的文件 原因 早期出现警告 Visual Studio Code is unable to watch for file changes in this large
  • 蓝牙HID说明

    蓝牙HID说明 本章主要围绕BLE的HOGH进行说明 网上很多文档讲到HID都要说到USB的HID 让初学者一开始既要看理解蓝牙GATT Service的概念 又要去理解USB的端点概念 实话来说本人刚去学习时也经常需要尝试去理解这两者的关
  • hystrix详述(2)- 配置

    一 hystrix在生产中的建议 1 保持timeout的默认值 1000ms 除非需要修改 其实通常会修改 2 保持threadpool的的线程数为10个 除非需要更多 3 依赖标准的报警和监控系统来捕获问题 4 通过dashboards
  • 快应用-华为市场快应用审核总是不通过,无法复现华为审核时的bug【经验贴】

    最近完成了一个快应用项目 在提交各个市场审核的时候 除了华为市场总是不过 其他市场 vivo oppo 小米 等 都很快通过了审核 最让人恼火的是 华为反馈的bug内容 我们尝试各种方法都无法复现 无法复现bug就很难定位修改 修改bug全
  • 微信小程序 一键授权 给第三方平台代开发管理(二,一键授权给第三方平台)

    不是重点 可以忽略 本人 七月的胜利 代表七月份我出生啦 嘻嘻 博客就是平常记录一些常用到的开发常用到的技术 方法等 看见好东西了就自己整理一下防止以后自己遇到了再找不到 如果有幸帮到你 欢迎点赞 评论 留言 Thank you 一 创建第
  • linux设置交换内存

    查看是否有交换空间 cat proc swaps free h 创建swapfile空间 sudo fallocate l 32G swapfile ls lh swapfile 设置空间权限 sudo chmod 600 swapfile
  • 如何使你的网页视频自动播放嵌入的iframe视频

    只需在视频链接后面接上 rel 0 amp autoplay 1
  • <Linux内核学习>文件系统

    环境 Linux 0 11 Linux 3 4 2 参考书籍 Linux内核完全剖析基于0 11内核 赵炯 一 Linux中使用文件系统的部分 1 1关于Linux中高速缓冲区的管理程序 1 2文件系统的底层通用函数 对于硬盘的读写 分配释