summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHeikki Linnakangas2015-02-04 15:40:25 +0000
committerHeikki Linnakangas2015-02-04 15:40:25 +0000
commitd88976cfa1302e8dccdcbfe55e9e29faee8c0cdf (patch)
treec1fb1f00b9c7d350b723d1eafabaf764dc8d30f3 /src
parent57fe246890ad51e166fb6a8da937e41c35d7a279 (diff)
Use a separate memory context for GIN scan keys.
It was getting tedious to track and release all the different things that form a scan key. We were leaking at least the queryCategories array, and possibly more, on a rescan. That was visible if a GIN index was used in a nested loop join. This also protects from leaks in extractQuery method. No backpatching, given the lack of complaints from the field. Maybe later, after this has received more field testing.
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/gin/ginget.c5
-rw-r--r--src/backend/access/gin/ginscan.c43
-rw-r--r--src/include/access/gin_private.h2
3 files changed, 29 insertions, 21 deletions
diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c
index 9d73142ee93..3e2b8b5fedf 100644
--- a/src/backend/access/gin/ginget.c
+++ b/src/backend/access/gin/ginget.c
@@ -497,7 +497,7 @@ startScanKey(GinState *ginstate, GinScanOpaque so, GinScanKey key)
}
/* i is now the last required entry. */
- MemoryContextSwitchTo(oldCtx);
+ MemoryContextSwitchTo(so->keyCtx);
key->nrequired = i + 1;
key->nadditional = key->nentries - key->nrequired;
@@ -515,11 +515,14 @@ startScanKey(GinState *ginstate, GinScanOpaque so, GinScanKey key)
}
else
{
+ MemoryContextSwitchTo(so->keyCtx);
+
key->nrequired = 1;
key->nadditional = 0;
key->requiredEntries = palloc(1 * sizeof(GinScanEntry));
key->requiredEntries[0] = key->scanEntry[0];
}
+ MemoryContextSwitchTo(oldCtx);
}
static void
diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c
index b3a2de1edd4..ac3a92b1981 100644
--- a/src/backend/access/gin/ginscan.c
+++ b/src/backend/access/gin/ginscan.c
@@ -44,6 +44,11 @@ ginbeginscan(PG_FUNCTION_ARGS)
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
+ so->keyCtx = AllocSetContextCreate(CurrentMemoryContext,
+ "Gin scan key context",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
initGinState(&so->ginstate, scan->indexRelation);
scan->opaque = so;
@@ -227,6 +232,9 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
}
}
+/*
+ * Release current scan keys, if any.
+ */
void
ginFreeScanKeys(GinScanOpaque so)
{
@@ -235,38 +243,22 @@ ginFreeScanKeys(GinScanOpaque so)
if (so->keys == NULL)
return;
- for (i = 0; i < so->nkeys; i++)
- {
- GinScanKey key = so->keys + i;
-
- pfree(key->scanEntry);
- pfree(key->entryRes);
- if (key->requiredEntries)
- pfree(key->requiredEntries);
- if (key->additionalEntries)
- pfree(key->additionalEntries);
- }
-
- pfree(so->keys);
- so->keys = NULL;
- so->nkeys = 0;
-
for (i = 0; i < so->totalentries; i++)
{
GinScanEntry entry = so->entries[i];
if (entry->buffer != InvalidBuffer)
ReleaseBuffer(entry->buffer);
- if (entry->list)
- pfree(entry->list);
if (entry->matchIterator)
tbm_end_iterate(entry->matchIterator);
if (entry->matchBitmap)
tbm_free(entry->matchBitmap);
- pfree(entry);
}
- pfree(so->entries);
+ MemoryContextResetAndDeleteChildren(so->keyCtx);
+
+ so->keys = NULL;
+ so->nkeys = 0;
so->entries = NULL;
so->totalentries = 0;
}
@@ -278,6 +270,14 @@ ginNewScanKey(IndexScanDesc scan)
GinScanOpaque so = (GinScanOpaque) scan->opaque;
int i;
bool hasNullQuery = false;
+ MemoryContext oldCtx;
+
+ /*
+ * Allocate all the scan key information in the key context. (If
+ * extractQuery leaks anything there, it won't be reset until the end of
+ * scan or rescan, but that's OK.)
+ */
+ oldCtx = MemoryContextSwitchTo(so->keyCtx);
/* if no scan keys provided, allocate extra EVERYTHING GinScanKey */
so->keys = (GinScanKey)
@@ -412,6 +412,8 @@ ginNewScanKey(IndexScanDesc scan)
RelationGetRelationName(scan->indexRelation))));
}
+ MemoryContextSwitchTo(oldCtx);
+
pgstat_count_index_scan(scan->indexRelation);
}
@@ -445,6 +447,7 @@ ginendscan(PG_FUNCTION_ARGS)
ginFreeScanKeys(so);
MemoryContextDelete(so->tempCtx);
+ MemoryContextDelete(so->keyCtx);
pfree(so);
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
index c949c97edec..bda7c284b13 100644
--- a/src/include/access/gin_private.h
+++ b/src/include/access/gin_private.h
@@ -888,6 +888,8 @@ typedef struct GinScanOpaqueData
uint32 totalentries;
uint32 allocentries; /* allocated length of entries[] */
+ MemoryContext keyCtx; /* used to hold key and entry data */
+
bool isVoidRes; /* true if query is unsatisfiable */
} GinScanOpaqueData;