美文网首页
小文件分析 - (一)

小文件分析 - (一)

作者: 5dplay | 来源:发表于2021-07-25 19:34 被阅读0次

    主要参考:

    • 1、《SQLite数据库文件格式全面分析.doc 》,链接不详,只是能再网上各个文库上找到此文档。
    • 2、官网文档 Database File Format

    前提准备

    准备好文件

    在win10环境下

    PS G:\code-2\sqlite3> ./sqlite3 small.db
    SQLite version 3.28.0 2019-04-16 19:49:53
    Enter ".help" for usage hints.
    sqlite> CREATE TABLE department(id int, dept char(30), emp_id int);
    sqlite> insert into department values(1, "test", -1);
    sqlite> insert into department values(2, "test", 1);
    sqlite> .qu
    

    准备一些小工具

    从sqlite官网下载的源码中的tool目录中有一些十分有用的小工具,例如showdbshowwal等,它们都是单个源文件组成,结合官网提供的sqlite-amalgamation-xxx.zip提供的sqlite3.hsqlite3.c就可以编译出来。例如showdb是由showdb.c编译出来的:gcc -g -O0 -o showdb showdb.c sqlite3.c,调试和编译优化选项看个人喜欢,可加可不加。

    最最基础的概念

    首先要明白三点:

    • sqlite3数据库是由单个文件组成的,而这个文件被称为主数据库文件main database file。这个文件又是由多个页page组成,页按顺序编号,从1开始。sqlite上层的b树最小组成单位就是页,至于如何存储,如何查找等我写完就差不多弄清楚了。还有页的分类都是后话,所有底层设计都是为了上层服务的,个人理解的时候要会把握关键的思路,再慢慢理顺细节。
    • 存储在文件中的数据格式全部都是大端格式,为什么是大端呢?不清楚,就像网络字节序也是用大端存储,不过大端存储在调式的时候有个明显的优势就是符合人类阅读习惯。
    • sqlite_schema 是一个特殊的表(别名有很多,例如sqlite_master),它存放着其余表对应所在的根页号,具体定义如下:
    CREATE TABLE sqlite_schema(
      type text,
      name text,
      tbl_name text,
      rootpage integer,
      sql text
    );
    

    开始分析这个小文件

    文件头

    主数据库文件的前100个字节即是文件头。格式官网也给出了:

    Offset Size Description
    0 16 The header string: "SQLite format 3\000"
    16 2 The database page size in bytes. Must be a power of two between 512 and 32768 inclusive, or the value 1 representing a page size of 65536.
    18 1 File format write version. 1 for legacy; 2 for WAL.
    19 1 File format read version. 1 for legacy; 2 for WAL.
    20 1 Bytes of unused "reserved" space at the end of each page. Usually 0.
    21 1 Maximum embedded payload fraction. Must be 64.
    22 1 Minimum embedded payload fraction. Must be 32.
    23 1 Leaf payload fraction. Must be 32.
    24 4 File change counter.
    28 4 Size of the database file in pages. The "in-header database size".
    32 4 Page number of the first freelist trunk page.
    36 4 Total number of freelist pages.
    40 4 The schema cookie.
    44 4 The schema format number. Supported schema formats are 1, 2, 3, and 4.
    48 4 Default page cache size.
    52 4 The page number of the largest root b-tree page when in auto-vacuum or incremental-vacuum modes, or zero otherwise.
    56 4 The database text encoding. A value of 1 means UTF-8. A value of 2 means UTF-16le. A value of 3 means UTF-16be.
    60 4 The "user version" as read and set by the user_version pragma.
    64 4 True (non-zero) for incremental-vacuum mode. False (zero) otherwise.
    68 4 The "Application ID" set by PRAGMA application_id.
    72 20 Reserved for expansion. Must be zero.
    92 4 The version-valid-for number.
    96 4 SQLITE_VERSION_NUMBER

    对应的小文件分析可以用showdb可知:

    PS G:\code-2\sqlite3> ./showdb small.db dbheader
    Pagesize: 4096
    Available pages: 1..2
     000: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
     010: 10 00 01 01 00 40 20 20 00 00 00 03 00 00 00 02 .....@  ........
     020: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................
     030: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
     040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
     050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ................
     060: 00 2e 34 20 00                                  ..4 .
    Decoded:
     010: 10 00              4096  Database page size
     012: 01                    1  File format write version
     013: 01                    1  File format read version
     014: 00                    0  Reserved space at end of page
     018: 00 00 00 03           3  File change counter
     01c: 00 00 00 02           2  Size of database in pages
     020: 00 00 00 00           0  Page number of first freelist page
     024: 00 00 00 00           0  Number of freelist pages
     028: 00 00 00 01           1  Schema cookie
     02c: 00 00 00 04           4  Schema format version
     030: 00 00 00 00           0  Default page cache size
     034: 00 00 00 00           0  Largest auto-vac root page
     038: 00 00 00 01           1  Text encoding
     03c: 00 00 00 00           0  User version
     040: 00 00 00 00           0  Incremental-vacuum mode
     044: 00 00 00 00           0  Application ID
     048: 00 00 00 00           0  meta[8]
     04c: 00 00 00 00           0  meta[9]
     050: 00 00 00 00           0  meta[10]
     054: 00 00 00 00           0  meta[11]
     058: 00 00 00 00           0  meta[12]
     05c: 00 00 00 03           3  Change counter for version number
     060: 00 2e 34 20     3028000  SQLite version number
    

    页大小 (Database page size)

    在0x10偏移处,规定了页的大小,取值必须是2的幂次方,范围为[512, 65536],这里有点小细节可以参考官网文档可知。

    文件格式版本(File format write/read version)

    现在仅存在1和2两种,分别代表Hot journalWAL journal。小文件分析时候采用的是前者。

    页的保留空间大小 (Reserved space at end of page)

    保留空间是在页的尾部开始,其的用途例如在加密插件启用的时候,存储nonce值或者页面的校验和。一般来说这个字段一般为0。

    Payload Fraction

    0x21-23是连续的页内每个单元占用的百分比,以255为分母,这三个值64\32\32分别做分子,可得到对应的百分比25%,12.5%,12.5%。前两个是给index使用的,分别表示最大和最小值,后一个是给table b-tree leaf page的最小值,其最大值是是pagesize - 35

    文件修改次数计数器(File change counter)

    统计每一次修改数据库文件,到目前为止,我们先是创建表一次,两次独立(相当于两次事务)的插入操作,所以总共修改了文件3次。

    当前数据库页的数目(Size of database in pages)

    字面意思,不过历史版本上对其处理还是有不一样的,这个值会需要进一步的和数据库文件大小相比较,如果不一致则采用具体的数据库文件大小。

    空闲页

    这里开始涉及到页的分类了,先简单的理解一下空闲页。它的存在是因为数据库在进行删除操作的时候,导致整一页的数据都被清除掉了,此时就要把该页添加入空闲页链表。
    这个链表在文件中的存储方式,是隐式链表,也就是页头会存放着指向下一个空闲页的下标。而第一个空闲页则由主数据库文件的文件头给出。
    回到我们的小文件分析,此时我们的数据库没有多余的页,所以Page number of first freelist page == 0,0可以理解为c语言中的NULL,并且空闲页数目也等于0

    Schema cookie

    这里的Schema,中文翻译怎么都不太恰当。它是整个数据库所有表的总和,而这cookie则是一个整数,每次Schema发生改动(也就是发生表的增删改操作)就自增。这里一个相关的使用场景就是调用sqlite3_step的时候会去检查schema是否发生变化。

    Schema format number

    它代表着schema不同历史时期的功能支持程度,可以见官网描述。这里直接摘抄原文,现在默认是用版本4。

      1. Format 1 is understood by all versions of SQLite back to version 3.0.0 (2004-06-18).
      1. Format 2 adds the ability of rows within the same table to have a varying number of columns, in order to support the ALTER TABLE ... ADD COLUMN functionality. Support for reading and writing format 2 was added in SQLite version 3.1.3 on 2005-02-20.
      1. Format 3 adds the ability of extra columns added by ALTER TABLE ... ADD COLUMN to have non-NULL default values. This capability was added in SQLite version 3.1.4 on 2005-03-11.
      1. Format 4 causes SQLite to respect the DESC keyword on index declarations. (The DESC keyword is ignored in indexes for formats 1, 2, and 3.) Format 4 also adds two new boolean record type values (serial types 8 and 9). Support for format 4 was added in SQLite 3.3.0 on 2006-01-10.

    Default page cache size

    默认的页缓存大小,只是一个建议,实际上由程序自己判断

    Incremental vacuum settings

    Largest auto-vac root pageIncremental-vacuum mode 都是vacuum相关的设置,前者是auto_vacuum模式使用,后者是incremental_vacuum模式使用。当前者等于0时候,ptrmap类型的页将会被从数据库文件中剔除,并且这两种模式都不会被支持。当前者不为0的时候,它指向的是最大的根页,储存着许多ptrmap类型的页,并且此时由后者控制是auto_vacuum还是incremental_vacuum

    文本编码 Text encoding

    • 1 for UTF-8
    • 2 for UTF16LE
    • 3 for UTF16BE

    User version

    这是给用户使用的版本号,sqlite3 并不使用它。这好像在系统升级的时候确实有用

    Application ID

    这个也是留给用户使用的,表示当前是由那个进程在使用。这个用处没这么大。

    sqlite3 库使用的版本

    Change counter for version numberSQLite version number,在0x5c和0x60存放的是sqlite3.so/sqlite3.dll在使用此数据库文件时候,存放的版本号,并且自增修改次数。用途不太明确,但是应该用来判断是否有不同版本的sqlite3库修改此文件吧。

    相关文章

      网友评论

          本文标题:小文件分析 - (一)

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