mirror of
https://github.com/postgres/postgres.git
synced 2025-11-25 12:03:53 +03:00
Move buffer I/O and content LWLocks out of the main tranche.
Move the content lock directly into the BufferDesc, so that locking and pinning a buffer touches only one cache line rather than two. Adjust the definition of BufferDesc slightly so that this doesn't make the BufferDesc any larger than one cache line (at least on platforms where a spinlock is only 1 or 2 bytes). We can't fit the I/O locks into the BufferDesc and stay within one cache line, so move those to a completely separate tranche. This leaves a relatively limited number of LWLocks in the main tranche, so increase the padding of those remaining locks to a full cache line, rather than allowing adjacent locks to share a cache line, hopefully reducing false sharing. Performance testing shows that these changes make little difference on laptop-class machines, but help significantly on larger servers, especially those with more than 2 sockets. Andres Freund, originally based on an earlier patch by Simon Riggs. Review and cosmetic adjustments (including heavy rewriting of the comments) by me.
This commit is contained in:
@@ -115,8 +115,8 @@ typedef struct buftag
|
||||
* Note: buf_hdr_lock must be held to examine or change the tag, flags,
|
||||
* usage_count, refcount, or wait_backend_pid fields. buf_id field never
|
||||
* changes after initialization, so does not need locking. freeNext is
|
||||
* protected by the buffer_strategy_lock not buf_hdr_lock. The LWLocks can take
|
||||
* care of themselves. The buf_hdr_lock is *not* used to control access to
|
||||
* protected by the buffer_strategy_lock not buf_hdr_lock. The LWLock can
|
||||
* take care of itself. The buf_hdr_lock is *not* used to control access to
|
||||
* the data in the buffer!
|
||||
*
|
||||
* An exception is that if we have the buffer pinned, its tag can't change
|
||||
@@ -133,22 +133,24 @@ typedef struct buftag
|
||||
*
|
||||
* We use this same struct for local buffer headers, but the lock fields
|
||||
* are not used and not all of the flag bits are useful either.
|
||||
*
|
||||
* Be careful to avoid increasing the size of the struct when adding or
|
||||
* reordering members. Keeping it below 64 bytes (the most common CPU
|
||||
* cache line size) is fairly important for performance.
|
||||
*/
|
||||
typedef struct BufferDesc
|
||||
{
|
||||
BufferTag tag; /* ID of page contained in buffer */
|
||||
BufFlags flags; /* see bit definitions above */
|
||||
uint16 usage_count; /* usage counter for clock sweep code */
|
||||
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 */
|
||||
|
||||
slock_t buf_hdr_lock; /* protects the above fields */
|
||||
|
||||
int buf_id; /* buffer's index number (from 0) */
|
||||
int freeNext; /* link in freelist chain */
|
||||
|
||||
LWLock *io_in_progress_lock; /* to wait for I/O to complete */
|
||||
LWLock *content_lock; /* to lock access to buffer contents */
|
||||
LWLock content_lock; /* to lock access to buffer contents */
|
||||
} BufferDesc;
|
||||
|
||||
/*
|
||||
@@ -184,6 +186,13 @@ typedef union BufferDescPadded
|
||||
|
||||
#define BufferDescriptorGetBuffer(bdesc) ((bdesc)->buf_id + 1)
|
||||
|
||||
#define BufferDescriptorGetIOLock(bdesc) \
|
||||
(&(BufferIOLWLockArray[(bdesc)->buf_id]).lock)
|
||||
#define BufferDescriptorGetContentLock(bdesc) \
|
||||
((LWLock*) (&(bdesc)->content_lock))
|
||||
|
||||
extern PGDLLIMPORT LWLockMinimallyPadded *BufferIOLWLockArray;
|
||||
|
||||
/*
|
||||
* The freeNext field is either the index of the next freelist entry,
|
||||
* or one of these special values:
|
||||
|
||||
Reference in New Issue
Block a user