zoukankan      html  css  js  c++  java
  • mongodb数据文件格式

    mongodb的数据文件存在dbpath选项指定的目录里。每个库(database)都有一系列的文件:dbname.ns, dbname.0, dbname.1, ...数据文件也叫pdfile,意思是Portable Data File。

    dbname.ns文件

    dbname.ns文件存储命名空间信息。在mongodb里,每个collection都具有一个命名空间,名字为dbname.collection_name。dbname.ns文件存储哈希表节点数组。

    struct Node {
        int hash;               // 根据key计算出来的hash值。如果大于0,则表示已经使用;等于0,则表示未使用
        Namespace key;          // 命名空间的名字,为128字节的char数组
        NamespaceDetails value; // 命名空间信息
    };
    View Code

    哈希节点目前大小是628字节,dbname.ns文件的默认大小是16M,一共可以存放26715个命名空间。nssize选项可以设置dbname.ns文件的大小。

    如何查找?
    n为数组大小,maxChain = (int) (n * 0.05),chain = 0
    a.根据key计算hash值(为一个大于0的整数)
    b.i = hash % n(n为数组大小),start = i,
    c.比较下标为i的节点的hash和key,如果相同则找到;如果不同,则i = (i + 1) % n,chain++, 继续比较
    d.如果i == start或者chain >= maxChain,则查找失败

    寻找空闲节点?
    a.根据key计算hash值(为一个大于0的整数)
    b.i = hash % n(n为数组大小),start = i
    c.如果下标为i的节点空闲,则返回。否则,i = (i + 1) % n,chain++,继续找
    d.如果i == start或者chain >= maxChain,则找不到

    实际上,mongodb把上述的2个操作合成一个操作,如果找不到节点,则返回第一个空闲节点。所以,当插入新的节点时,会查找maxChain次。

    示例代码

    打印一个库的所有命名空间

    dbname.<#>系列文件

    dbname.<#>系列文件存储了每个库的所有数据,其文件格式为

    --------------------------------------------
    DataFileHeader
    --------------------------------------------
    Extent (for a particular namespace)
    Record
    ...
    Record (some chained for unused space)
    --------------------------------------------
    more Extents...
    --------------------------------------------

    DataFileHeader是数据文件的头部,后面的部分为Extent。

    DiskLoc

    /** represents a disk location/offset on disk in a database.  64 bits.
      * it is assumed these will be passed around by value a lot so don't do anything to make them large
      * (such as adding a virtual function)
      */
    struct DiskLoc
    {
        int _a;     // this will be volume, file #, etc. but is a logical value could be anything depending on storage engine
        int ofs;
    };
    View Code

    DiskLoc表示数据文件的位置,_a为dbname.<#>文件的编号,ofs为在文件中的偏移,从0开始。

    DataFileHeader

    class DataFileHeader {
        public:
            int version;
            int versionMinor;
            int fileLength;
            DiskLoc unused; /* unused is the portion of the file that doesn't belong to any allocated extents. -1 = no more */
            int unusedLength;
            DiskLoc freeListStart;
            DiskLoc freeListEnd;
            char reserved[8192 - 4*4 - 8*3];
    
            char data[4]; // first extent starts here
    
            enum { HeaderSize = 8192 };
    };
    View Code

    unused字段是未分配空间的位置,unusedLength为未分配空间的大小。freeListStart和freeListEnd这2个字段比较特殊,只在dbname.0文件中才有效,存储了空闲Extent链表的头部Extent的位置和尾部Extent的位置。对于一个库来说,被删除的collection的所有Extent都会挂到这个空闲Extent链表中。

    可以利用这个特性来恢复被删除的collection,示例代码

    Extent

    class Extent {
        public:
            enum { extentSignature = 0x41424344 };
            unsigned magic;
            DiskLoc myLoc;
            DiskLoc xnext, xprev; /* next/prev extent for this namespace */
    
            /* which namespace this extent is for.  this is just for troubleshooting really
               and won't even be correct if the collection were renamed!
            */
            Namespace nsDiagnostic;
    
            int length;   /* size of the extent, including these fields */
            DiskLoc firstRecord;
            DiskLoc lastRecord;
            char _extentData[4];
    };
    View Code

    每个Extent本身是一个双向链表节点,xnext和xprev字段指向后继和前驱节点。Extent内的所有Record也组成一个双向链表,firstRecord指向头部Record,lastRecord指向尾部Record。

    Record

    class Record {
        public:
            enum HeaderSizeValue { HeaderSize = 16 };
    
        private:
    
            int _lengthWithHeaders;
            int _extentOfs;
            int _nextOfs;
            int _prevOfs;
    
            /** be careful when referencing this that your write intent was correct */
            char _data[4];
    };
    
    class DeletedRecord {
        private:
            int _lengthWithHeaders;
            int _extentOfs;
            DiskLoc _nextDeleted;
    };
    View Code

    _extentOfs字段表示Record所在Extent在数据文件中的偏移。属于同一个Extent的Record组成一个双向链表,_nextOfs和_prevOfs分别指向后继和前驱。

    DeletedRecord是一种特殊的Record,被删除的Record或者Extent中没有分配的空间,都会作为DeletedRecord。根据DeletedRecord的大小,形成19个单向链表,每个链表的表头存在命名空间信息里。

    文件空间的分配以Extent为单位。每个命名空间的所申请的Extent形成一个双向链表,表头和表尾存在命名空间信息里。Record在Extent里分配,每个Extent里的所有Record形成一个双向链表,表头和表尾存在Extent头部。可以想到,对命名空间的所有Record的遍历方法为:遍历Extent链表,对每个Extent,遍历其Record链表。空闲的Record(Extent里剩余的空间、或者Record被删除),称作DeleteRecord,根据其大小,形成19个单向链表(表头也存在命名空间里)。可以想到,申请一个Record的方法:先从空闲的Record里面找;如果找不到,则分配新的Extent。

    示例代码

    把一个collection的所有记录dump出来

  • 相关阅读:
    087 类的继承
    086 一切皆对象
    085 对象的绑定方法
    在菜鸟教程学 HTML(一)
    生成输出 URL(16.2)
    创建分部视图(7.6.3)
    显示页面链接(7.5.1)
    NuGet 控制台代码
    浏览器对应用程序的根URL发出请求时所发生的情况(结合 DI)
    第 6 章 —— 依赖项注入(DI)容器 —— Ninject
  • 原文地址:https://www.cnblogs.com/tripleH/p/2958147.html
Copyright © 2011-2022 走看看