自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Littlefs原理分析--Commit機(jī)制(二)

系統(tǒng) OpenHarmony
本文介紹了Littlefs中的Commit機(jī)制,包括Commit、Compact、Split操作的過(guò)程,怎樣寫(xiě)入Tag和數(shù)據(jù),怎樣計(jì)算CRC,以及相應(yīng)的異常情況處理等。

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

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

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

前言

回顧littlefs的存儲(chǔ)結(jié)構(gòu),其中最為核心的是元數(shù)據(jù)。元數(shù)據(jù)以tag為單元進(jìn)行信息的存儲(chǔ),以commit的方式進(jìn)行信息的更新。當(dāng)littlefs中進(jìn)行文件、目錄的創(chuàng)建、修改、刪除等一系列操作時(shí),實(shí)際上都是通過(guò)向元數(shù)據(jù)中進(jìn)行commit操作的方式實(shí)現(xiàn)。本文將對(duì)littlefs中commit機(jī)制進(jìn)行介紹。

一、commit過(guò)程

commit具體的過(guò)程如下圖所示:

#littlefs原理分析#[二]commit機(jī)制-開(kāi)源基礎(chǔ)軟件社區(qū)

每一次commit時(shí)都會(huì)向元數(shù)據(jù)對(duì)中寫(xiě)入一系列的tag和數(shù)據(jù),并計(jì)算CRC。因?yàn)樵赾ommit時(shí)總是會(huì)進(jìn)行CRC計(jì)算,并且從元數(shù)據(jù)中讀取數(shù)據(jù)時(shí)會(huì)做校驗(yàn),因此一次commit是一次原子操作。

下面以具體的案例對(duì)commit過(guò)程進(jìn)行說(shuō)明:

1、超級(jí)塊的創(chuàng)建

當(dāng)littlefs進(jìn)行格式化操作時(shí),會(huì)進(jìn)行超級(jí)塊的創(chuàng)建。超級(jí)塊創(chuàng)建主要是在根目錄對(duì)應(yīng)元數(shù)據(jù)對(duì)的塊中進(jìn)行commit:

#littlefs原理分析#[二]commit機(jī)制-開(kāi)源基礎(chǔ)軟件社區(qū)

如上圖,超級(jí)塊創(chuàng)建時(shí)調(diào)用lfs_dir_commit函數(shù)寫(xiě)入了CREATE、SUPERBLOCK、INLINESTRUCT和CRC類型的tag。lfs_dir_commit函數(shù)中進(jìn)行了commit的實(shí)際寫(xiě)入操作,其主要分為以下兩個(gè)步驟:

  1. 將tag和對(duì)應(yīng)的數(shù)據(jù)依次寫(xiě)入元數(shù)據(jù)對(duì)應(yīng)塊中。
  2. 計(jì)算CRC,并接著將其tag和CRC數(shù)據(jù)寫(xiě)入元數(shù)據(jù)對(duì)應(yīng)塊中。

超級(jí)塊創(chuàng)建相關(guān)函數(shù):

lfs_format(lfs_t *lfs, const struct lfs_config *cfg)
|-> lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg)
| // 1. 分配根目錄,其塊號(hào)為0,1
|-> lfs_dir_alloc(lfs, &root);
|
| // 2. 通過(guò)commit創(chuàng)建超級(jí)塊
|-> lfs_superblock_t superblock = {
| .version = LFS_DISK_VERSION,
| .block_size = lfs->cfg->block_size,
| .block_count = lfs->cfg->block_count,
| .name_max = lfs->name_max,
| .file_max = lfs->file_max,
| .attr_max = lfs->attr_max,
| };
| lfs_dir_commit(lfs, &root, LFS_MKATTRS(
| {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0), NULL},
| {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"},
| {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
| &superblock}));

(1)tag和相應(yīng)數(shù)據(jù)的寫(xiě)入

#littlefs原理分析#[二]commit機(jī)制-開(kāi)源基礎(chǔ)軟件社區(qū)

如上圖,在commit過(guò)程中,ptag用于進(jìn)行tag的異或運(yùn)算,其初始化值為0xffffffff。ptag會(huì)依次與將要commit的tag(如上圖中的tagA、tagB、tagC)進(jìn)行異或運(yùn)算,然后將運(yùn)算后的結(jié)果存儲(chǔ)到塊中。同時(shí)每寫(xiě)一個(gè)tag后,將其對(duì)應(yīng)的數(shù)據(jù)也進(jìn)行寫(xiě)入。

相關(guān)函數(shù)分析:

lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit,
| lfs_tag_t tag, const void *buffer)
| // 1. 將ptag和tag進(jìn)行異或運(yùn)算
| // 注:這里將tag的有效位置為了0,表示tag有效,并且tag為大端存儲(chǔ)
|-> lfs_tag_t ntag = lfs_tobe32((tag & 0x7fffffff) ^ commit->ptag);
|
| // 2. 寫(xiě)入異或后的ntag
|-> lfs_dir_commitprog(lfs, commit, &ntag, sizeof(ntag));
|
| // 3. 寫(xiě)入對(duì)應(yīng)數(shù)據(jù)
|-> lfs_dir_commitprog(lfs, commit, buffer, dsize-sizeof(tag));

(2)CRC的寫(xiě)入

commit過(guò)程中,當(dāng)寫(xiě)入tag(異或后的tag)或數(shù)據(jù)時(shí),均會(huì)進(jìn)行逐字節(jié)CRC的計(jì)算。最后commit完成后,再寫(xiě)入相應(yīng)的CRC tag和對(duì)應(yīng)的CRC值。同時(shí)為了寫(xiě)入對(duì)齊,在CRC tag后會(huì)設(shè)置相應(yīng)的padding。

CRC計(jì)算的范圍為從本次commit起始的tag和數(shù)據(jù),一直到CRC tag(包括CRC tag)。

寫(xiě)入CRC后塊中布局如下圖:

#littlefs原理分析#[二]commit機(jī)制-開(kāi)源基礎(chǔ)軟件社區(qū)

相關(guān)函數(shù)分析:

// 該函數(shù)用于寫(xiě)入tag或數(shù)據(jù),每當(dāng)調(diào)用該函數(shù)時(shí)都會(huì)做CRC的計(jì)算
lfs_dir_commitprog(lfs_t *lfs, struct lfs_commit *commit,
| const void *buffer, lfs_size_t size)
| // 1. 將傳入的tag或tag對(duì)應(yīng)數(shù)據(jù)寫(xiě)入塊中
|-> lfs_bd_prog(lfs,
| &lfs->pcache, &lfs->rcache, false,
| commit->block, commit->off ,
| (const uint8_t*)buffer, size)
|
| // 2. 計(jì)算CRC和更新偏移
|-> commit->crc = lfs_crc(commit->crc, buffer, size);
| commit->off += size;

// 該函數(shù)用于寫(xiě)入CRC tag和padding
lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit)
| // 1. 創(chuàng)建CRC tag,并異或后存儲(chǔ)于footer[0]中
| // 這里tag的size設(shè)置為了noff - off,實(shí)際上是包含了padding的大小
| // littlefs中沒(méi)有通過(guò)填充數(shù)據(jù)的方式來(lái)設(shè)置padding,而是設(shè)置其tag的size進(jìn)行標(biāo)記
|-> tag = LFS_MKTAG(LFS_TYPE_CRC + reset, 0x3ff, noff - off);
| uint32_t footer[2];
| footer[0] = lfs_tobe32(tag ^ commit->ptag);
|
| // 2. 計(jì)算CRC并將CRC值存入footer[1]中
| // 這里是最后一次計(jì)算CRC,前面的tag和數(shù)據(jù)已經(jīng)在寫(xiě)入時(shí)計(jì)算,只差CRC tag
|-> commit->crc = lfs_crc(commit->crc, &footer[0], sizeof(footer[0]));
| footer[1] = lfs_tole32(commit->crc);
|
| // 3. 寫(xiě)入CRC tag和CRC值到塊中
|-> lfs_bd_prog(lfs,
| &lfs->pcache, &lfs->rcache, false,
| commit->block, commit->off, &footer, sizeof(footer));

(3)crc的計(jì)算

littlefs中crc計(jì)算核心函數(shù)如下:

uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
static const uint32_t rtable[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
};
const uint8_t *data = buffer;
for (size_t i = 0; i < size; i++) {
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf];
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf];
}
return crc;
}

本文中不對(duì)crc的原理進(jìn)行具體介紹,有興趣的讀者可參考以下鏈接:

littlefs中crc計(jì)算算法的特點(diǎn)是采用了32位的crc結(jié)果,輸入數(shù)據(jù)以4bit為單位進(jìn)行計(jì)算。其中還用到了lookup table進(jìn)行加速,因?yàn)檩斎氲臄?shù)據(jù)以4bit為單位進(jìn)行計(jì)算,每次有2^4即16種可能的輸入,所以該lookup table的長(zhǎng)度為16。從lookup table中還可看出該crc算法對(duì)應(yīng)的多項(xiàng)式值為0x1db71064。

2、tag的遍歷和寫(xiě)入總結(jié)

與遍歷并寫(xiě)入tag等數(shù)據(jù)相關(guān)的函數(shù)為lfs_dir_traverse,該函數(shù)被lfs_dir_commit調(diào)用。該函數(shù)只用于commit等需要寫(xiě)入tag數(shù)據(jù)的過(guò)程,不用于遍歷獲取數(shù)據(jù)。其流程如下:

#littlefs原理分析#[二]commit機(jī)制-開(kāi)源基礎(chǔ)軟件社區(qū)

代碼分析如下:

static int lfs_dir_traverse(lfs_t *lfs,
| const lfs_mdir_t *dir, lfs_off_t off, lfs_tag_t ptag,
| const struct lfs_mattr *attrs, int attrcount,
| lfs_tag_t tmask, lfs_tag_t ttag,
| uint16_t begin, uint16_t end, int16_t diff,
| int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
|-> while (true) {
| // 1. 從磁盤(pán)或attrs中獲取下一個(gè)tag和相應(yīng)數(shù)據(jù),如果沒(méi)有則結(jié)束
| // attrs中保存的是將要commit的tag和相應(yīng)數(shù)據(jù)
| lfs_tag_t tag;
| const void *buffer;
| struct lfs_diskoff disk;
| // 1.1 如果在磁盤(pán)偏移范圍內(nèi),則從磁盤(pán)中獲取下一個(gè)tag和數(shù)據(jù)
| // 一般進(jìn)行commit時(shí)會(huì)將偏移設(shè)置到磁盤(pán)末尾,不從磁盤(pán)中獲取之前的tag
| // 只有如compact等過(guò)程中才從磁盤(pán)中獲取之前的tag來(lái)寫(xiě)入
|-> if (off+lfs_tag_dsize(ptag) < dir->off) {
| off += lfs_tag_dsize(ptag);
| ...
|
| tag = (lfs_frombe32(tag) ^ ptag) | 0x80000000;
| disk.block = dir->pair[0];
| disk.off = off+sizeof(lfs_tag_t);
| buffer = &disk;
| ptag = tag;
| } else if (attrcount > 0) {
| // 1.2 從attrs中獲取下一個(gè)tag和數(shù)據(jù)
| // attrs中保存的是將要commit的新的tag和數(shù)據(jù)
|-> tag = attrs[0].tag;
| buffer = attrs[0].buffer;
| attrs += 1;
| attrcount -= 1;
| } else {
| // 1.3 否則結(jié)束
|-> return 0;
| }
|
| // 2. 使用tmask和ttag參數(shù)過(guò)濾掉不想要寫(xiě)入的tag
|-> lfs_tag_t mask = LFS_MKTAG(0x7ff, 0, 0);
| if ((mask & tmask & tag) != (mask & tmask & ttag)) {
| continue;
| }
|
| // 3. 去除冗余tag等
| if (lfs_tag_id(tmask) != 0) {
| int filter = lfs_dir_traverse(lfs,
| dir, off, ptag, attrs, attrcount,
| 0, 0, 0, 0, 0,
| lfs_dir_traverse_filter, &tag);
| if (filter < 0) {
| return filter;
| }
|
| if (filter) {
| continue;
| }
|
| if (!(lfs_tag_id(tag) >= begin && lfs_tag_id(tag) < end)) {
| continue;
| }
| }
|
| // 4. 處理一些特殊情況
| if (lfs_tag_type3(tag) == ...) {
| ...
| } else {
| // 5. 調(diào)用cb回調(diào)函數(shù)進(jìn)行寫(xiě)入
|-> cb(data, tag + LFS_MKTAG(0, diff, 0), buffer);
| ...
| }
| }
}

二、compact過(guò)程

當(dāng)commit時(shí),如果元數(shù)據(jù)對(duì)應(yīng)塊中的空間不夠,則會(huì)嘗試進(jìn)行compact操作。如下圖:

#littlefs原理分析#[二]commit機(jī)制-開(kāi)源基礎(chǔ)軟件社區(qū)

上圖中左邊元數(shù)據(jù)塊中有兩個(gè)commit,其中tag A’是tag A的更新版本。當(dāng)commit一個(gè)tag B’作為tag B的更新版本后,如右圖中右邊的元數(shù)據(jù)塊,冗余的tag A和tag B被去除,只剩下一個(gè)commit。

如果compact后元數(shù)據(jù)塊中的空間足夠的話,在進(jìn)行完compact操作之后的元數(shù)據(jù)塊中就只會(huì)剩下一個(gè)CRC tag,即只有一個(gè)commit。compact的主要過(guò)程其實(shí)就是篩除冗余的tag和數(shù)據(jù)之后,將剩下的tag和數(shù)據(jù)作為一次commit寫(xiě)入同元數(shù)據(jù)對(duì)中的另一個(gè)塊中。

1、compact去除內(nèi)容

下面對(duì)compact過(guò)程中具體會(huì)去除的tag和相應(yīng)數(shù)據(jù)進(jìn)行說(shuō)明。

compact過(guò)程中調(diào)用了lfs_dir_traverse進(jìn)行去除冗余tag并寫(xiě)入:

lfs_dir_compact(lfs_t *lfs,
| lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount,
| lfs_mdir_t *source, uint16_t begin, uint16_t end)
|-> ...
|
| // 去重并寫(xiě)入tag
| // 這里使用了LFS_TYPE_NAME的tag類型進(jìn)行過(guò)濾
|-> lfs_dir_traverse(lfs,
| source, 0, 0xffffffff, attrs, attrcount,
| LFS_MKTAG(0x400, 0x3ff, 0),
| LFS_MKTAG(LFS_TYPE_NAME, 0, 0),
| begin, end, -begin,
| lfs_dir_commit_commit, &(struct lfs_dir_commit_commit){
| lfs, &commit});
|
|-> ...

在lfs_dir_traverse中用下面的邏輯進(jìn)行篩選tag:

static int lfs_dir_traverse(lfs_t *lfs,
| const lfs_mdir_t *dir, lfs_off_t off, lfs_tag_t ptag,
| const struct lfs_mattr *attrs, int attrcount,
| lfs_tag_t tmask, lfs_tag_t ttag,
| uint16_t begin, uint16_t end, int16_t diff,
| int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
|-> ...
|
|-> lfs_tag_t mask = LFS_MKTAG(0x7ff, 0, 0);
| if ((mask & tmask & tag) != (mask & tmask & ttag)) {
| continue;
| }
|-> ...

其中,mask為L(zhǎng)FS_MKTAG(0x7ff, 0, 0),tmask為L(zhǎng)FS_MKTAG(0x400, 3ff, 0),ttag為L(zhǎng)FS_MKTAG(LFS_TYPE_NAME, 0, 0)即LFS_MKTAG(0, 0, 0),則篩選邏輯可簡(jiǎn)化為:

if ((LFS_MKTAG(400, 0, 0) & tag) != LFS_MKTAG(0, 0, 0)) {
continue;
}

總結(jié)有以下類型的tag會(huì)被去除:

  • LFS_TYPE_SPLICE:包括CREATE和DELETE
  • LFS_TYPE_TAIL:包括SOFTTAIL和HARDTAIL
  • LFS_TYPE_GLOBALS:即MOVESTATE
  • LFS_TYPE_CRC

2、compact寫(xiě)入過(guò)程

與commit中tag和數(shù)據(jù)的寫(xiě)入過(guò)程類似,compact中的寫(xiě)入過(guò)程包括:

  1. 寫(xiě)入更新后的revision count。
  2. 寫(xiě)入去除冗余后的tag和數(shù)據(jù)。
  3. 如果原來(lái)有SOFTTAIL或HARDTAIL,則將原來(lái)最后一個(gè)TAIL補(bǔ)充寫(xiě)入。因此,compact過(guò)程對(duì)目錄的遍歷方式無(wú)影響,具體目錄的遍歷見(jiàn)后面的文章。
  4. 如果原來(lái)有MOVESTATE且進(jìn)行異或之后不為0,則將異或后的gstate作為MOVESTATE tag補(bǔ)充寫(xiě)入。gstate相關(guān)機(jī)制見(jiàn)后面的文章。
  5. 寫(xiě)入CRC。

相關(guān)函數(shù)分析:

lfs_dir_compact(lfs_t *lfs,
| lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount,
| lfs_mdir_t *source, uint16_t begin, uint16_t end)
| // 1. 檢查剩余空間,如果不夠則進(jìn)行split操作
|-> lfs_dir_split(lfs, dir, attrs, attrcount,
| source, begin+split, end)
|
| // 2. revision count + 1,并寫(xiě)入
|-> dir->rev += 1;
| lfs_bd_erase(lfs, dir->pair[1]);
| lfs_dir_commitprog(lfs, &commit,
| &dir->rev, sizeof(dir->rev));
|
| // 3. 去重并寫(xiě)入tag
|-> lfs_dir_traverse(lfs,
| source, 0, 0xffffffff, attrs, attrcount,
| LFS_MKTAG(0x400, 0x3ff, 0),
| LFS_MKTAG(LFS_TYPE_NAME, 0, 0),
| begin, end, -begin,
| lfs_dir_commit_commit, &(struct lfs_dir_commit_commit){
| lfs, &commit});
|
| // 4. 補(bǔ)充寫(xiě)入tail
|-> if (!lfs_pair_isnull(dir->tail)) {
| ...
| lfs_dir_commitattr(lfs, &commit,
| LFS_MKTAG(LFS_TYPE_TAIL + dir->split, 0x3ff, 8),
| dir->tail);
| ...
| }
|
| // 5. 補(bǔ)充寫(xiě)入move state
|-> if (!lfs_gstate_iszero(&delta)) {
| ...
| lfs_dir_commitattr(lfs, &commit,
| LFS_MKTAG(LFS_TYPE_MOVESTATE, 0x3ff,
| sizeof(delta)), &delta);
| ...
| }
|
| // 6. 計(jì)算CRC
|-> lfs_dir_commitcrc(lfs, &commit);

三、split過(guò)程

當(dāng)commit時(shí),進(jìn)行compact操作后仍空間不足,則會(huì)進(jìn)行split操作,將元數(shù)據(jù)對(duì)劃分為多個(gè)塊進(jìn)行存儲(chǔ):

#littlefs原理分析#[二]commit機(jī)制-開(kāi)源基礎(chǔ)軟件社區(qū)

如上圖,左圖中右邊的元數(shù)據(jù)塊為最新的元數(shù)據(jù)塊,其中包含一個(gè)commit的內(nèi)容,即tag A’和tag B’。當(dāng)再次commit tag C和tag D時(shí),一個(gè)元數(shù)據(jù)塊裝不下,就會(huì)進(jìn)行split操作。split操作在第一個(gè)元數(shù)據(jù)塊commit的末尾加入一個(gè)HARDTAIL類型的tag,指向一個(gè)新的元數(shù)據(jù)塊。新的元數(shù)據(jù)塊中再裝入剩下的tag和數(shù)據(jù)。

split操作中會(huì)遞歸調(diào)用compact和split,使得在一次split的容量無(wú)法滿足commit需求的時(shí)候,進(jìn)行多次split。

相關(guān)函數(shù)分析:

lfs_dir_split(lfs_t *lfs,
| lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount,
| lfs_mdir_t *source, uint16_t split, uint16_t end)
| // 1. 重新分配新的塊,用來(lái)存儲(chǔ)split后的數(shù)據(jù)
|-> lfs_dir_alloc(lfs, &tail);
|
| // 2. 將split部分?jǐn)?shù)據(jù)再進(jìn)行compact操作
| // 該調(diào)用會(huì)遞歸調(diào)用compact和split操作直到commit完成或失敗
|-> lfs_dir_compact(lfs, &tail, attrs, attrcount, source, split, end);
|
| // 3. 更新目錄信息
|-> dir->tail[0] = tail.pair[0];
| dir->tail[1] = tail.pair[1];
| dir->split = true;

四、異常情況

前文中提到每次commit之后,都會(huì)寫(xiě)入計(jì)算的CRC tag,用于校驗(yàn)。commit過(guò)程因此也是一次原子操作。當(dāng)commit過(guò)程中發(fā)生掉電等情況導(dǎo)致commit過(guò)程失敗時(shí),磁盤(pán)中元數(shù)據(jù)末尾雖然有寫(xiě)入的部分tag和數(shù)據(jù),但沒(méi)有最終的CRC tag,因此當(dāng)進(jìn)行tag的遍歷等操作時(shí)并不會(huì)將這次commit視為有效。compact過(guò)程和split過(guò)程中也類似,只要沒(méi)有最終寫(xiě)入CRC tag,便不會(huì)被視為完成一次commit。如下圖:

#littlefs原理分析#[二]commit機(jī)制-開(kāi)源基礎(chǔ)軟件社區(qū)

另外,當(dāng)split為多個(gè)塊時(shí),由前文中相關(guān)分析,compact和split會(huì)遞歸調(diào)用,并提前檢查塊大小是否滿足需求和分配相應(yīng)塊,最終寫(xiě)入多個(gè)塊。split過(guò)程時(shí)若沒(méi)有足夠的塊,則會(huì)報(bào)錯(cuò),且并不寫(xiě)入實(shí)際內(nèi)容。split過(guò)程時(shí)若中途commit失敗,則會(huì)導(dǎo)致上一個(gè)元數(shù)據(jù)塊末尾的HARDTAIL指向的塊中沒(méi)有有效的CRC tag,進(jìn)行遍歷時(shí)會(huì)直接返回錯(cuò)誤,如下圖:

#littlefs原理分析#[二]commit機(jī)制-開(kāi)源基礎(chǔ)軟件社區(qū)

總結(jié)

本文介紹了littlefs中的commit機(jī)制,包括commit、compact、split操作的過(guò)程,怎樣寫(xiě)入tag和數(shù)據(jù),怎樣計(jì)算CRC,以及相應(yīng)的異常情況處理等。commit是一個(gè)寫(xiě)入元數(shù)據(jù)的過(guò)程,后面的文章將會(huì)介紹怎樣讀取元數(shù)據(jù),從tag中獲取目標(biāo)信息。

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

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

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

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

2022-11-07 15:27:07

LittlefsFetch操作

2022-11-15 09:24:16

littlefs文件讀寫(xiě)

2022-11-09 08:52:57

littlefs目錄操作

2022-11-22 15:21:55

littlefs磨損均衡

2022-10-27 16:07:24

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

2012-12-03 16:57:37

HDFS

2021-12-06 14:52:08

動(dòng)畫(huà)Android補(bǔ)間動(dòng)畫(huà)

2021-12-08 06:53:28

Choreograph屏幕機(jī)制

2009-11-13 17:20:35

ADO.NET數(shù)據(jù)集工

2023-10-30 01:02:56

Java類類加載器雙親委派

2010-05-19 13:29:59

2011-07-18 14:08:08

2021-11-11 17:40:08

WatchdogAndroid源碼分析

2016-11-11 00:39:59

Java可見(jiàn)性機(jī)制

2023-06-07 15:25:19

Kafka版本日志

2021-12-01 18:36:35

屬性

2020-01-06 10:58:18

JvmGC機(jī)制虛擬機(jī)

2023-10-31 16:00:51

類加載機(jī)制Java

2014-07-18 11:11:16

SEAndroid

2011-08-24 16:59:59

LuaModule
點(diǎn)贊
收藏

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