LevelDb之manifest文件

从这篇文章开始想写写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中比较重要的内容。本文首先介绍其在整个LevelDB中不可替代的作用;之后从...
    CatKang阅读 5,543评论 12 12
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,032评论 19 139
  • LevelDB是Google传奇工程师Jeff Dean和Sanjay Ghemawat开源的KV存储引擎,无论从...
    CatKang阅读 4,873评论 5 25
  • 9.1 基本原理 版本信息有什么用?先来简要说明三个类的具体用途: Version:代表了某一时刻的数据库版本信息...
    随安居士阅读 2,653评论 0 3
  • 现在,我还难以平复因恒大夺冠而欣喜若狂的心情!这场比赛我看的很投入,不亚于在看台上的激动!只是在我因门将曾诚受...
    一颗柠檬半杯水阅读 323评论 0 0