偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Littlefs原理分析--Fetch操作(三)

系統(tǒng) OpenHarmony
本文介紹Fetch操作的流程及作用,描述了Littlefs中是怎樣通過(guò)遍歷元數(shù)據(jù)中的Tag和數(shù)據(jù),來(lái)獲取所需信息的。

??想了解更多關(guān)于開源的內(nèi)容,請(qǐng)?jiān)L問:??

??51CTO 開源基礎(chǔ)軟件社區(qū)??

??https://ost.51cto.com??

前言

前面的littlefs原理分析文章中,第一篇介紹了littlefs的整體結(jié)構(gòu),第二篇介紹了littlefs中記錄元數(shù)據(jù)的方式,即commit機(jī)制。這一篇(littlefs原理分析:(3)fetch操作)的主要內(nèi)容是介紹littlefs中的fetch操作,這部分還是與元數(shù)據(jù)有關(guān),不過(guò)commit過(guò)程是寫入元數(shù)據(jù),fetch操作是讀取元數(shù)據(jù)。

commit時(shí)記錄了如超級(jí)塊、文件、目錄的創(chuàng)建、刪除等操作。而如何去從這些記錄中獲取所需的信息(如打開文件時(shí)需要從其父目錄的元數(shù)據(jù)中獲取文件的塊指針),則是通過(guò)對(duì)元數(shù)據(jù)中tag的遍歷來(lái)完成。

fetch操作實(shí)際上就是對(duì)元數(shù)據(jù)中tag的遍歷,其功能是遍歷指定NAME類型的tag,如查找文件、目錄等,獲取文件、目錄id等數(shù)據(jù)。commit過(guò)程中寫入tag時(shí)也是通過(guò)tag的遍歷來(lái)完成的,不同的是fetch操作一般只用于讀取commit中記錄的數(shù)據(jù),而commit過(guò)程中調(diào)用的lfs_dir_traverse函數(shù)一般只用于寫入。

一、fetch作用說(shuō)明

fetch操作在littlefs中主要用于文件和目錄的讀取,和目錄的遍歷。

下面結(jié)合具體的文件、目錄操作,對(duì)其相應(yīng)的commit過(guò)程、以及commit之后如何結(jié)合fetch操作獲取相應(yīng)數(shù)據(jù),進(jìn)行說(shuō)明:

1、文件和目錄的讀取

在已知父目錄的元數(shù)據(jù)塊的情況下,文件和目錄的讀取可以分為以下兩個(gè)步驟:

  1. 遍歷查找到REG(DIR)類型的tag,獲取文件(目錄)名和文件(目錄)id
  2. 根據(jù)文件(目錄)id再次遍歷tag找到相應(yīng)數(shù)據(jù)tag,即INLINESTRUCT或CTZSTRUCT(DIRSTRUCT)

fetch操作完成了第一步,以下結(jié)合具體案例對(duì)fetch過(guò)程進(jìn)行說(shuō)明:

(1)文件創(chuàng)建后

文件剛創(chuàng)建時(shí)為inline文件:

 #littlefs原理分析#[三]fetch操作-開源基礎(chǔ)軟件社區(qū)

此時(shí)遍歷查找到與文件路徑匹配的REG類型的tag,就能夠獲取文件名和文件id、再通過(guò)其文件id再次遍歷tag就能夠獲取文件的數(shù)據(jù)。

如打開剛創(chuàng)建的文件:

lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file,
| const char *path, int flags,
| const struct lfs_file_config *cfg)
| // 1. 根據(jù)路徑查找對(duì)應(yīng)tag和id
| // 此時(shí)查找的為REG類型的tag,查找到的文件id存儲(chǔ)在file->id
|-> lfs_stag_t tag = lfs_dir_find(lfs, &file->m, &path, &file->id);
|
| // 2. 根據(jù)文件id查找文件數(shù)據(jù)對(duì)應(yīng)tag
| // 此時(shí)查找的為STRUCT類型的tag,包括inline文件和outline文件
|-> tag = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x700, 0x3ff, 0),
| LFS_MKTAG(LFS_TYPE_STRUCT, file->id, 8), &file->ctz);
|
|-> ...

(2)文件刪除后

如刪除剛創(chuàng)建的文件:

 #littlefs原理分析#[三]fetch操作-開源基礎(chǔ)軟件社區(qū)

進(jìn)行文件或目錄的刪除操作時(shí),會(huì)寫入DELETE和CRC類型的tag。其中,CREATE和DELETE類型的tag中的id存儲(chǔ)了相應(yīng)創(chuàng)建或刪除的文件或目錄的id。

此時(shí)若再打開該文件,在遍歷tag時(shí),由于檢查到了包含對(duì)應(yīng)id的DELETE類型tag,則會(huì)返回失敗。

在遍歷獲取文件、目錄數(shù)據(jù)的相關(guān)函數(shù)中,對(duì)DELETE類型tag的相關(guān)檢測(cè)分析如下:

// 該函數(shù)用于遍歷時(shí)查找匹配的tag,如打開文件時(shí)查找匹配文件的對(duì)應(yīng)tag
lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
| lfs_mdir_t *dir, const lfs_block_t pair[2],
| lfs_tag_t fmask, lfs_tag_t ftag, uint16_t *id,
| int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data)
|-> ...
|
| // 如果當(dāng)前遍歷到的tag的類型為DELETE,且其id與tempbesttag中id相同
| // 則將tempbesttag置為無(wú)效。
|-> if (tag == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) |
| (LFS_MKTAG(0, 0x3ff, 0) & tempbesttag))) {
| tempbesttag |= 0x80000000;
| }
|-> ...

(3)其他

  • 目錄創(chuàng)建、刪除后的讀取過(guò)程與文件創(chuàng)建、刪除后的類似
  • 目錄、文件的移動(dòng)實(shí)際上是創(chuàng)建過(guò)程和刪除過(guò)程的結(jié)合,先在新父目錄下創(chuàng)建,再在舊父目錄下刪除。其讀取過(guò)程也類似。

2、目錄的遍歷

littlefs中目錄的遍歷是通過(guò)TAIL類型的tag來(lái)進(jìn)行的,TAIL類型tag在littlefs存儲(chǔ)結(jié)構(gòu)中已說(shuō)明,分為SOFTTAIL和HARDTAIL。每個(gè)目錄對(duì)應(yīng)的元數(shù)據(jù)塊中都可能存儲(chǔ)指向其他目錄的SOFTTAIL或者指向該目錄下一個(gè)元數(shù)據(jù)塊的HARDTAIL。

如何從一個(gè)目錄跳轉(zhuǎn)到其后繼目錄,其實(shí)就是通過(guò)fetch tail的操作實(shí)現(xiàn)。

本節(jié)中著重介紹fetch tail的過(guò)程,即已知其父目錄的情況下,如何跳轉(zhuǎn)到后繼目錄。目錄的鏈接方式見后面的文章。

(1)fetch tail

在父目錄中會(huì)記錄其子目錄的創(chuàng)建信息,并會(huì)有相應(yīng)的SOFTTAIL指向該子目錄。具體目錄操作后目錄的鏈接方式見后面的文章,這里只是以一個(gè)包含多個(gè)子目錄的父目錄的例子來(lái)對(duì)fetch tail的過(guò)程進(jìn)行說(shuō)明。

下圖中父目錄有兩個(gè)元數(shù)據(jù)對(duì),包含了指向子目錄A、B、C的SOFTTAIL:

 #littlefs原理分析#[三]fetch操作-開源基礎(chǔ)軟件社區(qū)

在fetch操作對(duì)應(yīng)函數(shù)lfs_dir_fetchmatch中,能夠檢查到TAIL類型的tag更新傳入的參數(shù)dir->tail,保存TAIL指向的元數(shù)據(jù)對(duì)塊。

littlefs中通常是fetch最后一個(gè)TAIL,在上圖中即為HARDTAIL和目錄C。littlefs目錄鏈接相關(guān)的機(jī)制保證這樣遍歷能夠從根目錄遍歷完所有目錄。相關(guān)函數(shù)為lfs_dir_fetch:

int lfs_dir_fetch(lfs_t *lfs,
lfs_mdir_t *dir, // fetch tail結(jié)果存儲(chǔ)在dir->tail中
const lfs_block_t pair[2] // 父目錄元數(shù)據(jù)對(duì)所在塊
) {
// 調(diào)用lfs_dir_fetchmatch實(shí)現(xiàn)
// 其中fmask、ftag為-1,表示不進(jìn)行匹配,會(huì)fetch到元數(shù)據(jù)末尾
return (int)lfs_dir_fetchmatch(lfs, dir, pair,
(lfs_tag_t)-1, (lfs_tag_t)-1, NULL, NULL, NULL);
}

因?yàn)門AIL類型的tag分為SOFTTAIL和HARDTAIL,因此最后dir->tail中保存的tail既可能是HARDTAIL,也可能是SOFTTAIL。以上圖為例:

  1. 第一次調(diào)用lfs_dir_fetch,dir->tail中保存的tail為HARDTAIL,指向該目錄的下一個(gè)元數(shù)據(jù)塊
  2. 第二次調(diào)用lfs_dir_fetch,dir->tail中保存的tail為SOFTTAIL,指向子目錄C

(2)fetch下一個(gè)目錄

上小節(jié)中,lfs_dir_fetch既可以fetch HARDTAIL,也可以fetch SOFTTAIL。而fetch過(guò)程中同時(shí)會(huì)更新dir->split成員,該成員表示當(dāng)前目錄塊是否有再分,當(dāng)dir->split為false即表示在當(dāng)前目錄塊的末尾。

由此littlefs中常用以下方法fetch下一個(gè)目錄:

lfs_mdir_t m = dir.m;
while (m.split) {
lfs_dir_fetch(lfs, &m, m.tail);
}

(3)目錄刪除和移動(dòng)后

如果SOFTTAIL對(duì)應(yīng)的目錄已被刪除或移動(dòng),那么在該CREATE等tag后應(yīng)有一個(gè)DELETE類型的tag。但該DELETE類型tag對(duì)fetch tail的過(guò)程沒有影響。目錄的鏈接方式只與SOFTTAIL類型tag有關(guān)。目錄刪除和移動(dòng)后具體的鏈接方式變化見后面的文章。

二、fetch流程

fetch操作的相關(guān)函數(shù)為lfs_dir_fetchmatch,該函數(shù)遍歷tag并從中匹配和獲取數(shù)據(jù)。該函數(shù)定義在上節(jié)中已提到,該函數(shù)匹配到tag之后會(huì)執(zhí)行相應(yīng)的回調(diào)函數(shù),回調(diào)函數(shù)一般為對(duì)tag和相應(yīng)數(shù)據(jù)進(jìn)行進(jìn)一步的比較和匹配。流程如下:

 #littlefs原理分析#[三]fetch操作-開源基礎(chǔ)軟件社區(qū)

代碼分析如下:

static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
| lfs_mdir_t *dir, const lfs_block_t pair[2],
| lfs_tag_t fmask, lfs_tag_t ftag, uint16_t *id,
| int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
| // 用besttag保存最佳匹配結(jié)果
|-> lfs_stag_t besttag = -1;
|
|-> ...
|
| // 準(zhǔn)備用于暫存每次匹配中的最佳匹配結(jié)果、更新等變量
|-> uint16_t tempcount = 0;
| lfs_block_t temptail[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL};
| bool tempsplit = false;
| lfs_stag_t tempbesttag = besttag;
|
| // fetch主流程
|-> while (true) {
| // 1. 從磁盤中解析下一個(gè)tag并計(jì)算tag的CRC
|-> lfs_bd_read(lfs,
| NULL, &lfs->rcache, lfs->cfg->block_size,
| dir->pair[0], off, &tag, sizeof(tag));
| crc = lfs_crc(crc, &tag, sizeof(tag));
| tag = lfs_frombe32(tag) ^ ptag;
|
| // 2. 檢查邊界,當(dāng)不在范圍內(nèi)或tag無(wú)效時(shí)跳出循環(huán)
|-> if (!lfs_tag_isvalid(tag)) {
| dir->erased = (lfs_tag_type1(ptag) == LFS_TYPE_CRC &&
| dir->off % lfs->cfg->prog_size == 0);
| break;
| } else if (off + lfs_tag_dsize(tag) > lfs->cfg->block_size) {
| dir->erased = false;
| break;
| }
|
| // 3. 如果tag為CRC,則檢查CRC并更新最佳匹配結(jié)果
|-> if (lfs_tag_type1(tag) == LFS_TYPE_CRC) {
| // 3.1 檢查CRC
|-> uint32_t dcrc;
| lfs_bd_read(lfs,
| NULL, &lfs->rcache, lfs->cfg->block_size,
| dir->pair[0], off+sizeof(tag), &dcrc, sizeof(dcrc));
| if (crc != dcrc) {
| dir->erased = false;
| break;
| }
|
| // 3.2 更新最佳匹配結(jié)果等
|-> besttag = tempbesttag;
| dir->off = off + lfs_tag_dsize(tag);
| dir->etag = ptag;
| dir->count = tempcount;
| dir->tail[0] = temptail[0];
| dir->tail[1] = temptail[1];
| dir->split = tempsplit;
|
| // 3.3 重置CRC
|-> crc = 0xffffffff;
| continue;
}
|
| // 4. 計(jì)算entry的CRC
|-> for (lfs_off_t j = sizeof(tag); j < lfs_tag_dsize(tag); j++) {
| uint8_t dat;
| lfs_bd_read(lfs,
| NULL, &lfs->rcache, lfs->cfg->block_size,
| dir->pair[0], off+j, &dat, 1);
| ...
| crc = lfs_crc(crc, &dat, 1);
| }
|
| // 5. 根據(jù)tag類型進(jìn)行相應(yīng)更新
|-> if (lfs_tag_type1(tag) == LFS_TYPE_NAME) {
| // 5.1 tag為NAME類型,則根據(jù)其中id更新目錄中count
| // 目錄中的最后一個(gè)id為count-1
| if (lfs_tag_id(tag) >= tempcount) {
| tempcount = lfs_tag_id(tag) + 1;
| }
| } else if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE) {
| // 5.2 tag為DELETE類型,如果id和目前的最佳匹配結(jié)果對(duì)應(yīng)
| // 則將最佳匹配結(jié)果置為無(wú)效
| if (tag == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) |
| (LFS_MKTAG(0, 0x3ff, 0) & tempbesttag))) {
| tempbesttag |= 0x80000000;
| }
| ...
| } else if (lfs_tag_type1(tag) == LFS_TYPE_TAIL) {
| // 5.3 tag為TAIL類型,則更新tempsplit和temptail
| tempsplit = (lfs_tag_chunk(tag) & 1);
| lfs_bd_read(lfs,
| NULL, &lfs->rcache, lfs->cfg->block_size,
| dir->pair[0], off+sizeof(tag), &temptail, 8);
| ...
| }
|
| // 6. 先用fmask和ftag參數(shù)進(jìn)行初次匹配
|-> if ((fmask & tag) == (fmask & ftag)) {
| // 6.1 如果匹配則調(diào)用cb回調(diào)函數(shù)進(jìn)行進(jìn)一步匹配
| int res = cb(data, tag, &(struct lfs_diskoff){
| dir->pair[0], off+sizeof(tag)});
| ...
| // 6.2 如果匹配成功則更新到最佳匹配結(jié)果
| if (res == LFS_CMP_EQ) {
| tempbesttag = tag;
| } else if (...)
| ...
| }
| }
|
| // 如果讀到結(jié)束,則根據(jù)最佳匹配結(jié)果返回相應(yīng)值
|-> if (dir->off > 0) {
| ...
|
| if (lfs_tag_isvalid(besttag)) {
| return besttag;
| } else if (lfs_tag_id(besttag) < dir->count) {
| return LFS_ERR_NOENT;
| } else {
| return 0;
| }
| }
|
|-> ...

1、tag和數(shù)據(jù)的讀取

如上文中對(duì)fetch流程的分析,也和commit時(shí)tag和數(shù)據(jù)寫入的過(guò)程類似,fetch等操作時(shí)遍歷讀取tag的數(shù)據(jù)如下圖所示:

 #littlefs原理分析#[三]fetch操作-開源基礎(chǔ)軟件社區(qū)

如上圖,tag和數(shù)據(jù)的讀取過(guò)程實(shí)際上與commit時(shí)tag和數(shù)據(jù)寫入的過(guò)程相對(duì)稱。在tag和數(shù)據(jù)的讀取過(guò)程中,ptag用于進(jìn)行tag的異或運(yùn)算,其初始化值為0xffffffff。ptag會(huì)依次與將要commit的tag(如上圖中的tagA、tagB、tagC)進(jìn)行異或運(yùn)算,每次運(yùn)算后的結(jié)果即為讀取出來(lái)的tag。同時(shí)每讀取一個(gè)tag后,其對(duì)應(yīng)的數(shù)據(jù)也能夠相應(yīng)進(jìn)行解析。

2、crc的校驗(yàn)

如上文中對(duì)fetch流程的分析,在fetch過(guò)程中會(huì)進(jìn)行crc的校驗(yàn),以檢驗(yàn)commit是否有效。crc校驗(yàn)時(shí)仍用lfs_crc函數(shù)進(jìn)行計(jì)算,該函數(shù)在上一篇文章中已作說(shuō)明。

crc校驗(yàn)從元數(shù)據(jù)塊中的revision count開始,逐個(gè)與tag或數(shù)據(jù)進(jìn)行計(jì)算,每當(dāng)遇到crc tag時(shí),則將當(dāng)前crc結(jié)果與crc tag對(duì)應(yīng)crc值進(jìn)行比對(duì)。如果不匹配,則當(dāng)前commit以及其后的commit中所有tag和數(shù)據(jù)將會(huì)被視為無(wú)效。crc的校驗(yàn)使得commit操作具有原子性。

總結(jié)

本文介紹了fetch操作的流程及作用,描述了littlefs中是怎樣通過(guò)遍歷元數(shù)據(jù)中的tag和數(shù)據(jù),來(lái)獲取所需信息的。后面的文章將會(huì)開始介紹具體的目錄和文件操作。

??想了解更多關(guān)于開源的內(nèi)容,請(qǐng)?jiān)L問:??

??51CTO 開源基礎(chǔ)軟件社區(qū)??

??https://ost.51cto.com??

責(zé)任編輯:jianghua 來(lái)源: 51CTO開源基礎(chǔ)軟件社區(qū)
相關(guān)推薦

2022-11-09 08:52:57

littlefs目錄操作

2022-11-15 09:24:16

littlefs文件讀寫

2022-10-27 16:07:24

littlefs存儲(chǔ)結(jié)構(gòu)

2022-11-02 15:56:45

littlefscommit機(jī)制

2022-11-22 15:21:55

littlefs磨損均衡

2009-02-27 08:56:30

IIS.Net原理分析

2020-10-13 07:35:22

JUC - Count

2023-04-26 08:39:41

Bitmap元素存儲(chǔ)

2022-04-13 08:23:31

Golang并發(fā)

2021-10-12 17:19:17

Random局限性變量

2010-06-04 14:10:09

MySQL_fetch

2011-08-24 15:14:12

fetch中文man

2025-02-28 09:58:07

2012-12-03 16:57:37

HDFS

2009-09-24 09:35:47

Hibernate插入

2021-08-09 11:15:28

MybatisJavaSpring

2009-11-06 09:22:46

WCF應(yīng)用

2021-04-21 15:17:10

WebsocketWsnodejs

2015-06-15 10:12:36

Java原理分析

2021-11-26 17:17:43

Android廣播運(yùn)行原理源碼分析
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)