• Tom Lane's avatar
    Improve timeout.c's handling of repeated timeout set/cancel. · 09cf1d52
    Tom Lane authored
    A very common usage pattern is that we set a timeout that we don't
    expect to reach, cancel it after a little bit, and later repeat.
    With the original implementation of timeout.c, this results in one
    setitimer() call per timeout set or cancel.  We can do a lot better
    by being lazy about changing the timeout interrupt request, namely:
    (1) never cancel the outstanding interrupt, even when we have no
    active timeout events;
    (2) if we need to set an interrupt, but there already is one pending
    at or before the required time, leave it alone.  When the interrupt
    happens, the signal handler will reschedule it at whatever time is
    then needed.
    
    For example, with a one-second setting for statement_timeout, this
    method results in having to interact with the kernel only a little
    more than once a second, no matter how many statements we execute
    in between.  The mainline code might never call setitimer() at all
    after the first time, while each time the signal handler fires,
    it sees that the then-pending request is most of a second away,
    and that's when it sets the next interrupt request for.  Each
    mainline timeout-set request after that will observe that the time
    it wants is past the pending interrupt request time, and do nothing.
    
    This also works pretty well for cases where a few different timeout
    lengths are in use, as long as none of them are very short.  But
    that describes our usage well.
    
    Idea and original patch by Thomas Munro; I fixed a race condition
    and improved the comments.
    
    Discussion: https://postgr.es/m/CA+hUKG+o6pbuHBJSGnud=TadsuXySWA7CCcPgCt2QE9F6_4iHQ@mail.gmail.com
    09cf1d52
timeout.c 21.1 KB