<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 背景 我們執行一個大SQL時(長度大于512M),會返回如下錯誤: ~~~ ERROR: invalid memory alloc request size 1073741824 ~~~ ## 復現 我們首先復現出來這個問題 1. 創建表 ~~~ create table byteatable(id int, obj bytea); ~~~ 2. 插入512M大對象 ~~~ #!/bin/bash data='a' for ((i=1;i<=29;i++)); do data=$data$data done echo 'build ok' psql -U postgres -d postgres << EOF insert into byteatable(id,obj) values (1,"$data"); EOF echo 'OK' ~~~ 執行腳本后就能復現出來了 ~~~ ERROR: invalid memory alloc request size 1073741824 ~~~ ## BUG分析 我們先找到出現這個錯誤的位置。 源碼位置: ~~~ void * MemoryContextAlloc(MemoryContext context, Size size) { void *ret; AssertArg(MemoryContextIsValid(context)); if (!AllocSizeIsValid(size)) elog(ERROR, "invalid memory alloc request size %zu", size); context->isReset = false; ret = (*context->methods->alloc) (context, size); VALGRIND_MEMPOOL_ALLOC(context, ret, size); return ret; } #define AllocSizeIsValid(size) ((Size) (size) <= MaxAllocSize) #define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */ ~~~ 這里限制的內存是1G - 1,而我們插入的大SQL需要的內存沒有1G,那么為什么還提示非法的申請內存大小呢?通過調試跟蹤,我們發現是在詞法分析的時刻出錯的。主要問題是在詞法分析的內存申請機制上,申請的內存肯定不能少于sql的長度,如果當前申請的內存不夠用,那么將重新申請當前內存乘以2的內存大小。 ~~~ int literallen; /* actual current string length */ int literalalloc; /* current allocated buffer size */ //當前申請內存初始化 yyext->literalalloc = 1024; ~~~ ~~~ static void addlit(char *ytext, int yleng, core_yyscan_t yyscanner) { /* enlarge buffer if needed */ if ((yyextra->literallen + yleng) >= yyextra->literalalloc) { do { yyextra->literalalloc *= 2; } while ((yyextra->literallen + yleng) >= yyextra->literalalloc); yyextra->literalbuf = (char *) repalloc(yyextra->literalbuf, yyextra->literalalloc); } /* append new data */ memcpy(yyextra->literalbuf + yyextra->literallen, ytext, yleng); yyextra->literallen += yleng; } static void addlitchar(unsigned char ychar, core_yyscan_t yyscanner) { /* enlarge buffer if needed */ if ((yyextra->literallen + 1) >= yyextra->literalalloc) { yyextra->literalalloc *= 2; yyextra->literalbuf = (char *) repalloc(yyextra->literalbuf, yyextra->literalalloc); } } ~~~ 從源碼中可以看出,每次申請原申請內存的2倍,即yyextra->literalalloc *= 2; 而最大申請內存限制是 ~~~ #define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */ ~~~ 所以我們在詞法分析能申請的最大內存是2^29 = 536870912,如果詞法分析SQL語句需要的內存大于536870912,那么申請的內存需要再乘2,就會得到2^30 = 1073741824,超過MaxAllocSize=0x3fffffff= 1073741823。所以會提示錯誤: ~~~ ERROR: invalid memory alloc request size 1073741824 ~~~ 當然不僅僅是插入一個大對象才會引起這個問題,只要是SQL語句長度大于512M都是出現這個錯誤,我們可以使用select復現: ~~~ do language plpgsql $$ declare v_text text := 'a'; begin for i in 1..29 loop v_text:=v_text||v_text; end loop; execute $_$select '$_$||v_text||$_$'$_$; raise notice 'execute a sql large than 512MB success.'; exception when others then raise notice 'execute a sql large than 512MB failed.'; end; $$; ~~~ ## BUG修復 其實申請MaxAllocSize是可行的,通過修改源碼實現,每當申請的內存大于MaxAllocSize并且SQL需要的長度小于MaxAllocSize時,我們就申請MaxAllocSize大小的內存。 ~~~ static void addlit(char *ytext, int yleng, core_yyscan_t yyscanner) { /* enlarge buffer if needed */ if ((yyextra->literallen + yleng) >= yyextra->literalalloc) { do { yyextra->literalalloc *= 2; } while ((yyextra->literallen + yleng) >= yyextra->literalalloc); /* we can not alloc more than MaxAllocSize */ if (yyextra->literalalloc > MaxAllocSize && (yyextra->literallen + yleng) < MaxAllocSize) yyextra->literalalloc = MaxAllocSize; yyextra->literalbuf = (char *) repalloc(yyextra->literalbuf, yyextra->literalalloc); } /* append new data */ memcpy(yyextra->literalbuf + yyextra->literallen, ytext, yleng); yyextra->literallen += yleng; } ~~~ ~~~ static void addlitchar(unsigned char ychar, core_yyscan_t yyscanner) { /* enlarge buffer if needed */ if ((yyextra->literallen + 1) >= yyextra->literalalloc) { yyextra->literalalloc *= 2; /* we can not alloc more than MaxAllocSize */ if (yyextra->literalalloc > MaxAllocSize && (yyextra->literallen + 1) < MaxAllocSize) yyextra->literalalloc = MaxAllocSize; yyextra->literalbuf = (char *) repalloc(yyextra->literalbuf, yyextra->literalalloc); } /* append new data */ yyextra->literalbuf[yyextra->literallen] = ychar; yyextra->literallen += 1; } ~~~ 修復之后可以正常插入了 ~~~ $ sh pgtest.sh build ok INSERT 0 1 OK ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看