<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                MongoDB 的 mongod 服務管理一個數據目錄,可包含多個DB,每個DB的數據單獨組織,本文主要介紹 MMAPv1 存儲引擎的數據組織方式。 ## Database 每個 Database(DB) 由一個.ns文件及若干個數據文件組成 ~~~ $ll mydb.* -rw------- 1 ydzhang staff 67108864 7 4 14:05 mydb.0 -rw------- 1 ydzhang staff 16777216 7 4 14:05 mydb.ns ~~~ 數據文件從0開始編號,依次為mydb.0、mydb.1、mydb.2等,文件大小從64MB起,依次倍增,最大為2GB。 ## Namespace 每個 DB 包含多個 namespace(對應 mongodb 的 collection 名),mydb.ns實際上是一個hash表(采用線性探測方式解決沖突),用于快速定位某個 namespace 的起始位置。 hash表里的一個節點包含的元數據結構如下,每個節點大小為 628Bytes,16M 的 NS 文件最多可存儲26715個 namespace。 ~~~ struct Node { int hash; Namespace key; NamespaceDetails value; }; ~~~ * key 為 namespace 的名字,為固定長度128字節的字符數組; * hash 為 namespce 的 hash 值,用于快速查找; * value 包含一個 namespace 所有的元數據。 namespace元數據結構如下: ~~~ class NamespaceDetails { DiskLoc firstExtent; // 第一個extent位置 DiskLoc lastExtent; // 最后一個extent位置 DiskLoc deletedListSmall[SmallBuckets]; // 不同大小的刪除記錄列表 ... }; ~~~ 其中 DiskLoc 代表某個數據文件的具體偏移位置,數據文件使用 mmap 映射到內存空間進行管理,內存的管理(哪些數據何時換入/換出)完全交給OS管理。 ~~~ class DiskLoc { int _a; // 數據文件編號,如mydb.0編號為0 int ofs; // 文件內部偏移 }; ~~~ ## 數據文件 每個數據文件被劃分成多個extent,每個 extent 只包含一個 namespace 的數據,同一個 namespace 的所有 extent 之間以雙向鏈表形式組織。 namesapce 的元數據里包含指向第一個及最后一個 extent 的位置指針,通過這些信息,就可以遍歷一個 namespace 下的所有 extent 數據。 每個數據文件包含一個固定長度頭部DataFileHeader: ~~~ class DataFileHeader { DataFileVersion version; int fileLength; DiskLoc unused; int unusedLength; DiskLoc freeListStart; DiskLoc freeListEnd; char reserve[]; }; ~~~ Header 中包含數據文件版本、文件大小、未使用空間位置及長度、空閑 extent 鏈表起始及結束位置。extent被回收時,就會放到數據文件對應的空閑 extent 鏈表里。 unusedLength 為數據文件未被使用過的空間長度,unused 則指向未使用空間的起始位置。 ## Extent 每個 extent 包含多個 record(對應 mongodb 的 document),同一個 extent 下的所有 record 以雙向鏈表形式組織。 ~~~ struct Extent { unsigned magic; // 用于檢查extent數據有效性 DiskLoc myLoc; // extent自身位置 /* 前一個/后一個 extent位置指針 */ DiskLoc xnext; DiskLoc xprev; int length; // extent總長度 DiskLoc firstRecord; // extent內第一個record位置指針 DiskLoc lastRecord; // extent內最后一個record位置指針 char _extentData[4]; // extent數據 }; ~~~ ## Record 每個Record對應mongodb里的一個文檔,每個Record包含固定長度16bytes的描述信息。 ~~~ class Record { int _lengthWithHeaders; // Record長度 int _extentOfs; // Record所在的extent位置指針 int _nextOfs; // 前一個Record位置信息 int _prevOfs; // 后一個Record位置信息 char _data[4]; // Record數據 }; ~~~ Record被刪除后,會以 DeleteRecord 的形式存儲,其前兩個字段與 Record 是一致的。 ~~~ class DeletedRecord { int _lengthWithHeaders; // record長度 int _extentOfs; // record所在的extent位置指針 DiskLoc _nextDeleted; // 下一個已刪除記錄的位置 }; ~~~ 一個 namespace 下的所有的已刪除記錄(可以回收并復用的存儲空間)以單向鏈表的形式,為了最大化存儲空間利用率,不同size(32B、64B、128B…)的記錄被掛在不同的鏈表上,NamespaceDetail 里的 deletedListSmall/deletedListLarge 包含指向這些不同大小鏈表頭部的指針。 ![](https://box.kancloud.cn/2016-04-11_570b48208f65a.jpg) MongoDB storage format ### 寫入Record 1. 檢查對應的namespace 對應的刪除記錄鏈表里是否有合適的 DeletedRecord 可以利用,如果有,則直接復用刪除空間寫入記錄; 2. 檢查數據文件的 freeList 里是否有合適大小的空閑 extent 可以利用,如果有則直接利用空閑的extent,將記錄寫入; 3. 第1、2步都不成功,則寫創建新的 extent 寫入記錄;創建新extent時,如果當前的數據文件沒有足夠的空閑空間,則創建新的數據文件。 ### 刪除Record 刪除的記錄會以 DeleteRecord 的形式插入到對應集合的刪除鏈表里,刪除的空間在下一次寫入新的記錄時可能會被利用上;但也有可能一直用不上而浪費。比如某個128Bytes大小的記錄被刪除后,接下來寫入的記錄一直大于128B,則這個128B的 DeletedRecord 不能有效的被利用。 當刪除很多時,可能產生很多不能重復利用的“存儲碎片”,從而導致存儲空間大量浪費;可通過對集合進行?[compact](http://docs.mongodb.org/manual/reference/command/compact/)來整理存儲碎片。 ### 更新Record 更新Record時,分2種情況 1. 更新的Record比原來小,可以直接復用現有的空間(原地更新);多余的空間如果足夠多,會將剩余空間插入到DeletedRecord鏈表; 2. 更新的Record比原來大,更新相當于刪除 + 新寫入,原來的空間會插入到DeletedRecord鏈表里。 更新跟刪除類似,也有可能產生很多存儲碎片;如果業務場景里更新很多,可通過合理設置?[Record Padding](http://docs.mongodb.org/v2.4/core/record-padding/),盡量讓每次更新都直接復用現有存儲空間。 ### 查詢Record 沒有索引的情況下,查詢某個Record需要遍歷整個集合,讀取出符合條件的Record;如果經常需要根據每個緯度查詢Record,則需要給集合建立索引以提高查詢效率。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看