aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/slru.c
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2014-01-02 18:16:54 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2014-01-02 18:16:54 -0300
commit722acf51a0d074d19782ad7e97ebe3fdb63fbb87 (patch)
tree2b0aba3e2dd322afc46175eb281142d760a44abb /src/backend/access/transam/slru.c
parent3cff1879f8d03cb729368722ca823a4bf74c0cac (diff)
downloadpostgresql-722acf51a0d074d19782ad7e97ebe3fdb63fbb87.tar.gz
postgresql-722acf51a0d074d19782ad7e97ebe3fdb63fbb87.zip
Handle wraparound during truncation in multixact/members
In pg_multixact/members, relying on modulo-2^32 arithmetic for wraparound handling doesn't work all that well. Because we don't explicitely track wraparound of the allocation counter for members, it is possible that the "live" area exceeds 2^31 entries; trying to remove SLRU segments that are "old" according to the original logic might lead to removal of segments still in use. To fix, have the truncation routine use a tailored SlruScanDirectory callback that keeps track of the live area in actual use; that way, when the live range exceeds 2^31 entries, the oldest segments still live will not get removed untimely. This new SlruScanDir callback needs to take care not to remove segments that are "in the future": if new SLRU segments appear while the truncation is ongoing, make sure we don't remove them. This requires examination of shared memory state to recheck for false positives, but testing suggests that this doesn't cause a problem. The original coding didn't suffer from this pitfall because segments created when truncation is running are never considered to be removable. Per Andres Freund's investigation of bug #8673 reported by Serge Negodyuck.
Diffstat (limited to 'src/backend/access/transam/slru.c')
-rw-r--r--src/backend/access/transam/slru.c31
1 files changed, 18 insertions, 13 deletions
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 5e53593a8f2..9dc566e1622 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -1210,6 +1210,17 @@ restart:;
(void) SlruScanDirectory(ctl, SlruScanDirCbDeleteCutoff, &cutoffPage);
}
+void
+SlruDeleteSegment(SlruCtl ctl, char *filename)
+{
+ char path[MAXPGPATH];
+
+ snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, filename);
+ ereport(DEBUG2,
+ (errmsg("removing file \"%s\"", path)));
+ unlink(path);
+}
+
/*
* SlruScanDirectory callback
* This callback reports true if there's any segment prior to the one
@@ -1235,16 +1246,10 @@ SlruScanDirCbReportPresence(SlruCtl ctl, char *filename, int segpage, void *data
static bool
SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int segpage, void *data)
{
- char path[MAXPGPATH];
int cutoffPage = *(int *) data;
if (ctl->PagePrecedes(segpage, cutoffPage))
- {
- snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, filename);
- ereport(DEBUG2,
- (errmsg("removing file \"%s\"", path)));
- unlink(path);
- }
+ SlruDeleteSegment(ctl, filename);
return false; /* keep going */
}
@@ -1256,12 +1261,7 @@ SlruScanDirCbDeleteCutoff(SlruCtl ctl, char *filename, int segpage, void *data)
bool
SlruScanDirCbDeleteAll(SlruCtl ctl, char *filename, int segpage, void *data)
{
- char path[MAXPGPATH];
-
- snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, filename);
- ereport(DEBUG2,
- (errmsg("removing file \"%s\"", path)));
- unlink(path);
+ SlruDeleteSegment(ctl, filename);
return false; /* keep going */
}
@@ -1272,6 +1272,11 @@ SlruScanDirCbDeleteAll(SlruCtl ctl, char *filename, int segpage, void *data)
* If the callback returns true, the scan is stopped. The last return value
* from the callback is returned.
*
+ * The callback receives the following arguments: 1. the SlruCtl struct for the
+ * slru being truncated; 2. the filename being considered; 3. the page number
+ * for the first page of that file; 4. a pointer to the opaque data given to us
+ * by the caller.
+ *
* Note that the ordering in which the directory is scanned is not guaranteed.
*
* Note that no locking is applied.