答复:[HACKERS] 答复:[HACKERS] 答复:[HACKERS] about fsync in CLOG buffer write - Mailing list pgsql-hackers

From 周正中(德歌)
Subject 答复:[HACKERS] 答复:[HACKERS] 答复:[HACKERS] about fsync in CLOG buffer write
Date
Msg-id ----.j------uHhVj$182941e2-a252-45fc-b0e2-7a370f224d68@alibaba-inc.com
Whole thread Raw
In response to about fsync in CLOG buffer write  ("张广舟(明虚)" <guangzhou.zgz@alibaba-inc.com>)
List pgsql-hackers
HI,
   Sorry, it's my misunderstand. 
   I don't read seriously SlruSelectLRUPage before.

  /* See if page already has a buffer assigned */
  for (slotno = 0; slotno < shared->num_slots; slotno++)
  {
   if (shared->page_number[slotno] == pageno &&
    shared->page_status[slotno] != SLRU_PAGE_EMPTY)
    return slotno;
  }

  /*
   * If we find any EMPTY slot, just select that one. Else choose a
   * victim page to replace.  We normally take the least recently used
   * valid page, but we will never take the slot containing
   * latest_page_number, even if it appears least recently used.  We
   * will select a slot that is already I/O busy only if there is no
   * other choice: a read-busy slot will not be least recently used once
   * the read finishes, and waiting for an I/O on a write-busy slot is
   * inferior to just picking some other slot.  Testing shows the slot
   * we pick instead will often be clean, allowing us to begin a read at
   * once.
   *
   * Normally the page_lru_count values will all be different and so
   * there will be a well-defined LRU page.  But since we allow
   * concurrent execution of SlruRecentlyUsed() within
   * SimpleLruReadPage_ReadOnly(), it is possible that multiple pages
   * acquire the same lru_count values.  In that case we break ties by
   * choosing the furthest-back page.
   *
   * Notice that this next line forcibly advances cur_lru_count to a
   * value that is certainly beyond any value that will be in the
   * page_lru_count array after the loop finishes.  This ensures that
   * the next execution of SlruRecentlyUsed will mark the page newly
   * used, even if it's for a page that has the current counter value.
   * That gets us back on the path to having good data when there are
   * multiple pages with the same lru_count.
   */
  cur_count = (shared->cur_lru_count)++;
  for (slotno = 0; slotno < shared->num_slots; slotno++)
  {
   int   this_delta;
   int   this_page_number;

   if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
    return slotno;
   this_delta = cur_count - shared->page_lru_count[slotno];
   if (this_delta < 0)
   {
    /*
     * Clean up in case shared updates have caused cur_count
     * increments to get "lost".  We back off the page counts,
     * rather than trying to increase cur_count, to avoid any
     * question of infinite loops or failure in the presence of
     * wrapped-around counts.
     */
    shared->page_lru_count[slotno] = cur_count;
    this_delta = 0;
   }
   this_page_number = shared->page_number[slotno];
   if (this_page_number == shared->latest_page_number)
    continue;
   if (shared->page_status[slotno] == SLRU_PAGE_VALID)
   {
    if (this_delta > best_valid_delta ||
     (this_delta == best_valid_delta &&
      ctl->PagePrecedes(this_page_number,
            best_valid_page_number)))
    {
     bestvalidslot = slotno;
     best_valid_delta = this_delta;
     best_valid_page_number = this_page_number;
    }
   }
   else
   {
    if (this_delta > best_invalid_delta ||
     (this_delta == best_invalid_delta &&
      ctl->PagePrecedes(this_page_number,
            best_invalid_page_number)))
    {
     bestinvalidslot = slotno;
     best_invalid_delta = this_delta;
     best_invalid_page_number = this_page_number;
    }
   }
  }

  /*
   * If all pages (except possibly the latest one) are I/O busy, we'll
   * have to wait for an I/O to complete and then retry.  In that
   * unhappy case, we choose to wait for the I/O on the least recently
   * used slot, on the assumption that it was likely initiated first of
   * all the I/Os in progress and may therefore finish first.
   */
  if (best_valid_delta < 0)
  {
   SimpleLruWaitIO(ctl, bestinvalidslot);
   continue;
  }

  /*
   * If the selected page is clean, we're set.
   */
  if (!shared->page_dirty[bestvalidslot])
   return bestvalidslot;

------------------------------------------------------------------
发件人:Andres Freund <andres@anarazel.de>
发送时间:2015年9月9日(星期三) 02:28
收件人:周正中(德歌) <dege.zzz@alibaba-inc.com>
抄 送:Amit Kapila <amit.kapila16@gmail.com>,张广舟(明虚) <guangzhou.zgz@alibaba-inc.com>,pgsql-hackers <pgsql-hackers@postgresql.org>,范孝剑(康贤) <funnyxj.fxj@alibaba-inc.com>,曾文旌(义从) <wenjing.zwj@alibaba-inc.com>,窦贤明(执白) <xianming.dxm@alibaba-inc.com>,萧少聪(铁庵) <shaocong.xsc@alibaba-inc.com>,陈新坚(惧留孙) <xinjian.chen@alibaba-inc.com>
主 题:Re: [HACKERS] 答复:[HACKERS] 答复:[HACKERS] about fsync in CLOG buffer write

Hi,

On 2015-09-08 15:58:26 +0800, 周正中(德歌) wrote:
> postgres@digoal-> cat 7.sql
> select txid_current();

> postgres@digoal-> pgbench -M prepared -n -r -P 1 -f ./7.sql -c 1 -j 1 -T 100000
> About 32K tps.
> progress: 240.0 s, 31164.4 tps, lat 0.031 ms stddev 0.183
> progress: 241.0 s, 33243.3 tps, lat 0.029 ms stddev 0.127

So you're benchmarking how fast you can assign txids. Is that actually
something meaningful? If you have other writes interleaved you'll write
much more WAL, so there'll be checkpoints and such.

FWIW, if you measure something realistic and there's checkpoints,
there'll be fewer fsyncs if you increase the slru buffer size - as
there'll often be clean buffers due to the checkpoint having written
them out.

Greetings,

Andres Freund

pgsql-hackers by date:

Previous
From: Oskari Saarenmaa
Date:
Subject: Re: jsonb_concat: make sure we always return a non-scalar value
Next
From: Fabien COELHO
Date:
Subject: Re: checkpointer continuous flushing