DuckDB Internals: Visión General del Formato de Archivo
DuckDB es conocido por su alto rendimiento en consultas. No obstante, debido a su relativamente corta historia de desarrollo, hay pocos artículos que analicen en profundidad sus diversos módulos. Esta serie de artículos desmenuzará DuckDB desde el nivel del código fuente. El presente artículo, como el primero en la serie de análisis del código fuente de DuckDB, comenzará presentando el formato de archivo, enfocándose en el almacenamiento de metadatos, mientras que los artículos subsiguientes examinarán el almacenamiento de datos de tabla. Todo el análisis en este artículo se basa en el código fuente de la versión 1.3.1 de DuckDB, y el resumen se encuentra al final del artículo.
Descripción General del Formato de Archivo
Normalmente, todos los datos de las tablas en DuckDB se almacenan en un solo archivo, y el formato es bastante simple, compuesto por tres tipos de bloques:
- Bloque de Cabecera Principal: Ubicado al principio, tamaño de 4KB, contiene información de versión.
- Bloque de Cabecera de Base de Datos: Hay dos, cada uno de 4KB, utilizados alternativamente. La rotación ocurre durante el Checkpoint de DuckDB, donde se almacena un puntero a los metadatos.
- Bloque de Datos: El bloque regular utilizado para almacenar tanto metadatos como datos, de diferentes maneras. Su tamaño es de 256KB, y los IDs de bloque se asignan comenzando desde 0.
Introducción al Formato de Bloque de Cabecera
La introducción anterior reveló que hay dos tipos de bloques de cabecera: el bloque de cabecera principal y el bloque de cabecera de base de datos, ambos de 4KB. Esto se debe a que los sistemas de archivos modernos y los discos generalmente soportan escrituras atómicas de 4KB. La escritura atómica del bloque de cabecera de base de datos es clave para el mecanismo de Checkpoint de DuckDB, que será introducido en artículos futuros. Este artículo se centrará en el formato del archivo en sí.
Bloque de Cabecera Principal
- Checksum (0~7B): Presente en cada bloque, los primeros 8B se utilizan para verificar la integridad de los datos.
- Bytes Mágicos (8~11B): Estos son DUCK, indicando el tipo de archivo.
- Número de Versión (12~19B): Indica la versión.
- Flags0-3 (20~51B): Flags.
- DUCKDB_VERSION; DUCKDB_SOURCE_ID: Información de versión.
Bloque de Cabecera de Base de Datos
- Checksum (0~7B): Utilizado para la verificación de datos.
- Iteración (8-15B): Este campo se utiliza para la comparación entre el Bloque de Cabecera de Base de Datos 0 y el Bloque de Cabecera de Base de Datos 1, el encabezado con un valor más alto es el cabecera activa actual.
- Puntero del Bloque Meta (16~23B): Apunta al bloque meta que registra todas las entradas del catálogo (esencialmente el diccionario de datos de DuckDB).
- Puntero del Bloque de Lista Libre (24~31B): Apunta al bloque meta que registra la lista libre (gestiona bloques libres).
- Conteo de Bloques (32B~39B): El ID de bloque más grande actualmente asignado.
- Tamaño del Bloque (40~47B): Por defecto es 262144=256KB.
- Tamaño del Vector (48~55B): Por defecto es 2048.
- Compatibilidad de Serialización (56~63B): Por defecto es 1, relacionado con la compatibilidad de versiones.
Almacenamiento de Metadatos
En DuckDB, hay numerosos lugares que involucran el almacenamiento de metadatos, que en última instancia se almacenan en archivos utilizando bloques meta. Cada bloque de datos es de 256KB, pero cada bloque meta es solo de 4088B. Cada 64 bloques meta comparten un bloque de datos de 256KB, organizados de manera compacta.
¿Qué sucede si los metadatos exceden 4088B?
La respuesta a esta pregunta radica en el formato del bloque meta en sí. Un bloque meta de 4088B consiste en un puntero de bloque meta de 8B y 4080B de contenido. A través de punteros, múltiples bloques meta pueden ser vinculados en una cadena, con un valor de puntero de -1 indicando el final de la cadena.
DuckDB tiene los siguientes metadatos típicos, cada uno correspondiente a una cadena de bloque meta independiente:
- Catálogo: Esencialmente el diccionario de datos de DuckDB, almacenando todos los esquemas, tablas, etc.
- Lista Libre: Almacena la distribución de bloques libres dentro del archivo.
- Versión de Fila: Los datos de fila dentro de las tablas requieren almacenar marcas de tiempo para los datos insertados o eliminados.
Escritura de Catálogo y Lista Libre en el Archivo
El proceso de escritura de metadatos está fuertemente asociado con el mecanismo de Checkpoint, que necesita ser introducido junto con el proceso de Checkpoint. El flujo general está asociado a la función SingleFileCheckpointWriter::CreateCheckpoint, donde se registra el catálogo y la lista libre.
Resumen
En resumen, un archivo de DuckDB consiste en 3 bloques de cabecera de 4KB más varios bloques de datos de 256KB cada uno. La escritura y lectura de metadatos y su almacenamiento se realiza mediante un proceso de serialización y deserialización. En este artículo se ha centrado en los procesos de escritura del catálogo y de la lista libre, y el almacenamiento del formato de datos de tabla será introducido en el próximo artículo.
Nota: Este contenido original ha sido modificado con IA y revisado por un especialista. Imagen generada por IA.












