mongodb源码分析(九)mongodb的存储管理

1.  mongodb中能够保存的最大collection数目.

mongodb官网(Using a Large Number of Collections,)的信息如下:

By default MongoDB has a limit of approximately 24,000 namespaces per database. Each namespace is 628 bytes, the .ns file is 16MB by default.

Each collection counts as a namespace, as does each index.  Thus if every collection had one index, we can create up to 12,000 collections.  The --nssize parameter allows you to increase this limit (see below).

        但是我实际测试发现每一个namespace大小为496,而且并不是一个collection有一个index,collection
数目就得减半为12000,创建的前10个索引是保存到namespaces中的也就是程序代码中的结构namespaceDtails
中,如果一个collection上索引数目超过10个那么将分配一个namespaceDtails::extra结构保存索引.extra结构同样
为496字节,一个extra上最多能够保存30个索引.因为限制一个collection最多能有64个索引,所以一个collection最多
能够拥有2个extra,extra同样是保存在ns文件上的,那么可以算出默认下一个database能够保存的collection数目为
16M/496*3~16M/496大概为:[11275,33825].当然可以通过--nssize选项调整ns文件的大小,然后
db.repairDatabase()让一个数据库能够保存更多的集合.

2. mongodb的文件信息

        mongodb的存储文件分两部分.1是保存集合信息的xxx.ns,另一部分是保存具体数据的xxx.0,xxx.1.

默认xxx.ns文件为16M.其中保存了collection的头信息,具体见

mongodb源码分析(五)查询2之mongod的数据库加载,

xxx.0,xxx.1.......xxx.n这些数据文件的空间默认是从64M增长的,每一个文件都是前一个文件的2倍大小,直到2G,对于

32位系统单个文件最大为512M,如果指定了--smallfiles,则上面的空间大小依次除以4也就是16M,32M.......512M.

3. mongodb内部存储空间的分配.

        mongodb内部空间的分配是按照extent来分配的,当存储数据时,collection首先查找该collection是否还有空间,

有则分配空间,没有就申请一个extent.一个collection中extent是按照双向链表来组织的,其中namespace保存了头

和尾.


申请到的extent除头部信息外其余的空间将会被加入到一个deleteList的头部中,其结构如下:


这里每一个bucket中的可用数据大小在上面标注的范围到下一个bucket大小减一的范围内,如32其bucket内部保存

的可用空间长度就在[32,63].

       这里每次collection的空间分配就是根据要分配的空间大小来找到相应的bucket,然后遍历bucket,找到相应的

可用的空间,将分配空间后将剩余的空间作为一个新的结构加入到相应的bucket中.如果剩余的空间不足24字节或

者分配空间的1/8,那么这段空间将不再加入到对应的bucket中.这部分空间将被划入相应的document中,其在更新

数据时可能会用到.

       mongodb的最小数据存储单位是document,每当插入一条document时其内部分配空间,分配的空间除了

document本身占用的内存外还有一个document头如下:

        int _lengthWithHeaders;//该条文档和头部总大小
        int _extentOfs;//该条文档所在的extent位置
        int _nextOfs;//下一条文档所在位置
        int _prevOfs;//上一条文档所在位置
分配空间时首先向collection申请空间,其就遍历上面那一张表,如果没找到合适的空间那么collection将向
database申请一个extent,上面提到过.申请的extent空间是根据当前要存储的document大小以及前一个extent大
小计算出来的.document加上头部信息为:a.要申请的extent空间为len,前一个extent大小为prelen.则有:
len = a * 16;
if(len < 1000)
    len *= 64;
if(len > 1000000000)
    len = 1000000000;
len = len & 0xffffff00;//256字节对齐
int y = prelen < 4000000 ? prelen * 4.0 : prelen * 1.35;//一般按照前一个extent大小分配,前一个大小小于4M则按照4倍的大小扩展,否则按照1.35倍大小扩展
len = y > len ? y : len;
if(len > 0x7ff00000)//最大是一个文件的大小,当指定了--smallfiles则空间除以4
    len = 0x7ff00000;
        这里就得到了要分配的extent大小,然后再想database申请空间,database先从一个名叫$freelist的collection
(这个collection保存了释放的extent)查看是否有extent满足要求,没有则遍历xxx.0,xxx.1...xxx.n文件询问是否有足够
的空间,有则分配,没有就再分配一个文件xxx.n+1,然后从这个文件中分配该extent.
4. 索引的保存
        每一个索引对应于一个collection,如db.coll collection的索引{x:1,y:1},其索引保存到了collection: 
db.coll.$x_1_y_1.可以通过db.system.namespaces.find()查看当前有数据库中存在哪些collection.

原文地址: mongodb源码分析(九)mongodb的存储管理
作者: yhjj0108,杨浩




你可能感兴趣的:(mongodb源码分析(九)mongodb的存储管理)