MariaDB
Posts
-
Digging into MariaDB's Source 1: How I Read It with AI, and the Map
The first post of a series on reading the MariaDB server's source, starting with pictures and a 3-minute hands-on run that show what MariaDB is, how it works and what it is for. It covers which version is read (the main branch, 13.2.0 alpha) and how it differs from the LTS releases, how to get the same source including submodules and make a Debug build in Docker (including why the build broke on Windows because of CRLF), a folder map of the 2.59-million-line codebase, the big road one query travels from the connection thread to InnoDB as confirmed with a gdb backtrace, and how AI-written notes are re-checked against the source.
-
Digging into MariaDB's Source 2: The Big Picture — the Server Layer, Storage Engines, and the Life of One Query
The map for this series, written for intermediate developers opening the MariaDB source for the first time. Why the server layer (sql/) and the storage engines (storage/) are separate, what their boundary looks like — handler (one opened table) and handlerton (one table of function pointers per engine) — the path one SELECT takes from connection → THD → parsing → preparation → optimization → execution → handler → engine and back through Protocol, and MEM_ROOT, which throws all those objects away in one go after every statement. Checked against the real source and gdb backtraces.
-
Digging into MariaDB's Source 3: Startup and Plugins — Until mariadbd Takes Its First Connection
What happens between starting mariadbd and its first connection? We follow mysqld_main() in sql/mysqld.cc — how a line in my.cnf becomes a system variable, how plugin_init() registers and initializes everything as a plugin (even InnoDB and Aria), where ha_initialize_handlerton() lets an engine fill its handlerton, the signal thread and the poll() loop, and how shutdown runs startup in reverse — checked with the error log and gdb.
-
Digging into MariaDB's Source 4: Connections and Threads — One Thread per Connection, and the Thread Pool
We follow the source from the moment mariadbd's main thread accepts a connection with poll() and wraps it in a CONNECT, to the point where it hands it to the scheduler (a bundle of function pointers) chosen by thread_handling. We look at the default one-thread-per-connection mode and its thread cache, the login step that creates the THD and authenticates, and how the thread pool — thread groups, a listener, workers and a timer_thread — detaches idle connections from threads, checking each step with ps, information_schema and gdb, and comparing it with httpd's MPMs and Tomcat's endpoint.
-
Digging into MariaDB's Source 5: The Protocol and Command Dispatch — How One Packet Reaches dispatch_command
How the bytes a client sends become packets, how a single first byte decides between COM_QUERY, COM_PING and COM_STMT_EXECUTE, and how the result turns back into packets on the way out — followed through sql/net_serv.cc, do_command() and dispatch_command() in sql_parse.cc, and protocol.cc. We talk to the server directly over bash's /dev/tcp with no client library, and run the query cache to see why it can look up a result before the SQL is even parsed.
-
Digging into MariaDB's Source 6: The Parser — How an SQL Statement Becomes LEX and Item Trees
We follow one SQL statement from a plain string through the lexer (Lex_input_stream), where it becomes tokens, into the rule actions of the Bison-generated parsers (MYSQLparse and ORAparse), where it becomes LEX, SELECT_LEX, TABLE_LIST and Item trees. We look at the build rule that turns one grammar file into two parsers, the keyword table and state_map, and the place the "near '...' at line N" error comes from, then print the trees the parser leaves behind with a Bison trace and gdb.
-
Digging into MariaDB's Source 7: Preparation — Checking Privileges, Opening Tables, Resolving Names
We follow, in the source, the three things the server does with the parser's LEX before it plans anything. In mysql_execute_command()'s big switch, check_table_access() checks privileges; open_and_lock_tables() takes metadata locks and pulls TABLE_SHARE and TABLE out of their caches; JOIN::prepare() binds column names to Field objects. We watch column-privilege errors 1142 and 1143, Opened_tables and Table_open_cache_hits moving, an ALTER TABLE waiting behind an open transaction with a plain SELECT queued behind it, and the call stack that raises errors 1054 and 1052.
-
Digging into MariaDB's Source 8: The Optimizer — JOIN::optimize and Choosing a Plan
We follow, in the source, what the MariaDB optimizer does before a single line of EXPLAIN appears — the stages of JOIN::optimize() (tidying the conditions, estimating row counts, range analysis, searching join orders), the new cost model where 1 means one millisecond, how a histogram flips a plan, and where EXPLAIN and optimizer_trace come from — checking each with examples and gdb.
-
Digging into MariaDB's Source 9: Execution and the Handler API — How the Nested-Loop Join Calls the Engine
We follow, in the source, the place where the optimizer's plan actually reads rows. From JOIN::exec() into the nested loop of do_select(), sub_select() and evaluate_join_record(), through the read functions chosen for each EXPLAIN type and the join buffer, past the handler's ha_ wrappers, and down to ha_innobase::rnd_next() and write_row(). We count calls with the Handler_read_* status variables, confirm the whole path from do_command to the engine with one gdb backtrace, and see that switching the engine to MEMORY, Aria or BLACKHOLE still goes through the same spots.
-
Digging into MariaDB's Source 10: InnoDB Part 1 — Pages, the Buffer Pool and B-trees
We go below the handler and read, in the source, the three containers InnoDB keeps data in. The 16KB page with its FIL header, page header, records and page directory; the buffer pool that keeps pages in memory (buf_page_get_gen, the old part of the LRU list, dirty pages and the page cleaner); the clustered-index B-tree that is the table itself (search_leaf, page splits); and the mini-transaction mtr_t that bundles page latches with redo. We open an .ibd file with od and read page headers, look inside the buffer pool through information_schema, grow a table to count B-tree height and splits, and use gdb to watch SELECT and INSERT reach the B-tree.
-
Digging into MariaDB's Source 11: InnoDB Part 2 — Transactions, MVCC, Undo and Locks
We follow, in the source of the reference commit, how one COMMIT travels from the server layer's ha_commit_trans() to InnoDB's trx_t::commit(), how REPEATABLE READ shows you old values through a ReadView and the undo chain, how purge cleans up versions nobody can see any more, and how row locks, gap locks, lock waits and deadlock detection work. Two-session examples show the snapshot, a lock wait, a deadlock and the history list length with our own eyes.
-
Digging into MariaDB's Source 12: Two Logs — the Redo Log, the Binlog and Crash Recovery, and Wrapping Up
What it means for data to be on disk when COMMIT returns. We follow InnoDB's redo log (log_sys, LSNs, mtr_t::commit, log_write_up_to) and the spot where innodb_flush_log_at_trx_commit splits, the checkpoint and the layout of ib_logfile0, crash recovery after kill -9 that rolls forward with redo and back with undo, the server-level binlog and its events, and the two-phase and group commit that tie the two logs together by XID. Using DBUG crash points we kill the server in both gaps of the two-phase commit and watch what recovery does, then wrap up all twelve parts of the series.