美文网首页LevelDb
LevelDb之manifest文件

LevelDb之manifest文件

作者: ieasy_tm | 来源:发表于2017-08-21 20:51 被阅读137次

    从这篇文章开始想写写leveldb的小知识。先了解manifest文件,因为这个文件关系到实例的读取。至于这个文件的内部结构以及如何来的,等会再聊。

    if instances[Name], err = leveldb.OpenFile(Dir, instance); err != nil {
            return errors.New(fmt.Sprintf(`leveldbs: err while open %s : %s`, Dir, err.Error()))
    }
    

    这段代码在manifest文件损坏的情况下会出现报错,报错内容:

    ERROR leveldb: manifest corrupted: missing [file=MANIFEST-*******]
    

    报错原因:leveldb在存储过程中因为一些其他原因导致程序突然的down掉可能导致manifest文件损害或者丢失。这样就只能手动repair下了,打不开一个instance 就没有办法执行get命令。repair的业务方代码可以这样写,这里以Golang代码来说明:

    if instances[cfgIns.Name], err = leveldb.OpenFile(Dir, instance); err != nil {
        if instances[cfgIns.Name], err = leveldb.RecoverFile(Dir, instance); err != nil {
            return errors.New(fmt.Sprintf(`err while recoverfile%s : %s`, Dir, err.Error()))
        }
    }
    

    RecoverFile 这个API函数的源码是:

    func RecoverFile(path string, o *opt.Options) (db *DB, err error) {
        stor, err := storage.OpenFile(path)
        if err != nil {
            return
        }
        db, err = Recover(stor, o)
        if err != nil {
            stor.Close()
        } else {
            db.closer = stor
        }
        return
    }
    

    manifest文件修复还是蛮简单的,说明Google的大神早就想到了这些东西。通过上面的例子先感受下manifest文件的存在,下面我们学习下manifest文件结构和文件的由来。文件结构如图:


    manifest.png

    再配合Golang中定义的struct看看:

    type session struct {
        stNextFileNum    uint64 // current unused file number
        stJournalNum     uint64 // current journal file number; need external synchronization
        stPrevJournalNum uint64 // prev journal file number; no longer used; for compatibility with older version of leveldb
        stSeqNum         uint64 // last mem compacted seq; need external synchronization
        stTempFileNum    uint64
    
        stor     storage.Storage
        storLock util.Releaser
        o        *cachedOptions
        icmp     *iComparer
        tops     *tOps
    
        manifest       *journal.Writer
        manifestWriter storage.Writer
        manifestFile   storage.File
    
        stCompPtrs []iKey   // compaction pointers; need external synchronization
        stVersion  *version // current version
        vmu        sync.Mutex
    }
    

    manifest文件存放versionset(版本集合信息)。versionset是一个链表,每个节点就是一个versionversion中主要包含有.sstable文件大小,文件编号,有序值的最大值和最小值等等信息。

    type tSet struct {
        level int
        table *tFile
    }
    type version struct {
        s *session
        tables []tFiles
        cLevel int
        cScore float64
        cSeek unsafe.Pointer
        ref int
        next *version
    }
    type tFile struct {
        file       storage.File
        seekLeft   int32
        size       uint64
        imin, imax iKey
    }
    

    好吧,manifest文件里面存放的东西大致上就这些了,下面聊聊manifest文件的创建和修改过程。这个问题还是有点难度的,这里还是以Golanggithub.com/syndtr/goleveldb/leveldb这个库为例来说明。newManifest是创建一个manifest, encode编码后写入文件,最后将manifest文件的名称写入到current文件中,current只记录当前的manifest文件的文件名称: _, err = fmt.Fprintln(w, f2.name())

    func (s *session) newManifest(rec *sessionRecord, v *version) (err error) {
        num := s.allocFileNum()
        file := s.stor.GetFile(num, storage.TypeManifest)
        writer, err := file.Create()
        if err != nil {
            return
        }
        jw := journal.NewWriter(writer)
    
        if v == nil {
            v = s.version()
            defer v.release()
        }
        if rec == nil {
            rec = &sessionRecord{}
        }
        s.fillRecord(rec, true)
        v.fillRecord(rec)
    
        defer func() {
            if err == nil {
                s.recordCommited(rec)
                if s.manifest != nil {
                    s.manifest.Close()
                }
                if s.manifestWriter != nil {
                    s.manifestWriter.Close()
                }
                if s.manifestFile != nil {
                    s.manifestFile.Remove()
                }
                s.manifestFile = file
                s.manifestWriter = writer
                s.manifest = jw
            } else {
                writer.Close()
                file.Remove()
                s.reuseFileNum(num)
            }
        }()
    
        w, err := jw.Next()
        if err != nil {
            return
        }
        err = rec.encode(w)
        if err != nil {
            return
        }
        err = jw.Flush()
        if err != nil {
            return
        }
        err = s.stor.SetManifest(file)
        return
    }
    

    一边学习,一边记录,end ~

    相关文章

      网友评论

        本文标题:LevelDb之manifest文件

        本文链接:https://www.haomeiwen.com/subject/fhbhdxtx.html