<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Tidb on Mini Fish</title>
    <link>https://blog.minifish.org/tags/tidb/</link>
    <description>Recent content in Tidb on Mini Fish</description>
    <image>
      <title>Mini Fish</title>
      <url>https://blog.minifish.org/android-chrome-512x512.png</url>
      <link>https://blog.minifish.org/android-chrome-512x512.png</link>
    </image>
    <generator>Hugo -- 0.154.5</generator>
    <language>en-US</language>
    <copyright>Mini Fish 2014-present. Licensed under CC-BY-NC</copyright>
    <lastBuildDate>Tue, 08 Sep 2020 11:36:00 +0800</lastBuildDate>
    <atom:link href="https://blog.minifish.org/tags/tidb/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>How to Read TiDB Source Code (Part 5)</title>
      <link>https://blog.minifish.org/posts/how-to-read-tidb-source-code-part-5/</link>
      <pubDate>Tue, 08 Sep 2020 11:36:00 +0800</pubDate>
      <guid>https://blog.minifish.org/posts/how-to-read-tidb-source-code-part-5/</guid>
      <description>&lt;p&gt;When using TiDB, you may occasionally encounter some exceptions, such as the &amp;ldquo;Lost connection to MySQL server during query&amp;rdquo; error. This indicates that the connection between the client and the database has been disconnected (not due to user action). The reasons for disconnection can vary. This article attempts to analyze some common TiDB errors from the perspective of exception handling and code analysis. Additionally, some exceptions are not errors but performance issues due to slow execution. In the second half of this article, we will also introduce common tools for tracking performance.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>When using TiDB, you may occasionally encounter some exceptions, such as the &ldquo;Lost connection to MySQL server during query&rdquo; error. This indicates that the connection between the client and the database has been disconnected (not due to user action). The reasons for disconnection can vary. This article attempts to analyze some common TiDB errors from the perspective of exception handling and code analysis. Additionally, some exceptions are not errors but performance issues due to slow execution. In the second half of this article, we will also introduce common tools for tracking performance.</p>
<h2 id="lost-connection">Lost Connection</h2>
<p>There are generally three reasons for a Lost Connection:</p>
<ol>
<li>A timeout occurs either directly between the client and the database or at some point along the intermediate link, such as from the client to the Proxy or from the Proxy to the database.</li>
<li>A bug occurs during SQL execution, which can generally be recovered, thus preventing the TiDB server from crashing completely (panic).</li>
<li>TiDB itself crashes, often due to excessive memory use, causing an OOM (Out of Memory), or a user deliberately kills TiDB. Another possibility is an unrecovered bug, which typically appears more frequently in background threads.</li>
</ol>
<h3 id="timeout">Timeout</h3>
<h4 id="direct-timeout">Direct Timeout</h4>
<p>TiDB supports the MySQL-compatible <code>wait_timeout</code> variable, with a default value of 0, meaning no timeout is set, unlike MySQL&rsquo;s default of 8 hours.</p>
<p><img alt="lost" loading="lazy" src="/posts/images/20200908132926.webp"></p>
<p>The only place it is used in the code is in <code>getSessionVarsWaitTimeout</code>. In the connection&rsquo;s Run section, its value is set for packet IO. If the variable is non-zero, a timeout is set before each <code>readPacket</code>.</p>
<p><img alt="lost" loading="lazy" src="/posts/images/20200908134545.webp"></p>
<p>If the client does not send data beyond the specified time, the connection will be disconnected. At this time, a log message &ldquo;read packet timeout, close this connection&rdquo; will appear, along with the specific timeout duration.</p>
<h4 id="intermediate-link-timeout">Intermediate Link Timeout</h4>
<p>Another scenario is an intermediate link timeout. A normal timeout in an intermediate link (proxy) typically returns an EOF error to the database. In older versions, at least a connection closed log would be output.</p>
<p><img alt="lost" loading="lazy" src="/posts/images/20200908141322.webp"></p>
<p>In the newer master version, product managers suggested changing this log to a debug level, so it is generally no longer output.</p>
<p>However, in the new version, a monitoring item called <code>DisconnectionCounter</code> has been added,</p>
<p><img alt="lost" loading="lazy" src="/posts/images/20200908141537.webp"></p>
<p><img alt="lost" loading="lazy" src="/posts/images/20200908142131.webp"></p>
<p>which records normal and abnormal disconnections as a supplement to downgraded logging.</p>
<h3 id="bugs-that-are-recovered">Bugs that Are Recovered</h3>
<p>TiDB &ldquo;basically&rdquo; can recover from panics caused by unknown bugs. However, if there is an array out-of-bounds, a null pointer reference, or intentional panic, it cannot guarantee correct results for the current and subsequent SQL, so terminating the current connection is a wise choice.</p>
<p><img alt="lost" loading="lazy" src="/posts/images/20200908143849.webp"></p>
<p>At this time, an error log &ldquo;connection running loop panic&rdquo; will appear, along with a <code>lastSQL</code> field that outputs the current erroneous SQL.</p>
<h3 id="panic-not-recovered">Panic Not Recovered</h3>
<p>Whether it&rsquo;s an unrecovered panic or a system-level OOM-induced panic, they do not leave a log in TiDB&rsquo;s logs. TiDB clusters managed by deployment tools like Ansible or TiUP will automatically restart a crashed TiDB server. Consequently, the log will contain a new &ldquo;Welcome&rdquo; message, which might be overlooked. However, the Uptime in monitoring will show TiDB&rsquo;s Uptime reset to zero, making this issue relatively easy to detect. Of course, it&rsquo;s better to have accompanying alerts.</p>
<p>Unrecovered panic outputs are Golang&rsquo;s default outputs, usually redirected to <code>tidb_stderr.log</code> by deployment tools. Older versions of Ansible overwrite this file every restart, but now use an append mode.</p>
<p><img alt="lost" loading="lazy" src="/posts/images/15992142135768.webp"></p>
<p>Nevertheless, it has some other drawbacks, like lacking timestamps. This makes it difficult to timestamp-match with TiDB logs. This <a href="https://github.com/pingcap/tidb/pull/18310">PR</a> implemented distinguishing <code>tidb_stderr.log</code> based on PID but hasn&rsquo;t been coordinated with the deployment tools and is temporarily disabled.</p>
<p>To get this standard panic output, you can use the panicparse introduced in the previous article to parse the panic results. Typically, you can look at the topmost stack. The example in the image evidently shows an out-of-memory error, commonly referred to as OOM. To identify which SQL caused the OOM, check TiDB&rsquo;s logs for resource-heavy SQL, which are usually logged with the <code>expensive_query</code> tag, and can be checked by grepping the logs. This will not be exemplified here.</p>
<h2 id="tracing">Tracing</h2>
<p>TiDB has supported tracing since version 2.1, but it hasn&rsquo;t been widely used. I think there are two main reasons:</p>
<ol>
<li>
<p>The initial version of tracing only supported the JSON format, requiring the output to be copied and pasted into a TiDB-specific web page at a special host port to view it. Although novel, the multiple steps involved prevented widespread adoption.</p>
<p><img alt="lost" loading="lazy" src="/posts/images/trace-view.webp"></p>
</li>
<li>
<p>Another issue is that tracing provides insight only after a problem is known. If developers suspect a problem or slow execution in advance, they must proactively add events at those points. Often, unforeseen issues cannot be covered, leaving gaps.</p>
</li>
</ol>
<p>Once the framework of tracing is in place, adding events is relatively straightforward and involves adding code like the snippet below at the desired points:</p>
<p><img alt="lost" loading="lazy" src="/posts/images/20200908165442.webp"></p>
<p>Interested individuals can add events to TiDB as needed, offering a good hands-on experience.</p>
<p>Eventually, tracing added <code>format='row'</code> and <code>format='log'</code> features. I personally favor <code>format='log'</code>.</p>
<h3 id="difference-between-tracing-and-explain-analyze">Difference between Tracing and Explain (Analyze)</h3>
<ol>
<li>Tracing operates at the function level, while Explain operates at the operator level. Tracing is easier to add and more granular and does not need to be part of a plan.</li>
<li>Tracing can trace any SQL, while Explain only shows data reading parts. For example, with an Insert, Explain shows almost nothing, whereas tracing provides detailed insights from SQL parsing to the full transaction commit.</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>How to Read TiDB Source Code (Part 4)</title>
      <link>https://blog.minifish.org/posts/how-to-read-tidb-source-code-part-4/</link>
      <pubDate>Fri, 31 Jul 2020 10:58:00 +0800</pubDate>
      <guid>https://blog.minifish.org/posts/how-to-read-tidb-source-code-part-4/</guid>
      <description>&lt;p&gt;This article will introduce some key functions and the interpretation of logs in TiDB.&lt;/p&gt;
&lt;h2 id=&#34;key-functions&#34;&gt;Key Functions&lt;/h2&gt;
&lt;p&gt;The definition of key functions varies from person to person, so the content of this section is subjective.&lt;/p&gt;
&lt;h3 id=&#34;execute&#34;&gt;execute&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&#34;func&#34; loading=&#34;lazy&#34; src=&#34;https://blog.minifish.org/posts/images/20200812152326.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;execute&lt;/code&gt; function is the necessary pathway for text protocol execution. It also nicely demonstrates the various processes of SQL handling.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;ParseSQL analyzes the SQL. The final implementation is in the parser, where SQL is parsed according to the rules introduced in the second article. Note that the parsed SQL may be a single statement or multiple statements. TiDB itself supports the multi-SQL feature, allowing multiple SQL statements to be executed at once.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>This article will introduce some key functions and the interpretation of logs in TiDB.</p>
<h2 id="key-functions">Key Functions</h2>
<p>The definition of key functions varies from person to person, so the content of this section is subjective.</p>
<h3 id="execute">execute</h3>
<p><img alt="func" loading="lazy" src="/posts/images/20200812152326.webp"></p>
<p>The <code>execute</code> function is the necessary pathway for text protocol execution. It also nicely demonstrates the various processes of SQL handling.</p>
<ol>
<li>
<p>ParseSQL analyzes the SQL. The final implementation is in the parser, where SQL is parsed according to the rules introduced in the second article. Note that the parsed SQL may be a single statement or multiple statements. TiDB itself supports the multi-SQL feature, allowing multiple SQL statements to be executed at once.</p>
</li>
<li>
<p>After parsing, a <code>stmtNodes</code> array is returned, which is processed one-by-one in the for loop below. The first step is to compile, where the core of compile is optimization, generating a plan. By following the <code>Optimize</code> function, you can find logic similar to logical and physical optimization found in other common databases.</p>
<p><img alt="func" loading="lazy" src="/posts/images/20200812153017.webp"></p>
</li>
<li>
<p>The last part is execution, where <code>executeStatement</code> and particularly the <code>runStmt</code> function are key functions.</p>
</li>
</ol>
<h3 id="runstmt">runStmt</h3>
<p>Judging from the call graph of <code>runStmt</code>, this function is almost the mandatory pathway for all SQL execution. Except for point query statements using the binary protocol with automatic commit, all other statements go through this function. This function is responsible for executing SQL, excluding SQL parsing and compilation (the binary protocol does not need repeated SQL parsing, nor does SQL compilation require plan caching).</p>
<p><img alt="func" loading="lazy" src="/posts/images/20200731112400.webp"></p>
<p>The core part of the <code>runStmt</code> function is as shown above. From top to bottom:</p>
<ol>
<li>
<p>checkTxnAborted</p>
<p>When a transaction is already corrupted and cannot be committed, the user must actively close the transaction to end the already corrupted transaction. During execution, transactions may encounter errors that cannot be handled and must be terminated. The transaction cannot be silently closed because the user may continue to execute SQL and assume it is still within the transaction. This function ensures that all subsequent SQL commands by the user are not executed and directly return an error until the user uses rollback or commit to explicitly close the transaction for normal execution.</p>
</li>
<li>
<p>Exec</p>
<p>Execute the SQL and return the result set (rs).</p>
</li>
<li>
<p>IsReadOnly</p>
<p>After executing a SQL, it&rsquo;s necessary to determine whether it is a read-only SQL. If it is not read-only, it must be temporarily stored in the transaction&rsquo;s execution history. This execution history is used when a transaction conflict or other errors require the transaction to be retried. Read-only SQL is bypassed because the retry of the transaction is done during the commit phase, and at this point, the only feedback to the client can be success or failure of the commit; reading results is meaningless.</p>
<p>This section also includes <code>StmtCommit</code> and <code>StmtRollback</code>. TiDB supports MySQL-like statement commits and rollbacks—if a statement fails during a transaction, that single statement will be atomically rolled back, while other successfully executed statements will eventually commit with the transaction.</p>
<p>In TiDB, the feature of statement commit is implemented with a two-layer buffer: both the transaction and the statement have their own buffers. After a statement executes successfully, the statement’s buffer is merged into the transaction buffer. If a statement fails, the statement’s buffer is discarded, thus ensuring the atomicity of statement commits. Of course, a statement commit may fail, in which case the entire transaction buffer becomes unusable, and the transaction can only be rolled back.</p>
</li>
<li>
<p>finishStmt</p>
<p>Once a statement is executed, should it be committed? This depends on whether the transaction was explicitly started (i.e., with <code>begin</code> or <code>start transaction</code>) and whether autocommit is enabled. The role of <code>finishStmt</code> is to, post-execution, check if it should be committed based on the above conditions. It&rsquo;s essentially for cleaning up and checking after each statement execution.</p>
</li>
<li>
<p>pending section</p>
<p>Some SQLs in TiDB do not require a transaction (e.g., the <code>set</code> statement). However, before parsing, the database doesn’t know whether the statement requires a transaction. The latency of starting a transaction in TiDB is relatively high because it requires obtaining a TSO (timestamp oracle) from PD. TiDB has an optimization to asynchronously obtain a TSO, meaning a TSO is prepared regardless of whether a transaction is eventually needed. If a statement indeed doesn’t require a TSO and a transaction is not activated, remaining in a pending status, the pending transaction must be closed.</p>
</li>
</ol>
<h2 id="logs">Logs</h2>
<p>Let&rsquo;s first look at a section of logs from TiDB at initial startup, divided into several parts:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[2020/08/12 16:12:07.282 +08:00] [INFO] [printer.go:42] [&#34;Welcome to TiDB.&#34;] [&#34;Release Version&#34;=None] [Edition=None] [&#34;Git Commit Hash&#34;=None] [&#34;Git Branch&#34;=None] [&#34;UTC Build Time&#34;=None] [GoVersion=go1.15] [&#34;Race Enabled&#34;=false] [&#34;Check Table Before Drop&#34;=false] [&#34;TiKV Min Version&#34;=v3.0.0-60965b006877ca7234adaced7890d7b029ed1306]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.300 +08:00] [INFO] [printer.go:56] [&#34;loaded config&#34;] [config=&#34;{\&#34;host\&#34;:\&#34;0.0.0.0\&#34;,\&#34;advertise-address\&#34;:\&#34;0.0.0.0\&#34;,\&#34;port\&#34;:4000,\&#34;cors\&#34;:\&#34;\&#34;,\&#34;store\&#34;:\&#34;mocktikv\&#34;,\&#34;path\&#34;:\&#34;/tmp/tidb\&#34;,\&#34;socket\&#34;:\&#34;\&#34;,\&#34;lease\&#34;:\&#34;45s\&#34;,\&#34;run-ddl\&#34;:true,\&#34;split-table\&#34;:true,\&#34;token-limit\&#34;:1000,\&#34;oom-use-tmp-storage\&#34;:true,\&#34;tmp-storage-path\&#34;:\&#34;C:\\\\Users\\\\username\\\\AppData\\\\Local\\\\Temp\\\\tidb\\\\tmp-storage\&#34;,\&#34;oom-action\&#34;:\&#34;log\&#34;,\&#34;mem-quota-query\&#34;:1073741824,\&#34;tmp-storage-quota\&#34;:-1,\&#34;enable-streaming\&#34;:false,\&#34;enable-batch-dml\&#34;:false,\&#34;lower-case-table-names\&#34;:2,\&#34;server-version\&#34;:\&#34;\&#34;,\&#34;log\&#34;:{\&#34;level\&#34;:\&#34;info\&#34;,\&#34;format\&#34;:\&#34;text\&#34;,\&#34;disable-timestamp\&#34;:null,\&#34;enable-timestamp\&#34;:null,\&#34;disable-error-stack\&#34;:null,\&#34;enable-error-stack\&#34;:null,\&#34;file\&#34;:{\&#34;filename\&#34;:\&#34;\&#34;,\&#34;max-size\&#34;:300,\&#34;max-days\&#34;:0,\&#34;max-backups\&#34;:0},\&#34;enable-slow-log\&#34;:true,\&#34;slow-query-file\&#34;:\&#34;tidb-slow.log\&#34;,\&#34;slow-threshold\&#34;:300,\&#34;expensive-threshold\&#34;:10000,\&#34;query-log-max-len\&#34;:4096,\&#34;record-plan-in-slow-log\&#34;:1},\&#34;security\&#34;:{\&#34;skip-grant-table\&#34;:false,\&#34;ssl-ca\&#34;:\&#34;\&#34;,\&#34;ssl-cert\&#34;:\&#34;\&#34;,\&#34;ssl-key\&#34;:\&#34;\&#34;,\&#34;require-secure-transport\&#34;:false,\&#34;cluster-ssl-ca\&#34;:\&#34;\&#34;,\&#34;cluster-ssl-cert\&#34;:\&#34;\&#34;,\&#34;cluster-ssl-key\&#34;:\&#34;\&#34;,\&#34;cluster-verify-cn\&#34;:null},\&#34;status\&#34;:{\&#34;status-host\&#34;:\&#34;0.0.0.0\&#34;,\&#34;metrics-addr\&#34;:\&#34;\&#34;,\&#34;status-port\&#34;:10080,\&#34;metrics-interval\&#34;:15,\&#34;report-status\&#34;:true,\&#34;record-db-qps\&#34;:false},\&#34;performance\&#34;:{\&#34;max-procs\&#34;:0,\&#34;max-memory\&#34;:0,\&#34;stats-lease\&#34;:\&#34;3s\&#34;,\&#34;stmt-count-limit\&#34;:5000,\&#34;feedback-probability\&#34;:0.05,\&#34;query-feedback-limit\&#34;:1024,\&#34;pseudo-estimate-ratio\&#34;:0.8,\&#34;force-priority\&#34;:\&#34;NO_PRIORITY\&#34;,\&#34;bind-info-lease\&#34;:\&#34;3s\&#34;,\&#34;txn-total-size-limit\&#34;:104857600,\&#34;tcp-keep-alive\&#34;:true,\&#34;cross-join\&#34;:true,\&#34;run-auto-analyze\&#34;:true,\&#34;agg-push-down-join\&#34;:false,\&#34;committer-concurrency\&#34;:16,\&#34;max-txn-ttl\&#34;:600000},\&#34;prepared-plan-cache\&#34;:{\&#34;enabled\&#34;:false,\&#34;capacity\&#34;:100,\&#34;memory-guard-ratio\&#34;:0.1},\&#34;opentracing\&#34;:{\&#34;enable\&#34;:false,\&#34;rpc-metrics\&#34;:false,\&#34;sampler\&#34;:{\&#34;type\&#34;:\&#34;const\&#34;,\&#34;param\&#34;:1,\&#34;sampling-server-url\&#34;:\&#34;\&#34;,\&#34;max-operations\&#34;:0,\&#34;sampling-refresh-interval\&#34;:0},\&#34;reporter\&#34;:{\&#34;queue-size\&#34;:0,\&#34;buffer-flush-interval\&#34;:0,\&#34;log-spans\&#34;:false,\&#34;local-agent-host-port\&#34;:\&#34;\&#34;}},\&#34;proxy-protocol\&#34;:{\&#34;networks\&#34;:\&#34;\&#34;,\&#34;header-timeout\&#34;:5},\&#34;tikv-client\&#34;:{\&#34;grpc-connection-count\&#34;:4,\&#34;grpc-keepalive-time\&#34;:10,\&#34;grpc-keepalive-timeout\&#34;:3,\&#34;commit-timeout\&#34;:\&#34;41s\&#34;,\&#34;max-batch-size\&#34;:128,\&#34;overload-threshold\&#34;:200,\&#34;max-batch-wait-time\&#34;:0,\&#34;batch-wait-size\&#34;:8,\&#34;enable-chunk-rpc\&#34;:true,\&#34;region-cache-ttl\&#34;:600,\&#34;store-limit\&#34;:0,\&#34;store-liveness-timeout\&#34;:\&#34;120s\&#34;,\&#34;copr-cache\&#34;:{\&#34;enable\&#34;:false,\&#34;capacity-mb\&#34;:1000,\&#34;admission-max-result-mb\&#34;:10,\&#34;admission-min-process-ms\&#34;:5}},\&#34;binlog\&#34;:{\&#34;enable\&#34;:false,\&#34;ignore-error\&#34;:false,\&#34;write-timeout\&#34;:\&#34;15s\&#34;,\&#34;binlog-socket\&#34;:\&#34;\&#34;,\&#34;strategy\&#34;:\&#34;range\&#34;},\&#34;compatible-kill-query\&#34;:false,\&#34;plugin\&#34;:{\&#34;dir\&#34;:\&#34;\&#34;,\&#34;load\&#34;:\&#34;\&#34;},\&#34;pessimistic-txn\&#34;:{\&#34;enable\&#34;:true,\&#34;max-retry-count\&#34;:256},\&#34;check-mb4-value-in-utf8\&#34;:true,\&#34;max-index-length\&#34;:3072,\&#34;alter-primary-key\&#34;:false,\&#34;treat-old-version-utf8-as-utf8mb4\&#34;:true,\&#34;enable-table-lock\&#34;:false,\&#34;delay-clean-table-lock\&#34;:0,\&#34;split-region-max-num\&#34;:1000,\&#34;stmt-summary\&#34;:{\&#34;enable\&#34;:true,\&#34;enable-internal-query\&#34;:false,\&#34;max-stmt-count\&#34;:200,\&#34;max-sql-length\&#34;:4096,\&#34;refresh-interval\&#34;:1800,\&#34;history-size\&#34;:24},\&#34;repair-mode\&#34;:false,\&#34;repair-table-list\&#34;:[],\&#34;isolation-read\&#34;:{\&#34;engines\&#34;:[\&#34;tikv\&#34;,\&#34;tiflash\&#34;,\&#34;tidb\&#34;]},\&#34;max-server-connections\&#34;:0,\&#34;new_collations_enabled_on_first_bootstrap\&#34;:false,\&#34;experimental\&#34;:{\&#34;allow-auto-random\&#34;:false,\&#34;allow-expression-index\&#34;:false}}&#34;]
</span></span></code></pre></div><ol>
<li>Mandatory startup outputs: &ldquo;Welcome to TiDB,&rdquo; git hash, Golang version, etc.</li>
<li>Actually loaded configuration (this section is somewhat difficult to read)</li>
</ol>
<p>The remainder are some routine startup logs. The process can be referenced from the main function section introduced in the first article, mainly outputting the initial system table creation process.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[2020/08/12 16:12:07.300 +08:00] [INFO] [main.go:341] [&#34;disable Prometheus push client&#34;]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.300 +08:00] [INFO] [store.go:68] [&#34;new store&#34;] [path=mocktikv:///tmp/tidb]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.300 +08:00] [INFO] [systime_mon.go:25] [&#34;start system time monitor&#34;]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.310 +08:00] [INFO] [store.go:74] [&#34;new store with retry success&#34;]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.310 +08:00] [INFO] [tidb.go:71] [&#34;new domain&#34;] [store=8d19232e-a273-4e31-ba9b-a3467998345c] [&#34;ddl lease&#34;=45s] [&#34;stats lease&#34;=3s]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.315 +08:00] [INFO] [ddl.go:321] [&#34;[ddl] start DDL&#34;] [ID=0e1bd28e-03ed-4900-bf71-f58b3b9d954a] [runWorker=true]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.315 +08:00] [INFO] [ddl.go:309] [&#34;[ddl] start delRangeManager OK&#34;] [&#34;is a emulator&#34;=true]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.315 +08:00] [INFO] [ddl_worker.go:130] [&#34;[ddl] start DDL worker&#34;] [worker=&#34;worker 1, tp general&#34;]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.315 +08:00] [INFO] [ddl_worker.go:130] [&#34;[ddl] start DDL worker&#34;] [worker=&#34;worker 2, tp add index&#34;]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.315 +08:00] [INFO] [delete_range.go:133] [&#34;[ddl] start delRange emulator&#34;]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.317 +08:00] [INFO] [domain.go:144] [&#34;full load InfoSchema success&#34;] [usedSchemaVersion=0] [neededSchemaVersion=0] [&#34;start time&#34;=2.0015ms]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.317 +08:00] [INFO] [domain.go:368] [&#34;full load and reset schema validator&#34;]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.317 +08:00] [INFO] [tidb.go:199] [&#34;rollbackTxn for ddl/autocommit failed&#34;]
</span></span></code></pre></div><p>Because DDL logs are very numerous, the TiDB logs basically record each step of the DDL execution, so I&rsquo;ve truncated this part of the log here. However, the basic outline can be sorted out. Firstly, the DDL execution is initiated from ddl_api, at this time recording <code>[&quot;CRUCIAL OPERATION&quot;]</code> style logs. DDL is a crucial operation, so it belongs to CRUCIAL type logs. Then, we can see a series of logs with the ddl keyword linked together, such as <code>[ddl] add DDL jobs</code>, <code>[ddl] start DDL job</code>, <code>[ddl] run DDL job</code>, <code>[ddl] finish DDL job</code>, and <code>[ddl] DDL job is finished</code>. These represent the process from when the DDL owner acquires a job to its final execution completion. Moreover, they have a unique job ID, which can be used to link a DDL in the log with something like <code>jobs=&quot;ID:2</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[2020/08/12 16:12:07.518 +08:00] [INFO] [server.go:235] [&#34;server is running MySQL protocol&#34;] [addr=0.0.0.0:4000]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.518 +08:00] [INFO] [http_status.go:80] [&#34;for status and metrics report&#34;] [&#34;listening on addr&#34;=0.0.0.0:10080]
</span></span><span style="display:flex;"><span>[2020/08/12 16:12:07.520 +08:00] [INFO] [domain.go:1015] [&#34;init stats info time&#34;] [&#34;take time&#34;=3.0126ms]
</span></span><span style="display:flex;"><span>[2020/08/12 16:15:41.482 +08:00] [INFO] [server.go:388] [&#34;new connection&#34;] [conn=1] [remoteAddr=127.0.0.1:64888]
</span></span><span style="display:flex;"><span>[2020/08/12 21:03:19.954 +08:00] [INFO] [server.go:391] [&#34;connection closed&#34;] [conn=1]
</span></span></code></pre></div><p>Thereafter, the appearance of <code>server is running MySQL protocol</code> means that TiDB can provide services externally. Later, there are logs corresponding to the creation and closing of each connection, namely <code>new connection</code> and <code>connection closed</code>. Of course, they also have their corresponding connection ID, which is unique for a TiDB. You can use the keyword <code>conn=1</code> in the log to contextually link them together.</p>
<h3 id="stack-logs">Stack Logs</h3>
<p>Most of TiDB&rsquo;s SQL errors (except for duplicate entry and syntax errors) will output the complete stack information. Due to the requirements of unified log format, the stack now looks very unsightly&hellip;</p>
<p>For this stack trace, I believe no one really enjoys reading it. Therefore, we need to paste it into Vim and execute <code>%s/\\n/\r/g</code> and <code>%s/\\t/    /g</code> to turn it into a Golang-style stack.</p>
<p>When you see which module it&rsquo;s stuck in, like the plan part here, you can find the corresponding colleague for support.</p>
<p>However, there is a more user-friendly tool for dealing with Golang’s lengthy stack called <a href="https://github.com/maruel/panicparse">panicparse</a>. To install it, simply run
<code>go get github.com/maruel/panicparse/v2/cmd/pp</code>. The effect is as follows:</p>
<p><img alt="func" loading="lazy" src="/posts/images/20200813172149.webp"></p>
<p>Whether it&rsquo;s TiDB running goroutines or panic outputs, it can be parsed using this. It has several features:</p>
<ol>
<li>It can display active and inactive goroutines.</li>
<li>It can show the relationships between goroutines.</li>
<li>Keyword highlighting.</li>
<li>Supports Windows.</li>
</ol>
<p>The latest 2.0.0 version supports race detector and HTML formatted output.</p>
<p>This concludes the introduction to the analysis of key functions and logs (startup, DDL, connection, error stack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to Read TiDB Source Code (Part 3)</title>
      <link>https://blog.minifish.org/posts/how-to-read-tidb-source-code-part-3/</link>
      <pubDate>Tue, 28 Jul 2020 11:47:00 +0800</pubDate>
      <guid>https://blog.minifish.org/posts/how-to-read-tidb-source-code-part-3/</guid>
      <description>&lt;p&gt;In the previous article, we introduced methods for viewing syntax and configurations. In this article, we will discuss how to view system variables, including default values, scopes, and how to monitor metrics.&lt;/p&gt;
&lt;h2 id=&#34;system-variables&#34;&gt;System Variables&lt;/h2&gt;
&lt;p&gt;The system variable names in TiDB are defined in &lt;a href=&#34;https://github.com/pingcap/tidb/blob/db0310b17901b1a59f7f728294455ed9667f88ac/sessionctx/variable/tidb_vars.go&#34;&gt;tidb_vars.go&lt;/a&gt;. This file also includes some default values for variables, but the place where they are actually assembled is &lt;a href=&#34;https://github.com/pingcap/tidb/blob/12aac547a9068c404ad18093ae4d0ea4d060a465/sessionctx/variable/sysvar.go#L96&#34;&gt;defaultSysVars&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;defaultSysVars&#34; loading=&#34;lazy&#34; src=&#34;https://blog.minifish.org/posts/images/20200728151254.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;This large struct array defines the scope, variable names, and default values for all variables in TiDB. Besides TiDB&amp;rsquo;s own system variables, it also includes compatibility with MySQL&amp;rsquo;s system variables.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In the previous article, we introduced methods for viewing syntax and configurations. In this article, we will discuss how to view system variables, including default values, scopes, and how to monitor metrics.</p>
<h2 id="system-variables">System Variables</h2>
<p>The system variable names in TiDB are defined in <a href="https://github.com/pingcap/tidb/blob/db0310b17901b1a59f7f728294455ed9667f88ac/sessionctx/variable/tidb_vars.go">tidb_vars.go</a>. This file also includes some default values for variables, but the place where they are actually assembled is <a href="https://github.com/pingcap/tidb/blob/12aac547a9068c404ad18093ae4d0ea4d060a465/sessionctx/variable/sysvar.go#L96">defaultSysVars</a>.</p>
<p><img alt="defaultSysVars" loading="lazy" src="/posts/images/20200728151254.webp"></p>
<p>This large struct array defines the scope, variable names, and default values for all variables in TiDB. Besides TiDB&rsquo;s own system variables, it also includes compatibility with MySQL&rsquo;s system variables.</p>
<h3 id="scope">Scope</h3>
<p>In TiDB, there are three types of variable scopes literally:</p>
<p><img alt="defaultSysVars" loading="lazy" src="/posts/images/20200728151833.webp"></p>
<p>They are ScopeNone, ScopeGlobal, and ScopeSession. They represent:</p>
<ul>
<li>ScopeNone: Read-only variables</li>
<li>ScopeGlobal: Global variables</li>
<li>ScopeSession: Session variables</li>
</ul>
<p>The actual effect of these scopes is that when you use SQL to read or write them, you need to use the corresponding syntax. If the SQL fails, the SQL operation does not take effect. If the SQL executes successfully, it merely means the setting is complete, but it does not mean that it takes effect according to the corresponding scope.</p>
<p>Let&rsquo;s use the method mentioned in the first article to start a single-node TiDB for demonstration:</p>
<h4 id="scopenone">ScopeNone</h4>
<p>Take <code>performance_schema_max_mutex_classes</code> as an example,</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">select</span> <span style="color:#f92672">@@</span>performance_schema_max_mutex_classes;
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">----------------------------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#f92672">@@</span>performance_schema_max_mutex_classes <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">----------------------------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#ae81ff">200</span>                                    <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">----------------------------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> <span style="color:#66d9ef">row</span> <span style="color:#66d9ef">in</span> <span style="color:#66d9ef">set</span> (<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0002</span> sec)
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">select</span> <span style="color:#f92672">@@</span><span style="color:#66d9ef">global</span>.performance_schema_max_mutex_classes;
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">-----------------------------------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#f92672">@@</span><span style="color:#66d9ef">global</span>.performance_schema_max_mutex_classes <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">-----------------------------------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#ae81ff">200</span>                                           <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">-----------------------------------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> <span style="color:#66d9ef">row</span> <span style="color:#66d9ef">in</span> <span style="color:#66d9ef">set</span> (<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0004</span> sec)
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">select</span> <span style="color:#f92672">@@</span><span style="color:#66d9ef">session</span>.performance_schema_max_mutex_classes;
</span></span><span style="display:flex;"><span>ERROR: <span style="color:#ae81ff">1238</span> (HY000): <span style="color:#66d9ef">Variable</span> <span style="color:#e6db74">&#39;performance_schema_max_mutex_classes&#39;</span> <span style="color:#66d9ef">is</span> a <span style="color:#66d9ef">GLOBAL</span> <span style="color:#66d9ef">variable</span>
</span></span></code></pre></div><p>As you can see, the scope of ScopeNone can be read as a global variable,</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">set</span> <span style="color:#66d9ef">global</span> performance_schema_max_mutex_classes <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>ERROR: <span style="color:#ae81ff">1105</span> (HY000): <span style="color:#66d9ef">Variable</span> <span style="color:#e6db74">&#39;performance_schema_max_mutex_classes&#39;</span> <span style="color:#66d9ef">is</span> a <span style="color:#66d9ef">read</span><span style="color:#f92672">-</span><span style="color:#66d9ef">only</span> <span style="color:#66d9ef">variable</span>
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">set</span> performance_schema_max_mutex_classes <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>ERROR: <span style="color:#ae81ff">1105</span> (HY000): <span style="color:#66d9ef">Variable</span> <span style="color:#e6db74">&#39;performance_schema_max_mutex_classes&#39;</span> <span style="color:#66d9ef">is</span> a <span style="color:#66d9ef">read</span><span style="color:#f92672">-</span><span style="color:#66d9ef">only</span> <span style="color:#66d9ef">variable</span>
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">set</span> <span style="color:#66d9ef">session</span> performance_schema_max_mutex_classes <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>;
</span></span><span style="display:flex;"><span>ERROR: <span style="color:#ae81ff">1105</span> (HY000): <span style="color:#66d9ef">Variable</span> <span style="color:#e6db74">&#39;performance_schema_max_mutex_classes&#39;</span> <span style="color:#66d9ef">is</span> a <span style="color:#66d9ef">read</span><span style="color:#f92672">-</span><span style="color:#66d9ef">only</span> <span style="color:#66d9ef">variable</span>
</span></span></code></pre></div><p>But it cannot be set in any way.</p>
<p>To trace the usage of ScopeNone, you will see</p>
<p><img alt="defaultSysVars" loading="lazy" src="/posts/images/20200728155134.webp"></p>
<p>In <code>setSysVariable</code>, when this type of scope variable is encountered, an error is directly returned.</p>
<p><img alt="defaultSysVars" loading="lazy" src="/posts/images/20200728155332.webp"></p>
<p>In <code>ValidateGetSystemVar</code>, it is handled as a global variable.
From a theoretical standpoint, these ScopeNone variables are essentially a single copy in the code. Once TiDB is started, they exist in memory as read-only and are not actually stored in TiKV.</p>
<h4 id="scopeglobal">ScopeGlobal</h4>
<p>Using <code>gtid_mode</code> as an example,</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">select</span> <span style="color:#f92672">@@</span>gtid_mode;
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">-------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#f92672">@@</span>gtid_mode <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">-------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#66d9ef">OFF</span>         <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">-------------+
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> <span style="color:#66d9ef">row</span> <span style="color:#66d9ef">in</span> <span style="color:#66d9ef">set</span> (<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0003</span> sec)
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">select</span> <span style="color:#f92672">@@</span><span style="color:#66d9ef">global</span>.gtid_mode;
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">--------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#f92672">@@</span><span style="color:#66d9ef">global</span>.gtid_mode <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">--------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#66d9ef">OFF</span>                <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">--------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> <span style="color:#66d9ef">row</span> <span style="color:#66d9ef">in</span> <span style="color:#66d9ef">set</span> (<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0006</span> sec)
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">select</span> <span style="color:#f92672">@@</span><span style="color:#66d9ef">session</span>.gtid_mode;
</span></span><span style="display:flex;"><span>ERROR: <span style="color:#ae81ff">1238</span> (HY000): <span style="color:#66d9ef">Variable</span> <span style="color:#e6db74">&#39;gtid_mode&#39;</span> <span style="color:#66d9ef">is</span> a <span style="color:#66d9ef">GLOBAL</span> <span style="color:#66d9ef">variable</span>
</span></span></code></pre></div><p>It works the same way as MySQL global variable reading,</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">set</span> gtid_mode<span style="color:#f92672">=</span><span style="color:#66d9ef">on</span>;
</span></span><span style="display:flex;"><span>ERROR: <span style="color:#ae81ff">1105</span> (HY000): <span style="color:#66d9ef">Variable</span> <span style="color:#e6db74">&#39;gtid_mode&#39;</span> <span style="color:#66d9ef">is</span> a <span style="color:#66d9ef">GLOBAL</span> <span style="color:#66d9ef">variable</span> <span style="color:#66d9ef">and</span> should be <span style="color:#66d9ef">set</span> <span style="color:#66d9ef">with</span> <span style="color:#66d9ef">SET</span> <span style="color:#66d9ef">GLOBAL</span>
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">set</span> <span style="color:#66d9ef">session</span> gtid_mode<span style="color:#f92672">=</span><span style="color:#66d9ef">on</span>;
</span></span><span style="display:flex;"><span>ERROR: <span style="color:#ae81ff">1105</span> (HY000): <span style="color:#66d9ef">Variable</span> <span style="color:#e6db74">&#39;gtid_mode&#39;</span> <span style="color:#66d9ef">is</span> a <span style="color:#66d9ef">GLOBAL</span> <span style="color:#66d9ef">variable</span> <span style="color:#66d9ef">and</span> should be <span style="color:#66d9ef">set</span> <span style="color:#66d9ef">with</span> <span style="color:#66d9ef">SET</span> <span style="color:#66d9ef">GLOBAL</span>
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">set</span> <span style="color:#66d9ef">global</span> gtid_mode<span style="color:#f92672">=</span><span style="color:#66d9ef">on</span>;
</span></span><span style="display:flex;"><span>Query OK, <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">rows</span> affected (<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0029</span> sec)
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">select</span> <span style="color:#f92672">@@</span><span style="color:#66d9ef">global</span>.gtid_mode;
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">--------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#f92672">@@</span><span style="color:#66d9ef">global</span>.gtid_mode <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">--------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#66d9ef">ON</span>                 <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">--------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> <span style="color:#66d9ef">row</span> <span style="color:#66d9ef">in</span> <span style="color:#66d9ef">set</span> (<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0005</span> sec)
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">select</span> <span style="color:#f92672">@@</span>gtid_mode;
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">-------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#f92672">@@</span>gtid_mode <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">-------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#66d9ef">ON</span>          <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">-------------+
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> <span style="color:#66d9ef">row</span> <span style="color:#66d9ef">in</span> <span style="color:#66d9ef">set</span> (<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0006</span> sec)
</span></span></code></pre></div><p>The setting method is also compatible with MySQL. At this point, we can shut down the single-instance TiDB and restart it,</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">select</span> <span style="color:#f92672">@@</span>gtid_mode;
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">-------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#f92672">@@</span>gtid_mode <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">-------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#66d9ef">ON</span>          <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">-------------+
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> <span style="color:#66d9ef">row</span> <span style="color:#66d9ef">in</span> <span style="color:#66d9ef">set</span> (<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0003</span> sec)
</span></span></code></pre></div><p>And you can see that the result can still be read, meaning that this setting was persisted to the storage engine.
Looking closely at the code, you can see:</p>
<p><img alt="defaultSysVars" loading="lazy" src="/posts/images/20200728164505.webp"></p>
<p>The actual implementation involves executing an internal replace statement to update the original value. This constitutes a complete transaction involving acquiring two TSOs and committing the entire process, making it slower compared to setting session variables.</p>
<h4 id="scopesession">ScopeSession</h4>
<p>Using <code>rand_seed2</code> as an example,</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">select</span> <span style="color:#f92672">@@</span>rand_seed2;
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">--------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#f92672">@@</span>rand_seed2 <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">--------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span>              <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">--------------+
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> <span style="color:#66d9ef">row</span> <span style="color:#66d9ef">in</span> <span style="color:#66d9ef">set</span> (<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0005</span> sec)
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">select</span> <span style="color:#f92672">@@</span><span style="color:#66d9ef">session</span>.rand_seed2;
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">----------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span> <span style="color:#f92672">@@</span><span style="color:#66d9ef">session</span>.rand_seed2 <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">----------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">|</span>                      <span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span><span style="color:#75715e">----------------------+
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> <span style="color:#66d9ef">row</span> <span style="color:#66d9ef">in</span> <span style="color:#66d9ef">set</span> (<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0003</span> sec)
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">select</span> <span style="color:#f92672">@@</span><span style="color:#66d9ef">global</span>.rand_seed2;
</span></span><span style="display:flex;"><span>ERROR: <span style="color:#ae81ff">1238</span> (HY000): <span style="color:#66d9ef">Variable</span> <span style="color:#e6db74">&#39;rand_seed2&#39;</span> <span style="color:#66d9ef">is</span> a <span style="color:#66d9ef">SESSION</span> <span style="color:#66d9ef">variable</span>
</span></span></code></pre></div><p>Reading is compatible with MySQL.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">set</span> rand_seed2<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;abc&#39;</span>;
</span></span><span style="display:flex;"><span>Query OK, <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">rows</span> affected (<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0006</span> sec)
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">set</span> <span style="color:#66d9ef">session</span> rand_seed2<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;bcd&#39;</span>;
</span></span><span style="display:flex;"><span>Query OK, <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">rows</span> affected (<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0004</span> sec)
</span></span><span style="display:flex;"><span>MySQL  <span style="color:#ae81ff">127</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">0</span>.<span style="color:#ae81ff">1</span>:<span style="color:#ae81ff">4000</span>  <span style="color:#66d9ef">SQL</span> <span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">set</span> <span style="color:#66d9ef">global</span> rand_seed2<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;cde&#39;</span>;
</span></span><span style="display:flex;"><span>ERROR: <span style="color:#ae81ff">1105</span> (HY000): <span style="color:#66d9ef">Variable</span> <span style="color:#e6db74">&#39;rand_seed2&#39;</span> <span style="color:#66d9ef">is</span> a <span style="color:#66d9ef">SESSION</span> <span style="color:#66d9ef">variable</span> <span style="color:#66d9ef">and</span> can<span style="color:#e6db74">&#39;t be used with SET GLOBAL
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">MySQL  127.0.0.1:4000  SQL &gt; select @@rand_seed2;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">+--------------+
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">| @@rand_seed2 |
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">+--------------+
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">| bcd          |
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">+--------------+
</span></span></span></code></pre></div><p>The setting is also compatible with MySQL. It can be simply observed that this operation only changes the session&rsquo;s memory.
The actual place where it finally takes effect is <a href="https://github.com/pingcap/tidb/blob/f360ad7a434e4edd4d7ebce5ed5dc2b9826b6ed0/sessionctx/variable/session.go#L998">SetSystemVar</a>.</p>
<p><img alt="defaultSysVars" loading="lazy" src="/posts/images/20200728171914.webp"></p>
<p>There are some tricks here.</p>
<h3 id="actual-scope-of-variables">Actual Scope of Variables</h3>
<p>The previous section covered setting session variables. Based on MySQL&rsquo;s variable rules, setting a global variable does not affect the current session. Only newly created sessions will load global variables for session variable assignment. Ultimately, the active session variable take effect. Global variables without session properties still have unique characteristics, and this chapter will cover:</p>
<ol>
<li>Activation of session variables</li>
<li>Activation of pure global variables</li>
<li>Mechanism of global variable function</li>
</ol>
<p>These three aspects.</p>
<h4 id="activation-of-session-variables">Activation of Session Variables</h4>
<p>Whether a session variable is also a global variable only affects whether it needs to load global variable data from the storage engine when the session starts. The default value in the code is the initial value for eternity if no loading is required.</p>
<p>The actual range where a variable operates can only be observed in <a href="https://github.com/pingcap/tidb/blob/f360ad7a434e4edd4d7ebce5ed5dc2b9826b6ed0/sessionctx/variable/session.go#L998">SetSystemVar</a>.</p>
<p><img alt="defaultSysVars" loading="lazy" src="/posts/images/20200728173351.webp"></p>
<p>For example, in this part, <code>s.MemQuotaNestedLoopApply = tidbOptInt64(val, DefTiDBMemQuotaNestedLoopApply)</code> changes the <code>s</code> structure, effectively changing the current session,</p>
<p>Whereas <code>atomic.StoreUint32(&amp;ProcessGeneralLog, uint32(tidbOptPositiveInt32(val, DefTiDBGeneralLog)))</code> changes the value of the global variable <code>ProcessGeneralLog</code>, thereby affecting the entire TiDB instance when <code>set tidb_general_log = 1</code> is executed.</p>
<h4 id="activation-of-pure-global-variables">Activation of Pure Global Variables</h4>
<p>Pure global variables in current TiDB are used for background threads like DDL, statistics, etc.</p>
<p><img alt="defaultSysVars" loading="lazy" src="/posts/images/20200728174207.webp">
<img alt="defaultSysVars" loading="lazy" src="/posts/images/20200728174243.webp"></p>
<p>Because only one TiDB server requires them, session-level variables hold no meaning for these.</p>
<h4 id="mechanism-of-global-variable-function">Mechanism of Global Variable Function</h4>
<p>Global variables in TiDB don&rsquo;t activate immediately after setting. A connection fetches the latest global system variables from TiKV to assign them to the current session the first time it&rsquo;s established. Concurrent connection creation results in frequent access to the TiKV node holding a few global variables. Thus, TiDB caches global variables, updating them every two seconds, significantly reducing TiKV load.
The problem arises that after setting a global variable, a brief wait is necessary before creating a new connection, ensuring new connections will read the latest global variable. This is one of the few eventual consistency locations within TiDB.</p>
<p>For specific details, see <a href="https://github.com/pingcap/tidb/blob/838b6a0cf2df2d1907508e56d9de9ba7fab502e5/session/session.go#L1990">this commentary</a> in <code>loadCommonGlobalVariablesIfNeeded</code>.</p>
<p><img alt="defaultSysVars" loading="lazy" src="/posts/images/20200728191527.webp"></p>
<h2 id="metrics">Metrics</h2>
<p>Compared to system variables, Metrics in TiDB are simpler, or straightforward. The most common Metrics are Histogram and Counter, the former is used to record actual values for an operation and the latter records occurrences of fixed events.
All Metrics in TiDB are uniformly located <a href="https://github.com/pingcap/tidb/tree/cbc225fa17c93a3f58bef41b5accb57beb0d9586/metrics">here</a>, with AlertManager and Grafana scripts also available separately under alertmanager and grafana.</p>
<p>There are many Metrics, and from a beginner&rsquo;s perspective, it&rsquo;s best to focus on a specific monitoring example. Let&rsquo;s take the TPS (transactions per second) panel as an example.</p>
<p><img alt="tps" loading="lazy" src="/posts/images/20200729205545.webp"></p>
<p>Click EDIT and you will see the monitoring formula is:</p>
<p><img alt="tps2" loading="lazy" src="/posts/images/20200729210124.webp"></p>
<p>The <code>tidb_session_transaction_duration_seconds</code> is the name of this specific metric. Since it is a histogram, it can actually be expressed as three types of values: sum, count, and bucket, which represent the total sum of values, the count (which functions the same as a counter), and the distribution by bucket, respectively.</p>
<p>In this context, [1m] represents a time window of 1 minute, indicating the precision of the measurement. The rate function calculates the slope, essentially the rate of change, indicating how many times something occurs per second. The sum function is used for aggregation, and when combined with by (type, txn_mode), it represents aggregation by the dimensions of type and txn_mode.</p>
<p>The Legend below displays the dimensions above using {{type}}-{{txn_mode}}. When surrounded by {{}}, it can display the actual label names.</p>
<p>In this representation, the final states of transactions are commit, abort, and rollback. A commit indicates a successful user-initiated transaction, rollback indicates a user-initiated rollback (which cannot fail), and abort indicates a user-initiated commit that failed.</p>
<p>The second label, txn_mode, refers to two modes: optimistic and pessimistic transactions. There&rsquo;s nothing further to explain about these modes.</p>
<p>Corresponding to the code:</p>
<p><img alt="alt text" loading="lazy" src="/posts/images/20200729211352.webp"></p>
<p>This segment of code shows that <code>tidb_session_transaction_duration_seconds</code> is divided into several parts, including namespace and subsystem. Generally, to find a variable in a formula like <code>tidb_session_transaction_duration_seconds_count</code> within TiDB code, you need to remove the first two words and the last word.</p>
<p>From this code snippet, you can see it&rsquo;s a histogram, specifically a HistogramVec, which is an array of histograms because it records data with several different labels. The labels LblTxnMode and LblType are these two labels.</p>
<p><img alt="alt text" loading="lazy" src="/posts/images/20200729211511.webp"></p>
<p>Checking the references, there is a place for registration, which is in the main function we discussed in the first article, where metrics are registered.</p>
<p><img alt="alt text" loading="lazy" src="/posts/images/20200729211725.webp"></p>
<p>Other references show how metrics are instantiated. Why do we do this? Mainly because as the number of labels increases, the performance of metrics becomes poorer, which is related to Prometheus&rsquo;s implementation. We had no choice but to create many instantiated global variables.</p>
<p><img alt="alt text" loading="lazy" src="/posts/images/20200729211935.webp"></p>
<p>Taking the implementation of Rollback as an example, its essence is to record the actual execution time of a transaction when Rollback is truly executed. Since it’s a histogram, it is also used as a counter in this instance.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to Read TiDB Source Code (Part 2)</title>
      <link>https://blog.minifish.org/posts/how-to-read-tidb-source-code-part-2/</link>
      <pubDate>Sun, 12 Jul 2020 12:09:00 +0800</pubDate>
      <guid>https://blog.minifish.org/posts/how-to-read-tidb-source-code-part-2/</guid>
      <description>&lt;p&gt;Continuing from &lt;a href=&#34;https://blog.minifish.org/posts/tidb1&#34;&gt;the previous article&lt;/a&gt;, we learned how to set up the environment for reading code and where to start reading the code. In this part, we&amp;rsquo;ll introduce methods for viewing code based on some common needs.&lt;/p&gt;
&lt;h2 id=&#34;how-to-check-the-support-level-of-a-syntax&#34;&gt;How to Check the Support Level of a Syntax&lt;/h2&gt;
&lt;p&gt;There are usually two methods:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check through the parser repo&lt;/li&gt;
&lt;li&gt;Directly check within the TiDB repo&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Both of these methods require the &lt;a href=&#34;https://blog.minifish.org/posts/tidb1#%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA&#34;&gt;environment setup from the previous article&lt;/a&gt;. If you haven&amp;rsquo;t tried that yet, give it a go.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Continuing from <a href="/posts/tidb1">the previous article</a>, we learned how to set up the environment for reading code and where to start reading the code. In this part, we&rsquo;ll introduce methods for viewing code based on some common needs.</p>
<h2 id="how-to-check-the-support-level-of-a-syntax">How to Check the Support Level of a Syntax</h2>
<p>There are usually two methods:</p>
<ol>
<li>Check through the parser repo</li>
<li>Directly check within the TiDB repo</li>
</ol>
<p>Both of these methods require the <a href="/posts/tidb1#%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA">environment setup from the previous article</a>. If you haven&rsquo;t tried that yet, give it a go.</p>
<h3 id="preparation">Preparation</h3>
<ol>
<li>
<p>Install GoYacc Support</p>
<p><img alt="goyacc" loading="lazy" src="/posts/images/20200712124300.webp"></p>
<p>The GoYacc Support plugin is a creation by a colleague at our company, a third-party plugin officially accepted by JetBrains, a well-regarded product. It includes syntax highlighting and intelligence, which is great!</p>
</li>
<li>
<p>Download <a href="https://github.com/pingcap/parser">parser repo</a></p>
<p>If you&rsquo;re checking syntax directly from the parser, you need to download it manually. If you&rsquo;re navigating from TiDB, IDEA will automatically download the code, so no extra steps are needed.</p>
</li>
</ol>
<h3 id="check-via-parser-repo">Check via parser repo</h3>
<p>Open the parser using IDEA, switch to the branch you need, and locate the parser.y file. However, it is more recommended to check from within TiDB.</p>
<h3 id="check-via-tidb-repo">Check via TiDB repo</h3>
<ol>
<li>
<p>Open the TiDB project with IDEA and switch to the required branch</p>
<p><img alt="co" loading="lazy" src="/posts/images/20200712183012.webp"></p>
</li>
<li>
<p>Find the parser.y file; make sure to select the broadest search scope</p>
<p><img alt="parser.y" loading="lazy" src="/posts/images/20200712183658.webp"></p>
<p>Alternatively, you can find it in the file list,</p>
<p><img alt="parser.y2" loading="lazy" src="/posts/images/20200712184101.webp"></p>
<p><img alt="parser.y3" loading="lazy" src="/posts/images/20200712184157.webp"></p>
</li>
</ol>
<p>Let&rsquo;s take checking the <code>SHOW ENGINES</code> SQL statement as an example.</p>
<p>The entry point for the entire statement parsing is <a href="https://github.com/pingcap/parser/blob/f56688124d8bbba98ca103dbcc667d0e3b9bef30/parser.y#L1309-L1308">Start</a>. Below it is the StatementList, followed by Statement. Under the large list of Statements, you can find ShowStmt.</p>
<p><img alt="parser.y4" loading="lazy" src="/posts/images/20200712184841.webp"></p>
<p>However, ShowStmt is actually quite complex. Another way is to directly search for <code>ShowEngines</code> within parser.y, since naming follows Golang conventions, with camel case and capitalized letters for public exposure. Naturally, if familiar with the code, you&rsquo;d know <code>ShowEngines</code> is under <code>ShowTargetFilterable</code>. Its first branch is <code>ShowEngines</code>.</p>
<p><img alt="parser.y5" loading="lazy" src="/posts/images/20200712185533.webp"></p>
<p><strong>What is the level of support for <code>SHOW ENGINES</code>?</strong></p>
<p>You can look at how <code>ast.ShowEngines</code> is processed. Here, you can&rsquo;t just jump to it; you need to copy and search.</p>
<p><img alt="parser.y6" loading="lazy" src="/posts/images/20200712190242.webp"></p>
<p>You only need to see how it&rsquo;s processed under TiDB, and you can skip test files.</p>
<p><img alt="parser.y7" loading="lazy" src="/posts/images/20200712190752.webp"></p>
<p>One is the actual implementation,</p>
<p><img alt="parser.y7" loading="lazy" src="/posts/images/20200712190839.webp"></p>
<p>The other is the build schema, which you can ignore for now,</p>
<p><img alt="parser.y7" loading="lazy" src="/posts/images/20200712190956.webp"></p>
<p>Entering <code>fetchShowEngines</code>, you can see the specific implementation is simple, running an internal SQL to read a system table.</p>
<p><img alt="parser.y7" loading="lazy" src="/posts/images/20200712191054.webp"></p>
<p>Checking <code>SHOW ENGINES</code> ends here. You can see that it&rsquo;s fully supported.</p>
<p><strong>Which statements only have syntax support?</strong></p>
<p>Taking the temporary table creation syntax as an example, find its position in the parser.y file.</p>
<p><img alt="parser.y8" loading="lazy" src="/posts/images/20200712191711.webp"></p>
<p>It&rsquo;s an option.</p>
<p><img alt="parser.y9" loading="lazy" src="/posts/images/20200712191843.webp"></p>
<p>You can see that if the temporary table option is specified, it simply returns true with an attached warning, stating that the table is still treated as a regular table. Previously, the parser had a lot of operations that only returned without doing anything, not even a warning, but these are now rare.</p>
<h4 id="advantages-of-querying-via-tidb-repo">Advantages of Querying via TiDB repo</h4>
<p>You can see that checking via the TiDB repo allows you to find the parser&rsquo;s detailed hash using IDEA. If you check directly via the parser, you need to first look up the parser’s hash in TiDB’s go.mod, then check out to the corresponding hash in the parser. If you need to check specific implementations, you have to go back to TiDB, making back-and-forth checks less convenient compared to looking within a single project. The only advantage is the ease of blaming commit history.</p>
<h2 id="viewing-and-modifying-default-configuration">Viewing and Modifying Default Configuration</h2>
<p>The default configurations can be easily viewed in TiDB, specifically the variable <a href="https://github.com/pingcap/tidb/blob/72f6a0405837b92e40de979a4f3134d9aa19a5b3/config/config.go#L547">defaultConf</a>. The configurations listed here are the actual default settings.</p>
<p><img alt="conf1" loading="lazy" src="/posts/images/20200713172228.webp"></p>
<p>Taking the first Host configuration as an example, it has a mapping to toml and json files.</p>
<p><img alt="conf2" loading="lazy" src="/posts/images/20200713172535.webp"></p>
<p>This essentially shows how it&rsquo;s written in a toml file. The <code>DefHost</code> following it is the specific default value.</p>
<p><img alt="conf3" loading="lazy" src="/posts/images/20200713180137.webp"></p>
<p>Something important to note is that configurations have a hierarchical relationship. For example, the log-related configuration in the configuration file is:</p>
<p><img alt="conf4" loading="lazy" src="/posts/images/20200715164756.webp"></p>
<p>In the code, it is represented as:</p>
<p><img alt="conf5" loading="lazy" src="/posts/images/20200715164930.webp"></p>
<p>This denotes a configuration called &ldquo;level&rdquo; under the log configuration.</p>
<p>What if you want to add more levels? For instance, the most complex configuration for CopCache adds another layer under tikv-client called copr-cache.</p>
<p><img alt="conf6" loading="lazy" src="/posts/images/20200715165243.webp"></p>
<p>Since toml files do not support multi-level nesting, this leads to the most complex configuration writing in TiDB.</p>
<p><img alt="conf6" loading="lazy" src="/posts/images/20200715165456.webp"></p>
<p>To use non-default configurations with the TiDB started through IDEA as mentioned above, the simplest way is to modify this defaultConf.</p>
<h2 id="summary">Summary</h2>
<p>From this, you can see that checking whether a statement is supported, and whether it’s just syntax support or has a specific implementation, can be achieved with the described methods. You also learned how to view and modify default configurations, allowing you to conduct some verifications yourself. In the next article, I plan to introduce TiDB’s system variables.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to Read TiDB Source Code (Part 1)</title>
      <link>https://blog.minifish.org/posts/how-to-read-tidb-source-code-part-1/</link>
      <pubDate>Mon, 06 Jul 2020 16:51:00 +0800</pubDate>
      <guid>https://blog.minifish.org/posts/how-to-read-tidb-source-code-part-1/</guid>
      <description>&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;
&lt;p&gt;There are many articles on reading the source code of TiDB, often referred to as &lt;a href=&#34;https://pingcap.com/blog-cn/#TiDB-%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB&#34;&gt;the &amp;ldquo;Twenty-Four Chapters Scriptures&amp;rdquo;&lt;/a&gt;. However, these introductions typically proceed from a macro to a micro perspective. This series attempts to introduce how to read TiDB&amp;rsquo;s source code from an easier angle. The goals we aim to achieve are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enable readers to start reading TiDB&amp;rsquo;s code themselves, rather than understanding it passively through pre-written articles.&lt;/li&gt;
&lt;li&gt;Provide some common examples of looking into the details of the code, such as examining the scope of a variable.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After all, teaching people to fish is better than giving them fish. While the code changes often, the methods remain mostly unchanged.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>There are many articles on reading the source code of TiDB, often referred to as <a href="https://pingcap.com/blog-cn/#TiDB-%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB">the &ldquo;Twenty-Four Chapters Scriptures&rdquo;</a>. However, these introductions typically proceed from a macro to a micro perspective. This series attempts to introduce how to read TiDB&rsquo;s source code from an easier angle. The goals we aim to achieve are:</p>
<ol>
<li>Enable readers to start reading TiDB&rsquo;s code themselves, rather than understanding it passively through pre-written articles.</li>
<li>Provide some common examples of looking into the details of the code, such as examining the scope of a variable.</li>
</ol>
<p>After all, teaching people to fish is better than giving them fish. While the code changes often, the methods remain mostly unchanged.</p>
<p>Why choose TiDB to read?</p>
<ol>
<li>
<p>I am not familiar with TiKV or PD.</p>
</li>
<li>
<p>TiDB is the entry point directly interacting with users and is also the most likely to be questioned.</p>
</li>
<li>
<p>TiDB can run independently and be debugged. If you want to run some SQL after reading the code to verify your understanding, it can be easily done.</p>
</li>
</ol>
<h2 id="preparations">Preparations</h2>
<ol>
<li>
<p>A development machine</p>
<p>TiDB is a pure Golang project. It can be conveniently developed on Linux, MacOS, and even Windows. My environment is Windows 10.</p>
</li>
<li>
<p>A copy of the TiDB source code, available for download at the <a href="https://github.com/pingcap/tidb">official repo</a>.</p>
</li>
<li>
<p><a href="https://golang.org/">Golang</a> environment, following the official guide is straightforward.</p>
</li>
<li>
<p>Goland or IntelliJ IDEA + Golang plugin</p>
<p>I personally feel there&rsquo;s no difference between the two. Why not recommend VSCode + Golang plugin? Mainly because I&rsquo;m used to the JetBrains suite, and indeed commercial software tends to be higher quality than community software. For long-term use, it&rsquo;s recommended to pay for it. Students can use it for free, but need to renew the license every year.</p>
</li>
</ol>
<h2 id="environment-setup">Environment Setup</h2>
<ol>
<li>
<p>After installing the Golang environment, remember to set the GOPATH.</p>
</li>
<li>
<p>The TiDB code doesn&rsquo;t need to be developed under the GOPATH, so you can place it anywhere. I usually create a directory called work and throw various codes in there.</p>
</li>
<li>
<p>Open Goland/IDEA. I use IDEA because I often look at code in other languages.</p>
</li>
<li>
<p>Open with IDEA, select the tidb directory.</p>
<p><img alt="src" loading="lazy" src="/posts/images/20200706174108.webp"></p>
</li>
<li>
<p>At this point, IDEA typically prompts you to set up GOROOT and enable Go Modules. Follow the recommendations.</p>
</li>
</ol>
<p>The environment setup is now complete.</p>
<h2 id="entry-points">Entry Points</h2>
<p>At the beginning, someone advised me to start with the session package. However, after some experience, I personally feel there are two better entry points: the <code>main</code> function and the <code>dispatch</code> function.</p>
<h3 id="main-function">main Function</h3>
<p>The <code>main</code> function of TiDB can be seen at <a href="https://github.com/pingcap/tidb/blob/6b6096f1f18a03d655d04d67a2f21d7fbfca2e3f/tidb-server/main.go#L160">link</a>. You can roughly go through what happens when starting a tidb-server from top to bottom.</p>
<p><img alt="main" loading="lazy" src="/posts/images/20200706220211.webp"></p>
<p>From top to bottom:</p>
<ul>
<li>
<p>Parse flags</p>
</li>
<li>
<p>Output version information and exit</p>
</li>
<li>
<p>Register store and monitoring</p>
</li>
<li>
<p>Configuration file check</p>
</li>
<li>
<p>Initialize temporary folders, etc.</p>
</li>
<li>
<p>Set global variables, CPU affinity, log, trace, print server information, set binlog, set monitoring</p>
</li>
<li>
<p>Create store and domain</p>
<p>The <code>createStoreAndDomain</code> method is important, as critical background threads are created here.</p>
</li>
<li>
<p>Create server and register stop signal function</p>
</li>
<li>
<p>Start the server</p>
<p>Within <code>runServer</code>, the <code>srv.Run()</code> actually brings up the tidb-server.
<img alt="run" loading="lazy" src="/posts/images/20200706221611.webp">
In the <code>Run()</code> function here, the server continuously listens to network requests, creating a new connection for each new request and using a new goroutine to serve it continually.</p>
</li>
<li>
<p>After this, cleanup work is done when the server needs to stop, ultimately writing out the logs.</p>
</li>
</ul>
<p>Thus, the entire <code>main</code> function process ends. Through the <code>main</code> function, you can see the complete lifecycle of a server from creation to destruction.</p>
<p>Additionally, with IDEA, you can easily start and debug TiDB. Click on this triangle symbol as shown in the image below:</p>
<p><img alt="run1" loading="lazy" src="/posts/images/20200706222247.webp"></p>
<p><img alt="run2" loading="lazy" src="/posts/images/20200706222457.webp"></p>
<p>A pop-up with options to run and debug the <code>main</code> function will appear. Essentially, this starts a TiDB with default configurations. TiDB defaults to using mocktikv as the storage engine, so it can be started on a single machine for various testing and validation.</p>
<p>As for how to modify the configuration for starting and debugging, this will be introduced in subsequent articles in the series.</p>
<h3 id="dispatch-function">dispatch Function</h3>
<p>From here, we can proceed further to another suitable entry point function, <code>dispatch</code>.</p>
<p>The <code>dispatch</code> function has several characteristics:</p>
<ol>
<li>
<p>Requests coming from clients only enter the <code>dispatch</code> function, meaning from this point onward, user requests are executed. If you set breakpoints here, you can conveniently filter out SQL executed by internal threads.</p>
</li>
<li>
<p>From here, various requests are dispatched into different processing logic, ensuring you don’t miss any user requests. It avoids situations like spending significant time reading text protocol code only to find out the user is actually using a binary protocol.</p>
</li>
<li>
<p><code>dispatch</code> itself is located at a very early stage, meaning its parameters mostly come directly from the client&rsquo;s initial information. If it&rsquo;s a text protocol, directly reading parameters can parse out the SQL text.</p>
</li>
</ol>
<p><img alt="dispatch1" loading="lazy" src="/posts/images/20200707150344.webp"></p>
<p>At the start, <code>dispatch</code> primarily focuses on obtaining tokens corresponding to the token-limit parameter. Requests that can&rsquo;t get a token won&rsquo;t execute, which explains why you can create many connections but only 1000 SQL executions are allowed simultaneously by default.</p>
<p>Next, we enter the most crucial switch case:</p>
<p><img alt="dispatch2" loading="lazy" src="/posts/images/20200707150736.webp"></p>
<p>These commands are MySQL protocol commands, so it&rsquo;s apparent from here exactly what TiDB implements. For comparison, you can refer to <a href="https://dev.mysql.com/doc/internals/en/text-protocol.html">this link</a> (this link is only for the text protocol). For full details, see the figure below:</p>
<p><img alt="dispatch3" loading="lazy" src="/posts/images/20200707151452.webp"></p>
<p>Within <code>dispatch</code>, the most important are <code>mysql.ComQuery</code>, as well as the trio <code>mysql.ComStmtPrepare</code>, <code>mysql.ComStmtExecute</code>, and <code>mysql.ComStmtClose</code>. The latter trio is more frequently used in actual production, hence even more important. In contrast, <code>mysql.ComQuery</code> is generally used only for some simple tests and validations.</p>
<p>Since <code>dispatch</code> is the entry point for interfacing with clients, it can conveniently tally how many requests the database has handled. The so-called QPS derived from monitoring statistics is essentially the number of times this function executes per second. Here arises an issue: in cases like multi-query requests, such as <code>select 1; select 1; select 1;</code>, multiple statements sent together are regarded as a single request by <code>dispatch</code>, but as multiple by clients. While using the binary protocol, some clients prepare a statement, then execute, and finally close it. Seemingly equivalent to executing a single SQL from the client&rsquo;s perspective, the database actually completes three requests.</p>
<p>In summary, users’ perceived QPS may not necessarily align with the number of <code>dispatch</code> function calls. In later versions, the QPS panel in TiDB&rsquo;s monitoring was changed to CPS, which stands for Commands Per Second, representing the number of commands executed per second.</p>
<p>Looking at the callers of <code>dispatch</code> can also reveal information that helps explain some frequently asked questions:</p>
<p><img alt="dispatch4" loading="lazy" src="/posts/images/20200707154120.webp"></p>
<ol>
<li>
<p>An EOF error in <code>dispatch</code> typically means the client has actively disconnected, so there&rsquo;s no need to maintain the database connection, and it is severed.</p>
</li>
<li>
<p>In case of an undetermined error (indicating a transaction&rsquo;s commit is uncertain—whether it has succeeded or failed needs manual intervention for verification), manual intervention is required immediately, and the connection will be closed.</p>
</li>
<li>
<p>If writing binlog fails and <code>ignore-error = false</code>, previously the tidb-server process wouldn&rsquo;t exit but couldn&rsquo;t provide services. Now, the tidb-server will exit directly.</p>
</li>
<li>
<p>For all other <code>dispatch</code> errors, the connection will not be closed, allowing service to continue, but the failure information will be logged as &ldquo;command dispatched failed&rdquo;, which is arguably one of the most critical logs for TiDB.</p>
</li>
</ol>
<h2 id="conclusion">Conclusion</h2>
<p>This concludes the introduction from setting up the environment to finding a reasonable entry point to start reading code. Subsequent posts in the series will cover aspects such as configuration (adjustments, default values), variables (default values, scope, actual range, activation), supported syntax, etc. Stay tuned.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
