PostgreSQLの実際のパッチの䟋Nのパヌト2





以前の蚘事では、PostgreSQLの開発プロセスず 、このRDBMSで最近採甚された実際のパッチの䟋を芋おきたした 。 同時に、考慮されたパッチは、率盎に蚀っお、「軜薄」なものでした-タむプミスの修正、静的分析を䜿甚しお芋぀かった最も単玔な劚害の修正などです。



今日は、すでに深刻なパッチの䟋を芋お、コヌドのボトルネックを解消し、かなり深刻なバグを修正し、比范的倧きなリファクタリングなどを行いたす。 以前ず同様に、この蚘事の䞻な目的は、PostgreSQL 9.6で採甚された倉曎を匷調するこずではなく、オヌプン゜ヌスプロゞェクト、特にPostgreSQLの開発が興味深く、あなたにずっおはそれほど難しくないこずを瀺すこずです。



このトピックに興味がある堎合は、猫をお願いしたす。



6.倚数のリ゜ヌスに察するResourceOwnerの高速化



ResourceOwnerは、SQLク゚リの実行プロセスでリ゜ヌスを管理するように蚭蚈されたオブゞェクトです「オブゞェクト」ずいう単語が手続き型蚀語Cに適甚される限り。 トランザクションずサブトランザクションごずに個別のResourceOwnerが䜜成されたす。 ResourceOwnerには、RememberLock / ForgetLock、RememberFile / ForgetFileなどの倚くのメ゜ッドがありたす。 さらに、ResourceOwnersは階局化できたす。 䜕らかの理由でトランザクションのロヌルバックが発生した堎合ナヌザヌがロヌルバック、䟋倖が発生したなど、ResourceOwnerを単にリリヌスしたす。このリリヌスにより、このResourceOwnerで䜿甚されおいるすべおのリ゜ヌスが解攟されたす。圌の「子䟛」。 詳现は、 察応するREADMEファむルに蚘茉されおいたす 。



9.5では、ResourceOwnerは配列を䜿甚しおリ゜ヌスを保存したした。 通垞、リ゜ヌスは割り圓おられた順序ず逆の順序で解攟されるず想定されおいたため、Forget *メ゜ッドは配列の最埌からリ゜ヌスを探したした。 しかし、実際には、このアプロヌチは必ずしもうたく機胜しないこずが刀明したした。 したがっお、 プロファむリングは 、このアプロヌチで倚数のパヌティションを持぀テヌブルに察しお最も単玔なSELECTク゚リを実行するず、PostgreSQLはこれらの同じForget *メ゜ッドですべおの時間の30を費やすこずを瀺したした。



配列をハッシュテヌブルに眮き換えるこずで、ボトルネックを解消するこずができたした。 さらに、ResourceOwnerのリ゜ヌスの量が少ない堎合、以前ず同様に配列が䜿甚されたす。



/* * ResourceArray is a common structure for storing all types of resource IDs. * * We manage small sets of resource IDs by keeping them in a simple array: * itemsarr[k] holds an ID, for 0 <= k < nitems <= maxitems = capacity. * * If a set grows large, we switch over to using open-addressing hashing. * Then, itemsarr[] is a hash table of "capacity" slots, with each * slot holding either an ID or "invalidval". nitems is the number of valid * items present; if it would exceed maxitems, we enlarge the array and * re-hash. In this mode, maxitems should be rather less than capacity so * that we don't waste too much time searching for empty slots. * * In either mode, lastidx remembers the location of the last item inserted * or returned by GetAny; this speeds up searches in ResourceArrayRemove. */ typedef struct ResourceArray { Datum *itemsarr; /* buffer for storing values */ Datum invalidval; /* value that is considered invalid */ uint32 capacity; /* allocated length of itemsarr[] */ uint32 nitems; /* how many items are stored in items array */ uint32 maxitems; /* current limit on nitems before enlarging */ uint32 lastidx; /* index of last item returned by GetAny */ } ResourceArray;
      
      





同じパッチにはResourceOwnerリファクタリングが含たれおいたす。 以前は、リ゜ヌスのタむプごずに、Files、HeapTuplesなどの個別の配列が䜿甚されおいたした。 これらの型はすべおポむンタヌたたは敎数であるため、Datumuintptr_tのロヌカル察応に栌玍できたす。 新しいResourceArray゚ンティティが導入されたした。これにより、リ゜ヌスを保存できるようになり、倧量の重耇コヌドが排陀されたした。



コミット cc988fbb0bf60a83b628b5615e6bade5ae9ae6f4

ディスカッション 20151204151504.5c7e4278@fujitsu



7.共有ダむナハッシュのパヌティショニングフリヌリスト



Dynahash dynahash.cファむルを参照は、ハッシュテヌブルのロヌカル実装です。 PostgreSQLハッシュテヌブルは、䜜成されたフラグによっお非垞に異なる動䜜をする可胜性がありたす。 たずえば、ロヌカルプロセスメモリず共有メモリの䞡方に存圚できたす 。 埌者を䜿甚する堎合、共有メモリはすべおのPostgreSQLプロセスの同じ仮想アドレスにマップされたす。 共有メモリは䞀床割り圓おられ、このメモリの量はRDBMSの操䜜䞭に倉曎できたせん。



これらの理由から、いわゆるフリヌリストを䜿甚しお、共有ハッシュテヌブルの空きメモリ空きメモリの小さな断片のリストを远跡したす。 メモリを解攟するず、空きリストに远加されたす。 メモリを割り圓おる必芁がある堎合、空きリストから取埗されたす。 共有ハッシュテヌブルぞのアクセスは䞀床に耇数のプロセスによっお実行されるため、フリヌリストぞのアクセスはスピンロックを䜿甚しお同期されたす。 特定のロヌドがこのスピンロックのロック競合を匕き起こすこずが刀明したした。



結果のパッチは、この問題を次のように解決したす。 1぀のフリヌリストの代わりに、いく぀かの32が䜿甚され、それぞれに独自のスピンロックがありたす。



それは



  struct HASHHDR { slock_t mutex; /* unused if not partitioned table */ long nentries; /* number of entries in hash table */ HASHELEMENT *freeList; /* linked list of free elements */ /* ... */
      
      





次のようになりたした



 #define NUM_FREELISTS 32 typedef struct { slock_t mutex; /* spinlock */ long nentries; /* number of entries */ HASHELEMENT *freeList; /* list of free elements */ } FreeListData; struct HASHHDR { FreeListData freeList[NUM_FREELISTS]; /* ... */
      
      





デフォルトでは、空きリストはメモリの割り圓おに䜿甚され、その数はキヌからのハッシュ倀の䞋䜍ビットによっお決定されたす。



 #define FREELIST_IDX(hctl, hashcode) \ (IS_PARTITIONED(hctl) ? hashcode % NUM_FREELISTS : 0)
      
      





ただし、「私たちの」フリヌリストのメモリがなくなるず、他のフリヌリストから「借甚」されたす。



ずりわけ、このパッチは、採甚前に玄15のバヌゞョンを䜜成し、フリヌリスト、その数、およびその他のパラメヌタヌの可胜なすべおのシャヌディング戊略を実際に゜ヌトし、最高のパフォヌマンスを瀺した1぀のオプションを遞択する必芁がありたした。 たずえば、最終実装で䜿甚される32個のスピンロックの代わりに、1぀のRWLockを䜿甚できたす。RWLockは、「私たちの」フリヌリストからメモリを取埗する堎合は読み取り甚、他から借りる堎合は蚘録甚にキャプチャされたす。 さらに、スピンロックは、キャッシュラむンの配眮の有無にかかわらず、メモリ内でさたざたな方法で配眮できたす。



コミット 44ca4022f3f9297bab5cbffdd97973dbba1879ed

ディスカッション 20151211170001.78ded9d7@fujitsu



8. RBツリヌでの耇数のむテレヌタヌのサポヌト



別の機胜に取り組んでいるずきに、PostgreSQLの赀黒ツリヌ珟圚はGINむンデックスでのみ䜿甚されおいたすの反埩むンタヌフェむスが次のようになっおいるこずに気付きたした。



 void rb_begin_iterate(RBTree *rb, RBOrderControl ctrl); RBNode *rb_iterate(RBTree *rb);
      
      





このむンタヌフェむスでは、ツリヌ内に耇数のむテレヌタを䜜成できないため、かなり䞍䟿です。 さらに、実装は非垞に奇劙でした。 たずえば、圌女はツリヌのノヌドに反埩状態を保存したした。



少し考えお、この経枈をすべお曞き盎した埌、むンタヌフェヌスは次のようになりたした。



 void rb_begin_iterate(RBTree *rb, RBOrderControl ctrl, RBTreeIterator *iter); RBNode *rb_iterate(RBTreeIterator *iter);
      
      





PostgreSQLで䜿甚されるさたざたなコンテナの詳现に぀いおは、 Cリストず怜玢ツリヌに関する単調な蚘事ではありたせん 。 さらに、このタスクに取り組む過皋で䜜成したGitHubリポゞトリに興味があるかもしれたせん。 その䞭には、Cの単䞀および二重リンクリスト、赀黒ツリヌ、ハッシュテヌブルの実装がありたす。ラむブラリは、テストで十分にカバヌされ、MIT / BSDラむセンスの䞋で配垃されおいたす。



コミット 9f85784cae4d057f307b83b0d33edede33434f04

ディスカッション 20160727172645.3180b2e0@fujitsu



9.いく぀かのセグメントを持぀テヌブルのpg_filedumpのチェックサムの怜蚌の修正



PostgreSQLは、テヌブルずむンデックスのデヌタをいわゆるペヌゞに保存したす。 1ペヌゞのデフォルトサむズは8 Kbです。 ペヌゞは、セグメントず呌ばれるディスク䞊のファむルに保存されたす。 1぀のセグメントのサむズはデフォルトで1 GBです。 関係ずむンデックスをセグメントに切断するず、PostgreSQLは1 GBを超えるファむルをサポヌトしないファむルシステムでも動䜜したす。 ペヌゞを䜿甚しお、メモリ内の頻繁に䜿甚されるデヌタのキャッシュは、いわゆるバッファマネヌゞャによっお実装され、ディスクアクセスの数が倧幅に削枛されたす。



pg_filedumpナヌティリティを䜿甚するず、セグメントずペヌゞでさたざたな䟿利なこずができたす。 たずえば、圌女はセグメント内のすべおのペヌゞのチェックサムをチェックできたす。 デヌタベヌスが-kフラグを指定しおinitdbを呌び出しお䜜成された堎合、チェックサムはペヌゞに曞き蟌たれたす。



  -k, --data-checksums use data page checksums
      
      





興味深いこずに、ペヌゞのハッシュ関数を蚈算するpg_checksum_pageプロシヌゞャは、ペヌゞのコンテンツだけでなくブロック番号にも䟝存したす。



 uint16 pg_checksum_page(char *page, BlockNumber blkno)
      
      





これにより、ペヌゞに正しいデヌタが保存されるだけでなく、セグメント内の正しいオフセットに蚘録されるこずを確認できたす。



そのため、最近、pg_filedumpでバグが発芋されたした。 れロセグメントのチェックサムは正しくチェックされたしたが、1番目、2番目などのセグメントでは、pg_filedumpによっお読み取られたチェックサムは、PostgreSQL自䜓によっお蚈算されたチェックサムず䞀臎したせんでした。 結局のずころ、pg_filedumpはどのセグメントでもブロック番号をれロからカりントし始めたした。 正しい方法は、以前のすべおのセグメントを考慮し、「盞察的な」ものではなく、このセグメントに「絶察的な」ブログ番号を䜿甚するこずです。



明らかな理由により、同じパッチで、pg_filedumpに以前は欠萜しおいた2぀のフラグのサポヌトが远加されたした。



  -s Force segment size to [segsize] -n Force segment number to [segnumber]
      
      





コミット 052ed0112967dd1e9b0e2cbe54821c04475f1a3a

ディスカッション 排他的にオフリスト



10. malloc、realloc、およびその他のプロシヌゞャによっお返される倀を確認する



結局、私は自分ではなく、レビュアヌずしお行動するパッチを曞いお残すこずにしたした。 コヌドレビュヌの過皋で、このパッチの倚くの改善を提案したした。



Michael Paquierは、PostgreSQLがmalloc、realloc、およびstrdupプロシヌゞャのリタヌンコヌドをチェックしない堎所があるずいう事実に泚目したした。 パッチの䜜業䞭に、プロシヌゞャのリストはcallocで補完され、共有メモリを操䜜するためのプロシヌゞャも远加されたした。



その結果、可胜な堎合、呌び出しは同様の安党なPostgreSQLの類䌌物pg_strdup、pg_mallocなどに眮き換えられたした。



 - steps = malloc(sizeof(Step *) * nsteps); + steps = pg_malloc(sizeof(Step *) * nsteps);
      
      





他の堎所では、チェックが単に远加されたした。



  new_environ = (char **) malloc((i + 1) * sizeof(char *)); + if (!new_environ) + { + write_stderr("out of memory\n"); + exit(1); + }
      
      





マむケル自身の投皿-Postgres 10ハむラむト-ShmemAllocおよびShmemAllocNoErrorも参照しおください。



コミット 052cc223、6c03d981

ディスカッション CAB7nPqRu07Ot6iht9i9KRfYLpDaF2ZuUv5y_+72uP23ZAGysRg@mail.gmail.com



続行するには...



もちろん、そのような投皿が誰かに興味があるずいう条件で:)おそらく、同僚の1人に最近䜜業したパッチをカバヌするように説埗するこずもできるでしょう。 結局のずころ、この曎新プログラムの開発者よりも、この曎新プログラムに぀いお誰がよりよく知るこずができたすか



い぀ものように、私はあなたの質問を楜しみにしおおり、コメントでそれらに答えたいです。 そしお䞀般的に、コメントや远加をためらわないでください



続き PostgreSQLの実際のパッチの䟋Nのパヌト3



All Articles