Linux 内核中根据文件inode号获取其对应的struct inode
文章目录
- 前言
- 一、简介
- 二、iget_locked
- 2.1 简介
- 2.2 内核中使用
- 2.3 LKM demo
- 三、ext4_iget
- 3.1 简介
- 3.2 LKM demo
前言
文件inode号和struct inode结构体请参考:
Linux文件路径,目录项,inode号关联
Linux文件系统 struct inode 结构体解析
一、简介
在Linux中,每个文件和目录都与一个唯一的inode号相关联。inode号是文件系统中inode的唯一标识符,用于表示文件或目录的元数据。
这就意味inode号在文件系统中是不可以重复的。
在同一个文件系统中,文件的inode号是唯一的,不会重复。每个文件系统维护着一个独立的inode表,其中的inode号在该文件系统中是唯一的。
然而,不同文件系统之间的inode号可以重复。当不同的文件系统挂载到同一个系统上时,它们各自维护着独立的inode号空间。因此,不同文件系统中的文件可以拥有相同的inode号,但它们在各自的文件系统中是唯一的。
这意味着,如果在不同文件系统中有两个文件的inode号是相同的,那么它们实际上是不同的文件,属于不同的文件系统。
需要注意的是,文件系统的实现可能会限制inode号的范围或分配策略,具体取决于文件系统的设计和实现。
因此当涉及到多个文件系统时,不同文件系统中的inode号确实可以重复。这是因为每个文件系统都有自己的inode号空间,用于在该文件系统中唯一标识文件和目录。
当不同的文件系统挂载到同一个操作系统中时,每个文件系统会独立地管理自己的inode号。这意味着,即使两个文件系统中存在具有相同inode号的文件,它们仍然被视为不同的文件,并且彼此之间没有任何关联。
这种情况可能发生在以下情况下:
(1)多个独立的物理磁盘或分区:每个磁盘或分区上的文件系统都有自己的inode号空间,它们彼此独立。
(2)文件系统镜像:如果相同的文件系统映像被多次挂载,每次挂载都会创建一个独立的inode号空间。
(3)网络文件系统(NFS):当使用NFS挂载远程文件系统时,本地文件系统和远程文件系统的inode号彼此独立。
这种设计允许不同的文件系统在同一个操作系统中并存,并通过挂载点进行访问。每个文件系统都有自己的inode号空间,确保了在各自范围内的唯一性。
需要注意的是,尽管不同文件系统中的inode号可以重复,但通常并不鼓励依赖inode号来唯一标识文件。在跨文件系统或跨系统的环境中,使用文件路径或其他唯一标识符更可靠和可移植。
二、iget_locked
接下来介绍根据文件系统(即超级块)+ 文件inode编号来获取 struct inode结构体对象,流程图如下所示:

2.1 简介
通常前面的知识我们可以知道不同文件系统中的文件可以拥有相同的inode号,它们在各自的文件系统中是唯一的,因此我们根据在内核态编程中根据文件inode号获取其对应的struct inode结构体,那么需要明确文件系统和inode号才能获取其对应的struct inode结构体,不能单独通过inode号获取其struct inode结构体,可以使用iget_locked函数。
/*** iget_locked - obtain an inode from a mounted file system* @sb: super block of file system* @ino: inode number to get** Search for the inode specified by @ino in the inode cache and if present* return it with an increased reference count. This is for file systems* where the inode number is sufficient for unique identification of an inode.** If the inode is not in cache, allocate a new inode and return it locked,* hashed, and with the I_NEW flag set. The file system gets to fill it in* before unlocking it via unlock_new_inode().*/
struct inode *iget_locked(struct super_block *sb, unsigned long ino)
{struct hlist_head *head = inode_hashtable + hash(sb, ino);struct inode *inode;
again:spin_lock(&inode_hash_lock);inode = find_inode_fast(sb, head, ino);spin_unlock(&inode_hash_lock);if (inode) {if (IS_ERR(inode))return NULL;wait_on_inode(inode);if (unlikely(inode_unhashed(inode))) {iput(inode);goto again;}return inode;}inode = alloc_inode(sb);if (inode) {struct inode *old;spin_lock(&inode_hash_lock);/* We released the lock, so.. */old = find_inode_fast(sb, head, ino);if (!old) {inode->i_ino = ino;spin_lock(&inode->i_lock);inode->i_state = I_NEW;hlist_add_head(&inode->i_hash, head);spin_unlock(&inode->i_lock);inode_sb_list_add(inode);spin_unlock(&inode_hash_lock);/* Return the locked inode with I_NEW set, the* caller is responsible for filling in the contents*/return inode;}/** Uhhuh, somebody else created the same inode under* us. Use the old inode instead of the one we just* allocated.*/spin_unlock(&inode_hash_lock);destroy_inode(inode);if (IS_ERR(old))return NULL;inode = old;wait_on_inode(inode);if (unlikely(inode_unhashed(inode))) {iput(inode);goto again;}}return inode;
}
EXPORT_SYMBOL(iget_locked);
iget_locked 函数通常在文件系统中使用,用于从已挂载的文件系统中获取一个 inode(索引节点)。
iget_locked 函数根据inode编号和超级块快速访问inode对象,这两项的组合在系统范围内是唯一的。
该函数的实现过程如下:
首先,根据给定的 inode 号 ino 和文件系统的超级块 sb,使用 hash 函数计算哈希值。该哈希值用于定位 inode 缓存中相应的哈希表条目。
函数获取自旋锁 inode_hash_lock,以在执行必要的操作时锁定 inode 缓存。
它搜索哈希链表(由 hlist_head 指针 head 指示),以查找与给定的 inode 号 ino 相关联的 inode。它使用 find_inode_fast 函数进行搜索。
如果在缓存中找到了 inode,函数通过使用 IS_ERR 函数检查它是否是有效的 inode。如果该 inode 无效,则返回 NULL。否则,它使用 wait_on_inode 函数等待 inode 上的任何挂起操作完成。
如果发现 inode 是未哈希的(即不在哈希表中),它将释放该 inode,并回到开始处重新搜索。
如果在缓存中未找到该 inode,则继续使用 alloc_inode 函数分配一个新的 inode。这将创建一个新的 struct inode 数据结构并进行初始化。
分配完 inode 后,函数释放自旋锁,并重新获取它,以执行另一次搜索以查找该 inode。这是必要的,因为在 alloc_inode 调用期间释放了锁,而另一个线程可能在此期间将该 inode 添加到缓存中。
如果没有其他线程添加了相同 inode 号的 inode,将设置新分配的 inode 的字段。将 i_ino 字段设置为给定的 inode 号 ino,将 i_state 字段设置为 I_NEW,以表示该 inode 是新的且尚未完全初始化,然后使用 hlist_add_head 将 inode 添加到哈希表中。使用 inode_sb_list_add 将 inode 添加到超级块的 inode 列表中。
然后,释放自旋锁和 inode 缓存锁,并将带有设置了 I_NEW 标志的锁定 inode 返回给调用者。调用者负责填充 inode 的内容。
如果在自旋锁释放期间有其他线程添加了相同 inode 号的 inode,则函数选择使用现有的 inode 而不是新分配的 inode。它使用 wait_on_inode 等待现有 inode 上的任何挂起操作完成。如果现有 inode 是未哈希的,则释放它,并回到开始处重新搜索。
最后,函数将获得的 inode(无论是新分配的还是现有的)返回给调用者。
/** find_inode_fast is the fast path version of find_inode, see the comment at* iget_locked for details.*/
static struct inode *find_inode_fast(struct super_block *sb,struct hlist_head *head, unsigned long ino)
{struct inode *inode = NULL;repeat:hlist_for_each_entry(inode, head, i_hash) {if (inode->i_ino != ino)continue;if (inode->i_sb != sb)continue;spin_lock(&inode->i_lock);if (inode->i_state & (I_FREEING|I_WILL_FREE)) {__wait_on_freeing_inode(inode);goto repeat;}if (unlikely(inode->i_state & I_CREATING)) {spin_unlock(&inode->i_lock);return ERR_PTR(-ESTALE);}__iget(inode);spin_unlock(&inode->i_lock);return inode;}return NULL;
}
该函数的作用是在给定的哈希链表 head 中快速查找与给定 inode 号 ino 和超级块 sb 相匹配的 inode。
函数使用 hlist_for_each_entry 宏遍历哈希链表中的每个 inode。对于每个 inode,它首先检查 inode 号和超级块是否与给定的匹配,如果不匹配,则继续遍历下一个 inode。
如果找到匹配的 inode,函数将获取 inode 的自旋锁,然后进行一系列的检查:
● 首先,它检查 inode 的状态是否处于 I_FREEING 或 I_WILL_FREE 状态,这表示 inode 正在释放或即将被释放。如果是这种情况,函数将调用 __wait_on_freeing_inode 函数等待 inode 完全释放,然后重新从头开始查找。
● 接下来,函数检查 inode 的状态是否处于 I_CREATING 状态,这表示 inode 正在创建过程中。如果是这种情况,函数将释放 inode 的自旋锁,并返回一个指向 -ESTALE 错误的指针,表示 inode 已过期。
● 最后,如果 inode 的状态正常,函数将调用 __iget 函数增加 inode 的引用计数,然后释放 inode 的自旋锁,并返回指向该 inode 的指针。
如果在整个哈希链表中没有找到匹配的 inode,函数将返回 NULL。
这个函数用于在inode缓存中快速查找 inode,以加速文件系统中对 inode 的访问操作。
2.2 内核中使用
这个函数一般是具体的文件系统函数调用,根据文件inode号和超级块从inode缓存中获取其对应的struct inode结构体,如果没有从inode缓存中找到,那么具体的文件系统函数会调用自己的文件系统获取函数获取磁盘上的原始inode结构体,比如ext4 inode,然后用ext4 inode的值来初始化struct inode结构体对象,然后将struct inode结构体对象加入到inode高速缓存中,以便下次加速查找。
比如minix文件系统:
/** The global function to read an inode.*/
struct inode *minix_iget(struct super_block *sb, unsigned long ino)
{struct inode *inode;inode = iget_locked(sb, ino);if (!inode)return ERR_PTR(-ENOMEM);if (!(inode->i_state & I_NEW))return inode;if (INODE_VERSION(inode) == MINIX_V1)return V1_minix_iget(inode);elsereturn V2_minix_iget(inode);
}
首先调用iget_locked函数根据文件inode号和超级块从inode缓存中获取其对应的struct inode结构体,加速struct inode结构体的查找,如果没有在缓存中找到,那么便分配一个struct inode结构体结构体,调用具体文件系统的函数V1_minix_iget读取minix文件系统中的minix_inode,即磁盘上的minix inode结构体,用磁盘上的minix inode结构体成员来初始化struct inode结构体对象,将struct inode结构体对象加入到inode缓存中,以便下次加速查找。
/** The minix V1 function to read an inode.*/
static struct inode *V1_minix_iget(struct inode *inode)
{struct buffer_head * bh;struct minix_inode * raw_inode;struct minix_inode_info *minix_inode = minix_i(inode);int i;//根据超级块和inode编号从minix磁盘文件系统获取磁盘上的inode节点:minix_inoderaw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);if (!raw_inode) {iget_failed(inode);return ERR_PTR(-EIO);}//根据磁盘上的inode节点:minix_inode 来初始化 struct inode结构体对象inode->i_mode = raw_inode->i_mode;i_uid_write(inode, raw_inode->i_uid);i_gid_write(inode, raw_inode->i_gid);set_nlink(inode, raw_inode->i_nlinks);inode->i_size = raw_inode->i_size;inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = raw_inode->i_time;inode->i_mtime.tv_nsec = 0;inode->i_atime.tv_nsec = 0;inode->i_ctime.tv_nsec = 0;inode->i_blocks = 0;for (i = 0; i < 9; i++)minix_inode->u.i1_data[i] = raw_inode->i_zone[i];minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0]));brelse(bh);unlock_new_inode(inode);return inode;
}
这段代码是用于在Minix V1文件系统中读取一个inode的函数。
函数解析:
调用"minix_V1_raw_inode"函数,通过给定的super_block、inode号以及一个用于传递缓冲区头指针的指针,获取Minix V1版本的原始inode结构:minix_inode。
将获取的原始inode结构:minix_inode中的字段赋值给目标inode结构。这包括inode的模式(i_mode)、用户ID(i_uid)、组ID(i_gid)、链接数(i_nlinks)、文件大小(i_size)、修改时间(i_mtime)、访问时间(i_atime)、创建时间(i_ctime)等。
将原始inode结构:minix_inode中的数据块地址赋值给目标inode结构的数据块地址。在Minix V1文件系统中,数据块地址存储在minix_inode结构的u.i1_data数组中。
使用"minix_set_inode"函数将目标inode结构中的设备号设置为原始inode结构中的第一个数据块地址。
返回struct inode结构体对象。
比如ext2文件系统:
struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
{struct ext2_inode_info *ei;struct buffer_head * bh = NULL;struct ext2_inode *raw_inode;struct inode *inode;long ret = -EIO;int n;uid_t i_uid;gid_t i_gid;inode = iget_locked(sb, ino);if (!inode)return ERR_PTR(-ENOMEM);if (!(inode->i_state & I_NEW))return inode;ei = EXT2_I(inode);ei->i_block_alloc_info = NULL;raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);if (IS_ERR(raw_inode)) {ret = PTR_ERR(raw_inode);goto bad_inode;}inode->i_mode = le16_to_cpu(raw_inode->i_mode);i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);if (!(test_opt (inode->i_sb, NO_UID32))) {i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;}i_uid_write(inode, i_uid);i_gid_write(inode, i_gid);set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));inode->i_size = le32_to_cpu(raw_inode->i_size);inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime);inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 0;......
}
2.3 LKM demo
接下来我们给出一个LKM示例根据inode号来获取对应的struct inode结构体:
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>#include <linux/fs.h>
#include <linux/fs_struct.h>/* Module parameter */
static unsigned long ino = 1837047;module_param(ino, ulong, 0);static int __init hello_init(void)
{struct fs_struct *fs;struct path pwd;//unsigned long ino = 1837047;struct inode *inode;struct super_block *sb;fs = current->fs;get_fs_pwd(fs, &pwd);/* The root of the dentry tree */sb = pwd.dentry->d_sb;//从inode 缓存中查找 struct inode 对象inode = iget_locked(sb, ino);if(inode)printk("inode num = %ld\n", inode->i_ino);return -1;
}module_init(hello_init);MODULE_LICENSE("GPL");
ls -il 3.txt
1837252# insmod hello.ko ino=1837252
insmod: ERROR: could not insert module hello.ko: Operation not permitted# dmesg -c
inode num = 1837252
这只是从inode缓存中查找struct inode,如果inode缓存中没有,那么便要去磁盘中查找对应的磁盘inode结构体。
三、ext4_iget
3.1 简介
我们简单看一下ext4文件系统根据inode号获取其struct inode结构体的方式:
// linux-5.4.18/fs/ext4/ext4.htypedef enum {EXT4_IGET_NORMAL = 0,EXT4_IGET_SPECIAL = 0x0001, /* OK to iget a system inode */EXT4_IGET_HANDLE = 0x0002 /* Inode # is from a handle */
} ext4_iget_flags;extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,ext4_iget_flags flags, const char *function,unsigned int line);#define ext4_iget(sb, ino, flags) \__ext4_iget((sb), (ino), (flags), __func__, __LINE__)
ext4文件系统通过ext4_iget宏来获取struct inode结构体,宏定义 ext4_iget调用 __ext4_iget 函数来获取指定inode号对应的 struct inode 结构体。
该宏定义接受三个参数:
sb:指向 super_block 结构体的指针,表示要操作的超级块。
ino:表示要获取的inode号。
flags:表示 ext4_iget_flags 类型的标志位,用于指定 __ext4_iget 函数的行为。
宏定义将参数传递给 __ext4_iget 函数,并在最后两个参数 func 和 LINE 中传递了调用该宏的函数名和行号。这些信息通常用于调试目的,以便在发生错误时能够追踪到具体的调用位置。
对于第三个参数flags:
typedef enum {EXT4_IGET_NORMAL = 0,EXT4_IGET_SPECIAL = 0x0001, /* OK to iget a system inode */EXT4_IGET_HANDLE = 0x0002 /* Inode # is from a handle */
} ext4_iget_flags;
枚举类型 ext4_iget_flags,用于表示 ext4_iget 函数的标志或选项。
ext4_iget_flags 枚举类型包含三个成员:
EXT4_IGET_NORMAL:表示普通的 iget 操作。它用于指示 iget 函数应该获取普通文件或目录的 inode。
EXT4_IGET_SPECIAL:表示可以 iget 系统级 inode。系统级 inode 是用于各种系统级操作或文件类型(如超级块或日志文件)的特殊目的 inode。
EXT4_IGET_HANDLE:用于当 inode 号是从一个句柄(handle)中获取时。句柄是用于跨文件系统和进程访问 inode 的标识符,通常用于实现文件系统的高级功能。
struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,ext4_iget_flags flags, const char *function,unsigned int line)
{struct ext4_iloc iloc;struct ext4_inode *raw_inode;struct ext4_inode_info *ei;struct inode *inode;journal_t *journal = EXT4_SB(sb)->s_journal;long ret;loff_t size;int block;uid_t i_uid;gid_t i_gid;projid_t i_projid;......//从inode高速缓存中查找struct inodeinode = iget_locked(sb, ino);if (!inode)return ERR_PTR(-ENOMEM);if (!(inode->i_state & I_NEW))//在inode高速缓存中查找到,并且不是最新分配的,那么直接返回return inode;ei = EXT4_I(inode);iloc.bh = NULL;//在inode高速缓存中没有找到,读取ext4文件系统的ext4_inoderet = __ext4_get_inode_loc(inode, &iloc, 0);if (ret < 0)goto bad_inode;raw_inode = ext4_raw_inode(&iloc);//根据ext4文件系统的ext4_inode初始化新分配的struct inode//比如初始化i_mode、i_uid 、i_gid inode->i_mode = le16_to_cpu(raw_inode->i_mode);i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);......i_uid_write(inode, i_uid);i_gid_write(inode, i_gid); ......//根据inode的文件类型初始化 i_op 和 i_fop if (S_ISREG(inode->i_mode)) {inode->i_op = &ext4_file_inode_operations;inode->i_fop = &ext4_file_operations;ext4_set_aops(inode);} else if (S_ISDIR(inode->i_mode)) {inode->i_op = &ext4_dir_inode_operations;inode->i_fop = &ext4_dir_operations;} else if (S_ISLNK(inode->i_mode)) {/* VFS does not allow setting these so must be corruption */if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) {ext4_error_inode(inode, function, line, 0,"iget: immutable or append flags ""not allowed on symlinks");ret = -EFSCORRUPTED;goto bad_inode;}if (IS_ENCRYPTED(inode)) {inode->i_op = &ext4_encrypted_symlink_inode_operations;ext4_set_aops(inode);} else if (ext4_inode_is_fast_symlink(inode)) {inode->i_link = (char *)ei->i_data;inode->i_op = &ext4_fast_symlink_inode_operations;nd_terminate_link(ei->i_data, inode->i_size,sizeof(ei->i_data) - 1);} else {inode->i_op = &ext4_symlink_inode_operations;ext4_set_aops(inode);}inode_nohighmem(inode);} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {inode->i_op = &ext4_special_inode_operations;if (raw_inode->i_block[0])init_special_inode(inode, inode->i_mode,old_decode_dev(le32_to_cpu(raw_inode->i_block[0])));elseinit_special_inode(inode, inode->i_mode,new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));} else if (ino == EXT4_BOOT_LOADER_INO) {make_bad_inode(inode);} else {ret = -EFSCORRUPTED;ext4_error_inode(inode, function, line, 0,"iget: bogus i_mode (%o)", inode->i_mode);goto bad_inode;}
}
__ext4_iget函数首先调用iget_locked函数根据超级块和文件的inode号从inode高速缓存中获取struct inode对象,如果从inode高速缓存中找到直接返回该struct inode对象,如果没有找到,分配一个struct inode对象,然后调用__ext4_get_inode_loc函数和ext4_raw_inode函数根据ext4文件系统读取磁盘上的ext4 inode,根据磁盘上的ext4 inode 来初始化struct inode对象,然后将struct inode对象加入到inode高速缓存中,以便下次inode加速查找。
3.2 LKM demo
接下来我们给出一个LKM示例根据inode号来获取对应的struct inode结构体:
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>#include <linux/fs.h>
#include <linux/fs_struct.h>#include <linux/kallsyms.h>/* Module parameter */
static unsigned long ino = 1837047;module_param(ino, ulong, 0);typedef enum {EXT4_IGET_NORMAL = 0,EXT4_IGET_SPECIAL = 0x0001, /* OK to iget a system inode */EXT4_IGET_HANDLE = 0x0002 /* Inode # is from a handle */
} ext4_iget_flags;struct inode *(*my__ext4_iget)(struct super_block *sb, unsigned long ino,ext4_iget_flags flags, const char *function,unsigned int line);static int __init hello_init(void)
{struct fs_struct *fs;struct path pwd;//unsigned long ino = 1837047;struct inode *inode;struct super_block *sb;fs = current->fs;get_fs_pwd(fs, &pwd);/* The root of the dentry tree */sb = pwd.dentry->d_sb;my__ext4_iget = (void *)kallsyms_lookup_name("__ext4_iget");inode = my__ext4_iget(sb, ino, EXT4_IGET_NORMAL, __func__, __LINE__);if(inode)printk("inode num = %ld\n", inode->i_ino);return -1;
}module_init(hello_init);MODULE_LICENSE("GPL");
相关文章:
Linux 内核中根据文件inode号获取其对应的struct inode
文章目录 前言一、简介二、iget_locked2.1 简介2.2 内核中使用2.3 LKM demo 三、ext4_iget3.1 简介3.2 LKM demo 前言 文件inode号和struct inode结构体请参考: Linux文件路径,目录项,inode号关联 Linux文件系统 struct inode 结构体解析 一…...
Pycharm-community-2021版安装和配置
一、下载Pycharm-community-2021 1.从官网下载pycharm-community Pycharm 版本官网 二、安装PyCharm 1.打开下载完成的安装包,点击Next 2.安装PyCharm到其他位置,点击Next 3.一定把更新PATH变量勾上,可以创建桌面快捷方式,创建关联,最后…...
飞书开发学习笔记(一)-应用创建和测试
飞书开发学习笔记(一)-应用创建和测试 一.前言 现在大企业用的办公IM软件中,飞书是口碑最好的,不得不说,字节在开发产品方面,确实有自己独到的竞争力,比如说抖音、头条、飞书。在办公会议和云文档的体验上,其它的办公…...
【Mybatis小白从0到90%精讲】12:Mybatis删除 delete, 推荐使用主键删除!
文章目录 前言XML映射文件方式推荐使用主键删除注解方式工具类前言 在实际开发中,我们经常需要删除数据库中的数据,MyBatis可以使用XML映射文件或注解来编写删除(delete)语句,下面是两种方法的示例。 XML映射文件方式 Mapper: int delete(int id);Mapper.xml:...
RocketMQ批量发送消息❓
优点: 批量发送消息可以提高rocketmq的生产者性能和吞吐量。 使用场景: 发送大量小型消息时;需要降低消息发送延迟时;需要提高生产者性能时; 注意事项: 消息列表的大小不能超过broker设置的最大消息大小;消息列表…...
一键同步chromedriver版本
ChromeDriver是一个控制Chrome浏览器的驱动程序,它和Selenium一起被广泛用于Web自动化测试。然而,随着Chrome版本的升级,我们需要不断更新ChromeDriver以保持其与Chrome的兼容性。这个过程既费时又繁琐,而且对于非技术人员来说可能…...
Zephyr-7B-β :类GPT的高速推理LLM
Zephyr 是一系列语言模型,经过训练可以充当有用的助手。 Zephyr-7B-β 是该系列中的第二个模型,是 Mistralai/Mistral-7B-v0.1 的微调版本,使用直接偏好优化 (DPO) 在公开可用的合成数据集上进行训练 。 我们发现,删除这些数据集的…...
【笔试题】位运算
记录一些常见的位运算题: 1、实现对一个8bit数据(unsigned char类型)的指定位(例如第n位)置0或者置1操作,并保持其他地位不变。 unsigned char reg;/* 对第n位置0 */ reg &~ (1 << n);/* 对第n位…...
RT-Thread 10. 使用keil4编译GD32F450
1. 修改keil路径 2.增加MCU型号宏定义 3. 在ENV界面输入 scons -c scons --targetmdk44. 编译 scons --verbose提示错误 Warning: L6310W: Unable to find ARM libraries. Error: L6411E: No compatible library exists with a definition of startup symbol __main. Finish…...
Vue 跨域的两种解决方式
一、通过 proxy 解决跨域 1.1 baseURL 配置 对 axios 二次封装时,baseURL 设置为 /api。 const serviceAxios axios.create({baseURL: /api,timeout: 10000, // 请求超时设置withCredentials: false, // 跨域请求是否需要携带 cookie });1.2 vue.config.js 配置…...
【windows Docker 安装mysql:只需3条命令】
如下 docker pull mysql docker run --name mysql -p 3306:3306 -v D:/dockerFile/mysql/data:/var/lib/mysql/ -v D:/dockerFile/mysql/conf/my.cnf:/etc/mysql/my.cnf -e MYSQL_ROOT_PASSWORDroot -d mysql:latest --default-authentication-pluginmysql_native_password do…...
【软件逆向】如何逆向Unity3D+il2cpp开发的安卓app【IDA Pro+il2CppDumper+DnSpy+AndroidKiller】
教程背景 课程作业要求使用反编译技术,在游戏中实现无碰撞。正常情况下碰撞后角色死亡,修改为直接穿过物体不死亡。 需要准备的软件 il2CppDumper。DnSpy。IDA Pro。AndroidKiller。 一、使用il2CppDumper导出程序集 将{my_game}.apk后缀修改为{my_…...
vue3ref和reactive
Vue 3中的ref和reactive是两个重要的响应式API。 ref用于将基本数据类型转换为响应式数据,它返回一个包含value属性的响应式对象。ref适合用于单个值的响应式需求,例如计数器、表单数据等。示例代码: <template><div><p>…...
[架构之路-244]:目标系统 - 设计方法 - 软件工程 - 软件开发方法与软件开发模型
目录 一、软件开发方法:组织、管理、复用软件代码的方法 1.1 概述: 软件聚合的程度由简单到复杂 1.2 结构化的开发方法 1.3 面对对象的开发方法 1.4 面向组件的开发方法 1.5 面向服务的开发方法 1.6 不同开发方法比较:结构化、面对对象、面向组件…...
Matter 系列 #10|Matter 的证书吊销机制
乐鑫 Matter 系列文章 #10 在之前的多篇博客文章中,我们从不同方面介绍了 Matter,其中包括 Matter 的安全模型。简单回顾一下,Matter 的安全模型基于 PKI(即公钥基础设施)机制,可用于建立和管理数字证书、加…...
mybatis动态表名
1.基于mybatis官方文档 Configuration public class MybatisPlusConfig {Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor new MybatisPlusInterceptor();DynamicTableNameInnerInterceptor dynamicTableNameInnerIntercep…...
高校为什么需要大数据挖掘平台?
目前数据挖掘已经成为各种应用领域的重要技术,大学数据挖掘课程的开放已经出现。数据挖掘课程整合了多门学科知识。该课程包括各种理论知识,也离不开相关的实用技术。整个教学过程是培养和提高学生全面创新和解决问题的能力。过去,教学过程理…...
@Value的使用
在spring boot项目中,Value只能获取非静态变量,否则是null /*** cron"0 */1 * * * ?"*/ Value("${system.cron}") private String cron;/*** cron1null*/ Value("${system.cron}") private static String cron1;静态块获…...
用 Wireshark 在 Firefox 或 Google Chrome 上使用 SSLKEYLOGFILE 环境变量解密 SSL 流量
原文:这 您希望使用 SSL 会话密钥解密和检查 SSL 应用程序数据。 您希望在客户端系统上记录 SSL 会话密钥。 您正在客户端系统上使用 Firefox 或 Google Chrome 浏览器来访问 Web 应用程序。 注意:您还可以在客户端系统上使用 Microsoft Edge ÿ…...
京东大数据:2023年Q3美妆行业数据分析报告
近日,珀莱雅发布三季报,今年前三季度,公司实现营收52.49亿元,同比增长32.47%。分季度看,“618大促”所在Q2业绩增长最为亮眼,营收同比增速达到46.22%,进入Q3,在电商大促缺席情况下&a…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
