Re: Move PinBuffer and UnpinBuffer to atomics

Поиск
Список
Период
Сортировка
От Alexander Korotkov
Тема Re: Move PinBuffer and UnpinBuffer to atomics
Дата
Msg-id CAPpHfdsd=xR=B2jD5rCbiGnmbTrGHFZAUVMS=r_bPezDChbsKA@mail.gmail.com
обсуждение исходный текст
Ответ на Re: Move PinBuffer and UnpinBuffer to atomics  (Andres Freund <andres@anarazel.de>)
Ответы Re: Move PinBuffer and UnpinBuffer to atomics  (Alexander Korotkov <a.korotkov@postgrespro.ru>)
Re: Move PinBuffer and UnpinBuffer to atomics  (Andres Freund <andres@anarazel.de>)
Список pgsql-hackers
On Thu, Mar 31, 2016 at 7:14 PM, Andres Freund <andres@anarazel.de> wrote:
> +/*
> + * The following two macros are aimed to simplify buffer state modification
> + * in CAS loop.  It's assumed that variable "uint32 state" is defined outside
> + * of this loop.  It should be used as following:
> + *
> + * BEGIN_BUFSTATE_CAS_LOOP(bufHdr);
> + * modifications of state variable;
> + * END_BUFSTATE_CAS_LOOP(bufHdr);
> + *
> + * For local buffers, these macros shouldn't be used..  Since there is
> + * no cuncurrency, local buffer state could be chaged directly by atomic
> + * read/write operations.
> + */
> +#define BEGIN_BUFSTATE_CAS_LOOP(bufHdr) \
> +     do { \
> +             SpinDelayStatus delayStatus = init_spin_delay((Pointer)(bufHdr)); \

> +             uint32                  oldstate; \
> +             oldstate = pg_atomic_read_u32(&(bufHdr)->state); \
> +             for (;;) { \
> +                     while (oldstate & BM_LOCKED) \
> +                     { \
> +                             make_spin_delay(&delayStatus); \
> +                             oldstate = pg_atomic_read_u32(&(bufHdr)->state); \
> +                     } \
> +                     state = oldstate
> +
> +#define END_BUFSTATE_CAS_LOOP(bufHdr) \
> +                     if (pg_atomic_compare_exchange_u32(&bufHdr->state, &oldstate, state)) \
> +                             break; \
> +             } \
> +             finish_spin_delay(&delayStatus); \
> +     } while (0)

Hm. Not sure if that's not too much magic. Will think about it.

I'm not sure too...
 
>   /*
> +  * Lock buffer header - set BM_LOCKED in buffer state.
> +  */
> + uint32
> + LockBufHdr(BufferDesc *desc)
> + {
> +     uint32                  state;
> +
> +     BEGIN_BUFSTATE_CAS_LOOP(desc);
> +     state |= BM_LOCKED;
> +     END_BUFSTATE_CAS_LOOP(desc);
> +
> +     return state;
> + }
> +

Hm. It seems a bit over the top to do the full round here. How about

uint32 oldstate;
while (true)
{
    oldstate = pg_atomic_fetch_or(..., BM_LOCKED);
    if (!(oldstate & BM_LOCKED)
        break;
    perform_spin_delay();
}
return oldstate | BM_LOCKED;

Especially if we implement atomic xor on x86, that'd likely be a good
bit more efficient.

Nice idea.  Done.
 
>  typedef struct BufferDesc
>  {
>       BufferTag       tag;                    /* ID of page contained in buffer */
> -     BufFlags        flags;                  /* see bit definitions above */
> -     uint8           usage_count;    /* usage counter for clock sweep code */
> -     slock_t         buf_hdr_lock;   /* protects a subset of fields, see above */
> -     unsigned        refcount;               /* # of backends holding pins on buffer */
> -     int                     wait_backend_pid;               /* backend PID of pin-count waiter */
>
> +     /* state of the tag, containing flags, refcount and usagecount */
> +     pg_atomic_uint32 state;
> +
> +     int                     wait_backend_pid;               /* backend PID of pin-count waiter */
>       int                     buf_id;                 /* buffer's index number (from 0) */
>       int                     freeNext;               /* link in freelist chain */

Hm. Won't matter on most platforms, but it seems like a good idea to
move to an 8 byte aligned boundary. Move buf_id up?

I think so.  Done.
 
> +/*
> + * Support for spin delay which could be useful in other places where
> + * spinlock-like procedures take place.
> + */
> +typedef struct
> +{
> +     int                     spins;
> +     int                     delays;
> +     int                     cur_delay;
> +     Pointer         ptr;
> +     const char *file;
> +     int                     line;
> +} SpinDelayStatus;
> +
> +#define init_spin_delay(ptr) {0, 0, 0, (ptr), __FILE__, __LINE__}
> +
> +void make_spin_delay(SpinDelayStatus *status);
> +void finish_spin_delay(SpinDelayStatus *status);
> +
>  #endif        /* S_LOCK_H */

s/make_spin_delay/perform_spin_delay/? The former sounds like it's
allocating something or such.

Done.

I think these changes worth running benchmark again.  I'm going to run it on 4x18 Intel.


------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company 

Вложения

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Robbie Harwood
Дата:
Сообщение: Re: [PATCH v9] GSSAPI encryption support
Следующее
От: Markus Nullmeier
Дата:
Сообщение: Re: WIP: Access method extendability