• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • MySQL協議分析

    發表于:2013-10-14來源:IT博客大學習作者:hoterran點擊數: 標簽:MySQL
    每個包發送到網絡或者從網絡讀包都會先把數據包保存在net->buff里,待到net->buff滿了或者一次命令結束才會通過socket發出給對端.net->buff有個初始大小(net->max_packet),會隨讀取數據的增多而擴展.

      MySQL協議分析,主要參考MySQL Forge上的wiki和源碼.協議的全圖見這里, 給同事分享的ppt見這里,下載見這里

      MySQL協議分析

      View more presentations from ruoyi ruan

      packet number

      在做proxy的時候在這里迷糊過,翻了幾遍代碼才搞明白,細節如下:

      客戶端服務端的net->pkt_nr都從0開始.接受包時比較packet number 和net->pkt_nr是否相等,否則報packet number亂序,連接報錯;相等則pkt_nr自增.發送包時把net->pkt_nr作為packet number發送,然后對net->pkt_nr進行自增保持和對端的同步.

      接收包

      sql/net_serv.c:my_real_read

      898 if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)

      發送包

      sql/net_serv.c:my_net_write

      392 int3store(buff,len);

      393 buff[3]= (uchar) net->pkt_nr++;

      我們來幾個具體場景的packet number, net->pkt_nr的變化

      連接

      0 c ———-> s 0 connect

      0 c <—-0——s 1 handshake

      2 c —-1—->s 1 auth

      2c <—-2——s 0 ok

      開始兩方都為0,服務端發送handshake packet(pkt=0)之后自增為1,然后等待對端發送過來pkt=1的包

      查詢

      每次查詢,服務客戶端都會對net->pkt_nr進行清零

      include/mysql_com.h

      388 #define net_new_transaction(net) ((net)->pkt_nr=0)

      sql/sql_parse.cc:do_command

      805 net_new_transaction(net);

      sql/client.c:cli_advanced_command

      800 net_clear(&mysql->net, (command != COM_QUIT));

      開始兩方net->pkt_nr皆為0, 命令發送后客戶端端為1,服務端開始發送分包,分包的pkt_nr的依次遞增,客戶端的net->pkt_nr也隨之增加.

      1 c ——0—-> s 0 query

      1 c <—-1——s 2 resultset

      2 c <—-2——s 3 resultset

      解包的細節

      my_net_read負責解包,首先讀取4個字節,判斷packet number是否等于net->pkt_nr然后再次讀取packet_number長度的包體。

      偽代碼如下:

      remain=4

      for(i = 0; i < 2; i++) {

      //數據是否讀完

      while (remain>0) {

      length = read(fd, net->buff, remain)

      remain = remain - length

      }

      //第一次

      if (i=0) {

      remain = uint3korr(net->buff+net->where_b);

      }

      }

      網絡層優化

      從ppt里可以看到,一個resultset packet由多個包組成,如果每次讀寫包都導致系統調用那肯定是不合理,常規優化方法:寫大包加預讀

      net->buff

      每個包發送到網絡或者從網絡讀包都會先把數據包保存在net->buff里,待到net->buff滿了或者一次命令結束才會通過socket發出給對端.net->buff有個初始大小(net->max_packet),會隨讀取數據的增多而擴展.

      vio->read_buffer

      每次從網絡讀包,并不是按包的大小讀取,而是會盡量讀取2048個字節,這樣一個resultset包的讀取不會再引起多次的系統調用了.header packet讀取完畢后, 接下來的field,eof, row apcket讀取僅僅需要從vio-read_buffer拷貝指定字節的數據即可.

      MySQL api說明

      api和MySQL客戶端都會使用sql/client.c這個文件,解包的過程都是使用sql/client.c:cli_read_query_result.

      mysql_store_result來解析row packet,并把數據存儲到res->data里,此時所有數據都存內存里了.

      mysql_fetch_row僅僅是使用內部的游標,遍歷result->data里的數據

      3052 if (!res->data_cursor)

      3053 {

      3054 DBUG_PRINT("info",("end of data"));

      3055 DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);

      3056 }

      3057 tmp = res->data_cursor->data;

      3058 res->data_cursor = res->data_cursor->next;

      3059 DBUG_RETURN(res->current_row=tmp);

      mysql_free_result是把result->data指定的行數據釋放掉.

    原文轉自:http://blogread.cn/it/article/5604

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>