• ubifs核心功能 -- 垃圾回收



    可回收空间的分类

        垃圾回收的目的是再利用(回收后的空间大小能写入有效的node),如果再利用的价值越低,其回收的必要性越低。为了进行有效的垃圾回收,UBIFS对可回收空间做了2个层次的水线划分:
        死空间水线,即最小node大小(一般是最小的data node):dead_wm = ALIGN(MIN_WRITE_SZ, min_io_size); 
        暗空间水线,即最大node大小(一般是最大的inode node):dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, min_io_size);  
        一般来说, min_io_size(page or subpage) <= dead_wm <= dark_wm。在我们的系统上,dead_wm和dark_wm的水线都是一个page的大小(8K)
     
        free + dirty < dead_wm时,此时认为垃圾很少,一般就认为此LEB full,不值得进行垃圾回收。
          free + dirty < dark_wm时,因为可回收的空间较小,dark_wm被回收的概率也变小。同时为了效率和节约空间考虑,这种leb也不会被加入到内存LPT树中。如果可回收空间小于dark_wm,这段空间的回收价值就不大。所以也得出一个结论:node越大,浪费的空间越大。
     

    可回收对象的分类

              因为index node和非index node的管理方式不一样,垃圾回收需要对这2类对象进行区分处理。
              非index node的管理方式为 wbuf - flash 2层结构,比较简单。在ubifs_garbage_collect_leb(BG GC)或者ubifs_gc_start_commit(Commit GC第一阶段)阶段unmap LEB完成回收;
              index node的管理方式为 TNC - journal - flash 4层结构,相对复杂。在ubifs_garbage_collect_leb(BG GC)或者ubifs_gc_start_commit(Commit GC第一阶段)阶段完成准备,在ubifs_gc_end_commit (Commit GC第二阶段)阶段unmap LEB完成回收,所有被垃圾回收的index leb加入到链表idx_gc中,这个链表中的leb在ubifs_gc_end_commit阶段unmap。
     

    垃圾回收(后台进程阶段

              后台垃圾回收由background线程负责,由wbuf定时器定时唤醒,并判断是否需要进行垃圾回收,如是,启动垃圾回收操作。正常情况下,每次垃圾回收操作回收UBIFS_GC_ONCE(5)个LEB。
              回收的leb最后被unmap,并且标记为空(bud->start 设置为 0),再次使用时,会重新map。LEB unmap-map重新映射流程,UBI根据磨损均衡算法进行重新map,达到PEB磨损平衡的效果。同时也避免了反复使用一个PEB的情况。
              垃圾回收时垃圾LEB上有效的数据会搬运到gc wbuf->lnum对于的LEB上,gc_lnum作为后备的垃圾回收目的LEB,如果gc的wbuf->lnum无效,取gc_lnum作为gc wbuf->lnum,并置c->gc_lnum无效(switch_gc_head)。通过gc_lnum,保证在垃圾回收时,不会出现找不到搬运目的LEB的情况(即gc wbuf->lnum)。

    垃圾回收判断准则:

                   检查gc水线设置gc_waterline, 只有当总的脏空间lst.total_dirty > 分卷总大小/gc_waterline时,才进行GC,避免在空闲空间较多的情况下进行gc。gc_waterline默认为UBIFS_FREE_RESERVE_RATIO(5)。
              而且,对于index node,ubifs对于index的回收是只回收脏空间大于一半擦除块的,其他index擦除块可能即使有脏空间也不会进行回收。

    垃圾回收流程:

              1)判断是否需要commit,如是,返回-EAGAIN,触发commit流程
              2)已经回收了index LEB并且gc已连续尝试SOFT_LEBS_LIMIT(4)次,返回-EAGAIN
              3)如果gc已连续尝试HARD_LEBS_LIMIT(32)次,返回-ENOSPC
              4)查找dirty LEB进行回收(查找顺序依次是lpt_heap[LPROPS_DIRTY_IDX], lpt_heap[LPROPS_DIRTY], lpt_heap[LPROPS_FREE],c->uncat_list,LPT in flash)
              5)读取dirty LEB的node,并进行排序、分类、丢弃过时数据和无需搬运数据等处理
              6)搬运数据到gc wbuf对应的LEB(gc LEB),回收垃圾LEB,这里区分index LEB和非index LEB详细流程见下
              7)如果回收的是非index LEB,此次GC结束
              8)如果回收的是index LEB,继续GC
              9)已经回收过多次还没有回收成功,说明每次回收的块都用于gc自己(因为GC需要始终占用一块free的LEB,用来作为搬运的目地LEB,即gc LEB),而且当前用于gc回收的leb空间没有更多。这里就尝试找更脏的leb,因为这样的LEB上的有效数据少,回收这样的leb需要的空间就要小些。
              10)同步gc wbuf,unmap gc LEB(c->gc_lnum)
              11)更新LPT树          

    搬运数据,回收LEB详细流程

    可全部回收的 leb(free + dirty == leb_size):sync,然后unmap

              1)如果不是全free的leb,将data和index wbuf写到对应的flash LEB。避免GC后,wbuf又把obsoleting nodes写入flash。然后再更新LEB lprops并将此LEB加入到c->frdi_idx_list(index LEB)或c->freeable_list(data LEB)。
              2)unmap回收LEB
              3)如果c->gc_lnum无效,将回收的lnum作为c->gc_lnum,然后返回LEB_RETAINED。否则返回LEB_FREED。

    非index leb:搬运后再sync,然后unmap

              1)将有效node搬运到GC LEB的wbuf(c->jheads[GCHD].wbuf)
              2)为了保证垃圾回收的节点是存在flash的,同步data和index LEB的wbuf到flash。避免GC后,wbuf又把obsoleting nodes写入flash
              3)更新LEB lprops并将此LEB加入到c->freeable_list(data LEB)
              4)如果c->gc_lnum无效,将回收的lnum作为c->gc_lnum,然后返回LEB_RETAINED。否则,同步gc LEB的wbuf到flash,再unmap回收LEB,然后返回LEB_FREED。 

    index leb:更新idx_gc->list对象和c->frdi_idx_list对象,以备在end commit gc阶段使用

              1)遍历index leb中index node,将 index node加入到TNC,并将TNC中该节点对应路径设置为脏,commit的时候就会重新写入flash,在gc中就达到了搬运的目的;
              2)将此LEB加入到已经gc的index链表中 idx_gc->list。因为已经将这个index leb读取到TNC中,所以在下一次commit的时候会将这些读取到TNC中的index写入flash。但是不能立即unmap这个leb,因为commit还没有发生, 如果发生掉电,还需要保留这个index leb,用于恢复,否则发生掉电,这个index leb已经unmap,但又没有commit完成,则这个index leb上的数据就会丢失。
              3)更新LEB lprops并将此LEB加入到c->frdi_idx_list(index LEB),然后返回LEB_FREED_IDX。
     
     
     

    垃圾回收提交阶段

            提交阶段的垃圾回收,以commit为界,划分为2部分:ubifs_gc_start_commit和ubifs_gc_end_commit。
            ubifs_gc_start_commit:更新idx_gc->list对象和c->frdi_idx_list对象,以备在end commit gc阶段使用
                   1)unmap freeable_list LEB,更新lprops;
                   2)找出所有的frdi_idx_list LEB,并更新到idx_gc中;
            ubifs_gc_end_commit:unmap idx_gc LEB
                   此阶段前,已完成commit,所以可以放心地unmap所有的idx_gc LEB;
     
    至此,UBIFS文件系统垃圾回收流程完成。
    --EOF--
  • 相关阅读:
    MySQL数据透视功能
    MySQL 姓名两个字中间加两个空格
    Back To Basics: Clustered vs NonClustered Indexes; what’s the difference?
    炉石传说 佣兵战纪 贫瘠之地
    When to Use Clustered or NonClustered Indexes in SQL Server
    Stairway to SQL Server Indexes
    Why use the INCLUDE clause when creating an index?
    Clustered vs Nonclustered Index: Key Differences with Example
    SQL Server: Order of Rows
    Being Agile vs. doing Agile: What's the difference?
  • 原文地址:https://www.cnblogs.com/wahaha02/p/4656741.html
Copyright © 2020-2023  润新知