diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index aa90503..3a307b1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -85,6 +85,7 @@ extern uint32 bootstrap_data_checksum_version; int max_wal_size = 64; /* 1 GB */ int min_wal_size = 5; /* 80 MB */ int wal_keep_segments = 0; +int wal_write_chunk_size = 4096; /* 4K */ int XLOGbuffers = -1; int XLogArchiveTimeout = 0; int XLogArchiveMode = ARCHIVE_MODE_OFF; @@ -2154,10 +2155,13 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) bool last_iteration; bool finishing_seg; bool use_existent; + bool first_write; int curridx; int npages; int startidx; uint32 startoffset; + uint32 startidx_offset; + XLogRecPtr startXLogPtr; /* We should always be inside a critical section here */ Assert(CritSectionCount > 0); @@ -2174,11 +2178,20 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) * written together; startidx is the cache block index of the first one, * and startoffset is the file offset at which it should go. The latter * two variables are only valid when npages > 0, but we must initialize - * all of them to keep the compiler quiet. + * all of them to keep the compiler quiet. startidx_offset is the offset + * of the cached block which indicates from where to start writing and + * startXLogPtr is used to calculate the startoffset for the first write. + * startidx_offset and startXLogPtr helps to calculate the starting position + * of write, we need to start writing from the wal_write_chunk_size boundary + * or from beginning of page. Writing in wal_write_chunk_size sized chunks + * helps in reducing the re-write of data. */ npages = 0; startidx = 0; startoffset = 0; + startidx_offset = 0; + startXLogPtr = LogwrtResult.Write; + first_write = true; /* * Within the loop, curridx is the cache block index of the page to @@ -2236,7 +2249,26 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) { /* first of group */ startidx = curridx; - startoffset = (LogwrtResult.Write - XLOG_BLCKSZ) % XLogSegSize; + startidx_offset = 0; + + /* + * for first page, we need to start writing from wal_write_chunk_size + * boundary or beginning of page. + */ + if (first_write) + { + uint32 start_chunk_pos = 0; + + /* position the start at wal_write_chunk_size boundary. */ + start_chunk_pos = floor((double) (startXLogPtr % XLOG_BLCKSZ) / wal_write_chunk_size); + startidx_offset = start_chunk_pos * wal_write_chunk_size; + + startoffset = (LogwrtResult.Write - XLOG_BLCKSZ + startidx_offset) % XLogSegSize; + } + else + startoffset = (LogwrtResult.Write - XLOG_BLCKSZ) % XLogSegSize; + + first_write = false; } npages++; @@ -2273,8 +2305,45 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) } /* OK to write the page(s) */ - from = XLogCtl->pages + startidx * (Size) XLOG_BLCKSZ; - nbytes = npages * (Size) XLOG_BLCKSZ; + from = XLogCtl->pages + startidx * (Size) XLOG_BLCKSZ + startidx_offset; + + /* + * Write in wal_write_chunk_size sized chunks. In case, previous + * write finishes at page boundary less than wal_write_chunk_size + * and current write (WriteRqst.Write) falls in next chunk of page, + * then we need to write the data in both the chunks. + */ + if (last_iteration) + { + uint32 chunk_pos = 0; + uint32 chunk_size = 0; + + if (npages > 1) + { + nbytes = (npages - 1) * (Size) XLOG_BLCKSZ - startidx_offset; + + if (((uint32) WriteRqst.Write) % XLOG_BLCKSZ == 0) + chunk_pos = ceil((double) XLOG_BLCKSZ / wal_write_chunk_size); + else + chunk_pos = ceil((double) (((uint32) WriteRqst.Write) % XLOG_BLCKSZ) / wal_write_chunk_size); + + chunk_size = chunk_pos * wal_write_chunk_size; + nbytes += chunk_size; + } + else + { + if (((uint32) WriteRqst.Write) % XLOG_BLCKSZ == 0) + chunk_pos = ceil((double) XLOG_BLCKSZ / wal_write_chunk_size); + else + chunk_pos = ceil((double) (((uint32) WriteRqst.Write) % XLOG_BLCKSZ) / wal_write_chunk_size); + + chunk_size = chunk_pos * wal_write_chunk_size; + nbytes = chunk_size - startidx_offset; + } + } + else + nbytes = npages * (Size) XLOG_BLCKSZ - startidx_offset; + nleft = nbytes; do { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 38ba82f..876c934 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2220,6 +2220,16 @@ static struct config_int ConfigureNamesInt[] = }, { + {"wal_write_chunk_size", PGC_POSTMASTER, WAL_SETTINGS, + gettext_noop("Sets the chunk size used for wal writing."), + NULL + }, + &wal_write_chunk_size, + 4096, 512, XLOG_BLCKSZ, + NULL, NULL, NULL + }, + + { {"wal_writer_delay", PGC_SIGHUP, WAL_SETTINGS, gettext_noop("WAL writer sleep time between WAL flushes."), NULL, diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 029114f..62423a7 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -192,6 +192,7 @@ #wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers # (change requires restart) #wal_writer_delay = 200ms # 1-10000 milliseconds +#wal_write_chunk_size = 4096 # chunk size used for wal writing #commit_delay = 0 # range 0-100000, in microseconds #commit_siblings = 5 # range 1-1000 diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 3de337a..93c2ac8 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -95,6 +95,7 @@ extern bool reachedConsistency; extern int min_wal_size; extern int max_wal_size; extern int wal_keep_segments; +extern int wal_write_chunk_size; extern int XLOGbuffers; extern int XLogArchiveTimeout; extern int wal_retrieve_retry_interval;