diff -cpr HEAD/doc/src/sgml/config.sgml pgsql-bgwriter/doc/src/sgml/config.sgml *** HEAD/doc/src/sgml/config.sgml Mon Mar 5 09:48:58 2007 --- pgsql-bgwriter/doc/src/sgml/config.sgml Mon Mar 5 12:39:42 2007 *************** SET ENABLE_SEQSCAN TO OFF; *** 1208,1248 **** - - bgwriter_lru_percent (floating point) - - bgwriter_lru_percent configuration parameter - - - - To reduce the probability that server processes will need to issue - their own writes, the background writer tries to write buffers that - are likely to be recycled soon. In each round, it examines up to - bgwriter_lru_percent of the buffers that are nearest to - being recycled, and writes any that are dirty. - The default value is 1.0 (1% of the total number of shared buffers). - This parameter can only be set in the postgresql.conf - file or on the server command line. - - - - - - bgwriter_lru_maxpages (integer) - - bgwriter_lru_maxpages configuration parameter - - - - In each round, no more than this many buffers will be written - as a result of scanning soon-to-be-recycled buffers. - The default value is five buffers. - This parameter can only be set in the postgresql.conf - file or on the server command line. - - - - bgwriter_all_percent (floating point) --- 1208,1213 ---- *************** SET ENABLE_SEQSCAN TO OFF; *** 1290,1303 **** caused by the background writer, but leave more work to be done at checkpoint time. To reduce load spikes at checkpoints, increase these two values. - Similarly, smaller values of bgwriter_lru_percent and - bgwriter_lru_maxpages reduce the extra I/O load - caused by the background writer, but make it more likely that server - processes will have to issue writes for themselves, delaying interactive - queries. To disable background writing entirely, ! set both maxpages values and/or both ! percent values to zero. --- 1255,1269 ---- caused by the background writer, but leave more work to be done at checkpoint time. To reduce load spikes at checkpoints, increase these two values. To disable background writing entirely, ! set bgwriter_all_percent value and/or ! bgwriter_all_maxpages value to zero. ! ! ! Also, to reduce the probability that server processes will need to ! issue their own writes, the background writer tries to write buffers ! that are likely to be recycled soon. The amount of writes are adjusted ! automatically. diff -cpr HEAD/src/backend/postmaster/bgwriter.c pgsql-bgwriter/src/backend/postmaster/bgwriter.c *** HEAD/src/backend/postmaster/bgwriter.c Mon Jan 22 13:08:10 2007 --- pgsql-bgwriter/src/backend/postmaster/bgwriter.c Mon Mar 5 12:40:14 2007 *************** static volatile sig_atomic_t shutdown_re *** 141,147 **** /* * Private state */ ! static bool am_bg_writer = false; static bool ckpt_active = false; --- 141,147 ---- /* * Private state */ ! /*static*/ bool am_bg_writer = false; /* ONLY FOR DEBUG */ static bool ckpt_active = false; *************** BackgroundWriterMain(void) *** 484,491 **** * * We absorb pending requests after each short sleep. */ ! if ((bgwriter_all_percent > 0.0 && bgwriter_all_maxpages > 0) || ! (bgwriter_lru_percent > 0.0 && bgwriter_lru_maxpages > 0)) udelay = BgWriterDelay * 1000L; else if (XLogArchiveTimeout > 0) udelay = 1000000L; /* One second */ --- 484,490 ---- * * We absorb pending requests after each short sleep. */ ! if (bgwriter_all_percent > 0.0 && bgwriter_all_maxpages > 0) udelay = BgWriterDelay * 1000L; else if (XLogArchiveTimeout > 0) udelay = 1000000L; /* One second */ diff -cpr HEAD/src/backend/storage/buffer/bufmgr.c pgsql-bgwriter/src/backend/storage/buffer/bufmgr.c *** HEAD/src/backend/storage/buffer/bufmgr.c Mon Feb 5 10:35:58 2007 --- pgsql-bgwriter/src/backend/storage/buffer/bufmgr.c Mon Mar 5 12:41:09 2007 *************** *** 62,72 **** /* GUC variables */ bool zero_damaged_pages = false; - double bgwriter_lru_percent = 1.0; double bgwriter_all_percent = 0.333; - int bgwriter_lru_maxpages = 5; int bgwriter_all_maxpages = 5; long NDirectFileRead; /* some I/O's are direct file access. bypass * bufmgr */ --- 62,71 ---- /* GUC variables */ bool zero_damaged_pages = false; double bgwriter_all_percent = 0.333; int bgwriter_all_maxpages = 5; + static int bgwriter_lru_maxpages = 5; /* adjusted automatically */ long NDirectFileRead; /* some I/O's are direct file access. bypass * bufmgr */ *************** BufferSync(void) *** 945,956 **** { int buf_id; int num_to_scan; int absorb_counter; /* * Find out where to start the circular scan. */ ! buf_id = StrategySyncStart(); /* Make sure we can handle the pin inside SyncOneBuffer */ ResourceOwnerEnlargeBuffers(CurrentResourceOwner); --- 944,956 ---- { int buf_id; int num_to_scan; + int num_to_clean; int absorb_counter; /* * Find out where to start the circular scan. */ ! buf_id = StrategySyncStart(&num_to_clean); /* Make sure we can handle the pin inside SyncOneBuffer */ ResourceOwnerEnlargeBuffers(CurrentResourceOwner); *************** BgBufferSync(void) *** 992,997 **** --- 992,998 ---- static int buf_id1 = 0; int buf_id2; int num_to_scan; + int num_to_clean; int num_written; /* Make sure we can handle the pin inside SyncOneBuffer */ *************** BgBufferSync(void) *** 1036,1058 **** * This loop considers only unpinned buffers close to the clock sweep * point. */ ! if (bgwriter_lru_percent > 0.0 && bgwriter_lru_maxpages > 0) ! { ! num_to_scan = (int) ((NBuffers * bgwriter_lru_percent + 99) / 100); ! num_written = 0; ! buf_id2 = StrategySyncStart(); ! while (num_to_scan-- > 0) ! { ! if (SyncOneBuffer(buf_id2, true)) ! { ! if (++num_written >= bgwriter_lru_maxpages) ! break; ! } ! if (++buf_id2 >= NBuffers) ! buf_id2 = 0; ! } } } --- 1037,1061 ---- * This loop considers only unpinned buffers close to the clock sweep * point. */ ! buf_id2 = StrategySyncStart(&num_to_clean); ! if (bgwriter_lru_maxpages < num_to_clean) ! bgwriter_lru_maxpages -= 1; ! else ! bgwriter_lru_maxpages += 1; ! { ! static int counter = 0; ! if ((++counter) % 50 == 0) ! elog(LOG, "bgwriter_lru_maxpages = %d", bgwriter_lru_maxpages); ! } ! num_written = 0; ! while (num_written < bgwriter_lru_maxpages) ! { ! if (SyncOneBuffer(buf_id2, true)) ! ++num_written; ! if (++buf_id2 >= NBuffers) ! buf_id2 = 0; } } *************** BgBufferSync(void) *** 1062,1070 **** * If skip_pinned is true, we don't write currently-pinned buffers, nor * buffers marked recently used, as these are not replacement candidates. * ! * Returns true if buffer was written, else false. (This could be in error ! * if FlushBuffers finds the buffer clean after locking it, but we don't ! * care all that much.) * * Note: caller must have done ResourceOwnerEnlargeBuffers. */ --- 1065,1073 ---- * If skip_pinned is true, we don't write currently-pinned buffers, nor * buffers marked recently used, as these are not replacement candidates. * ! * Returns true if buffer was written or recyclable soon, else false. ! * (This could be in error if FlushBuffers finds the buffer clean after ! * locking it, but we don't care all that much.) * * Note: caller must have done ResourceOwnerEnlargeBuffers. */ *************** SyncOneBuffer(int buf_id, bool skip_pinn *** 1083,1098 **** * upcoming changes and so we are not required to write such dirty buffer. */ LockBufHdr(bufHdr); ! if (!(bufHdr->flags & BM_VALID) || !(bufHdr->flags & BM_DIRTY)) { UnlockBufHdr(bufHdr); return false; } ! if (skip_pinned && ! (bufHdr->refcount != 0 || bufHdr->usage_count != 0)) { UnlockBufHdr(bufHdr); ! return false; } /* --- 1086,1101 ---- * upcoming changes and so we are not required to write such dirty buffer. */ LockBufHdr(bufHdr); ! if (skip_pinned && ! (bufHdr->refcount != 0 || bufHdr->usage_count != 0)) { UnlockBufHdr(bufHdr); return false; } ! if (!(bufHdr->flags & BM_VALID) || !(bufHdr->flags & BM_DIRTY)) { UnlockBufHdr(bufHdr); ! return skip_pinned; /* We can recycle non dirty buffers soon. */ } /* *************** PrintBufferLeakWarning(Buffer buffer) *** 1272,1279 **** --- 1275,1284 ---- void FlushBufferPool(void) { + StrategyShowReports(); /* ONLY FOR DEBUG */ BufferSync(); smgrsync(); + StrategyShowReports(); /* ONLY FOR DEBUG */ } *************** FlushBuffer(volatile BufferDesc *buf, SM *** 1365,1370 **** --- 1370,1377 ---- if (!StartBufferIO(buf, false)) return; + StrategyReportWrite(); /* ONLY FOR DEBUG */ + /* Setup error traceback support for ereport() */ errcontext.callback = buffer_write_error_callback; errcontext.arg = (void *) buf; diff -cpr HEAD/src/backend/storage/buffer/freelist.c pgsql-bgwriter/src/backend/storage/buffer/freelist.c *** HEAD/src/backend/storage/buffer/freelist.c Thu Jan 11 14:20:57 2007 --- pgsql-bgwriter/src/backend/storage/buffer/freelist.c Mon Mar 5 12:36:35 2007 *************** typedef struct *** 27,32 **** --- 27,37 ---- /* Clock sweep hand: index of next buffer to consider grabbing */ int nextVictimBuffer; + int numGetBuffer; /* Buffer request count per cycle */ + + int writtenByBgWriter; /* ONLY FOR DEBUG */ + int writtenByBackends; /* ONLY FOR DEBUG */ + int firstFreeBuffer; /* Head of list of unused buffers */ int lastFreeBuffer; /* Tail of list of unused buffers */ *************** StrategyGetBuffer(void) *** 63,68 **** --- 68,75 ---- LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE); + StrategyControl->numGetBuffer++; + /* * Try to get a buffer from the freelist. Note that the freeNext fields * are considered to be protected by the BufFreelistLock not the *************** StrategyFreeBuffer(volatile BufferDesc * *** 176,191 **** * BufferSync() will proceed circularly around the buffer array from there. */ int ! StrategySyncStart(void) { int result; - /* - * We could probably dispense with the locking here, but just to be safe - * ... - */ LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE); result = StrategyControl->nextVictimBuffer; LWLockRelease(BufFreelistLock); return result; } --- 183,196 ---- * BufferSync() will proceed circularly around the buffer array from there. */ int ! StrategySyncStart(int *num_to_clean) { int result; LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE); result = StrategyControl->nextVictimBuffer; + *num_to_clean = StrategyControl->numGetBuffer * 2; /* safety margin */ + StrategyControl->numGetBuffer = 0; LWLockRelease(BufFreelistLock); return result; } *************** StrategyInitialize(bool init) *** 270,276 **** --- 275,303 ---- /* Initialize the clock sweep pointer */ StrategyControl->nextVictimBuffer = 0; + + StrategyControl->numGetBuffer = 0; + StrategyControl->writtenByBgWriter = 0; + StrategyControl->writtenByBackends = 0; } else Assert(!init); } + + void + StrategyReportWrite(void) + { + extern bool am_bg_writer; + if (am_bg_writer) + StrategyControl->writtenByBgWriter++; + else + StrategyControl->writtenByBackends++; + } + + void + StrategyShowReports(void) + { + elog(LOG, "Write stats : bgwriter/backends = %d/%d", + StrategyControl->writtenByBgWriter, + StrategyControl->writtenByBackends); + } diff -cpr HEAD/src/backend/utils/misc/guc.c pgsql-bgwriter/src/backend/utils/misc/guc.c *** HEAD/src/backend/utils/misc/guc.c Mon Mar 5 09:48:58 2007 --- pgsql-bgwriter/src/backend/utils/misc/guc.c Mon Mar 5 12:39:42 2007 *************** static struct config_int ConfigureNamesI *** 1505,1519 **** }, { - {"bgwriter_lru_maxpages", PGC_SIGHUP, RESOURCES, - gettext_noop("Background writer maximum number of LRU pages to flush per round."), - NULL - }, - &bgwriter_lru_maxpages, - 5, 0, 1000, NULL, NULL - }, - - { {"bgwriter_all_maxpages", PGC_SIGHUP, RESOURCES, gettext_noop("Background writer maximum number of all pages to flush per round."), NULL --- 1505,1510 ---- *************** static struct config_real ConfigureNames *** 1757,1771 **** }, { - {"bgwriter_lru_percent", PGC_SIGHUP, RESOURCES, - gettext_noop("Background writer percentage of LRU buffers to flush per round."), - NULL - }, - &bgwriter_lru_percent, - 1.0, 0.0, 100.0, NULL, NULL - }, - - { {"bgwriter_all_percent", PGC_SIGHUP, RESOURCES, gettext_noop("Background writer percentage of all buffers to flush per round."), NULL --- 1748,1753 ---- diff -cpr HEAD/src/backend/utils/misc/postgresql.conf.sample pgsql-bgwriter/src/backend/utils/misc/postgresql.conf.sample *** HEAD/src/backend/utils/misc/postgresql.conf.sample Mon Mar 5 09:48:58 2007 --- pgsql-bgwriter/src/backend/utils/misc/postgresql.conf.sample Mon Mar 5 12:39:42 2007 *************** *** 138,146 **** # - Background writer - #bgwriter_delay = 200ms # 10-10000ms between rounds ! #bgwriter_lru_percent = 1.0 # 0-100% of LRU buffers scanned/round ! #bgwriter_lru_maxpages = 5 # 0-1000 buffers max written/round ! #bgwriter_all_percent = 0.333 # 0-100% of all buffers scanned/round #bgwriter_all_maxpages = 5 # 0-1000 buffers max written/round --- 138,144 ---- # - Background writer - #bgwriter_delay = 200ms # 10-10000ms between rounds ! #bgwriter_all_percent = 0.333 # 0-100% of buffers scanned/round #bgwriter_all_maxpages = 5 # 0-1000 buffers max written/round diff -cpr HEAD/src/include/storage/buf_internals.h pgsql-bgwriter/src/include/storage/buf_internals.h *** HEAD/src/include/storage/buf_internals.h Thu Jan 11 14:20:57 2007 --- pgsql-bgwriter/src/include/storage/buf_internals.h Mon Mar 5 12:36:35 2007 *************** extern long int LocalBufferFlushCount; *** 186,195 **** /* freelist.c */ extern volatile BufferDesc *StrategyGetBuffer(void); extern void StrategyFreeBuffer(volatile BufferDesc *buf, bool at_head); ! extern int StrategySyncStart(void); extern Size StrategyShmemSize(void); extern void StrategyInitialize(bool init); /* buf_table.c */ extern Size BufTableShmemSize(int size); extern void InitBufTable(int size); --- 186,198 ---- /* freelist.c */ extern volatile BufferDesc *StrategyGetBuffer(void); extern void StrategyFreeBuffer(volatile BufferDesc *buf, bool at_head); ! extern int StrategySyncStart(int *num_to_clean); extern Size StrategyShmemSize(void); extern void StrategyInitialize(bool init); + extern void StrategyReportWrite(void); /* ONLY FOR DEBUG */ + extern void StrategyShowReports(void); /* ONLY FOR DEBUG */ + /* buf_table.c */ extern Size BufTableShmemSize(int size); extern void InitBufTable(int size); diff -cpr HEAD/src/include/storage/bufmgr.h pgsql-bgwriter/src/include/storage/bufmgr.h *** HEAD/src/include/storage/bufmgr.h Thu Jan 11 14:20:57 2007 --- pgsql-bgwriter/src/include/storage/bufmgr.h Mon Mar 5 12:39:42 2007 *************** extern DLLIMPORT int NBuffers; *** 24,32 **** /* in bufmgr.c */ extern bool zero_damaged_pages; - extern double bgwriter_lru_percent; extern double bgwriter_all_percent; - extern int bgwriter_lru_maxpages; extern int bgwriter_all_maxpages; /* in buf_init.c */ --- 24,30 ----