Skip to content

Commit 3c28f65

Browse files
committed
Release cache pin memory
Cache pins are allocated on the CacheMemoryContext in order to survive subtransactions, and, optionally, main transactions (in case of, e.g., clustering or vaccuming). However, cache pins that are released also needs to free memory on the CacheMemoryContext in order to avoid leaking memory in a session. This change ensures cache pin memory is freed when a cache pin is released. It also allocates cache pins on a separate memory context, which is a child of the CacheMemoryContext. This separate memory context makes it easier to track the memory used by cache pins and also release it when necessary.
1 parent abe76fc commit 3c28f65

File tree

1 file changed

+33
-4
lines changed

1 file changed

+33
-4
lines changed

src/cache.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,28 @@
66
/* List of pinned caches. A cache occurs once in this list for every pin
77
* taken */
88
static List *pinned_caches = NIL;
9+
static MemoryContext pinned_caches_mctx = NULL;
910

1011
typedef struct CachePin
1112
{
1213
Cache *cache;
1314
SubTransactionId subtxnid;
1415
} CachePin;
1516

17+
18+
static void
19+
cache_reset_pinned_caches(void)
20+
{
21+
if (NULL != pinned_caches_mctx)
22+
MemoryContextDelete(pinned_caches_mctx);
23+
24+
pinned_caches_mctx = AllocSetContextCreate(CacheMemoryContext,
25+
"Cache pins",
26+
ALLOCSET_DEFAULT_SIZES);
27+
28+
pinned_caches = NIL;
29+
}
30+
1631
void
1732
cache_init(Cache *cache)
1833
{
@@ -72,7 +87,7 @@ cache_invalidate(Cache *cache)
7287
extern Cache *
7388
cache_pin(Cache *cache)
7489
{
75-
MemoryContext old = MemoryContextSwitchTo(CacheMemoryContext);
90+
MemoryContext old = MemoryContextSwitchTo(pinned_caches_mctx);
7691
CachePin *cp = palloc(sizeof(CachePin));
7792

7893
cp->cache = cache;
@@ -96,6 +111,7 @@ remove_pin(Cache *cache, SubTransactionId subtxnid)
96111
if (cp->cache == cache && cp->subtxnid == subtxnid)
97112
{
98113
pinned_caches = list_delete_cell(pinned_caches, lc, prev);
114+
pfree(cp);
99115
return;
100116
}
101117

@@ -200,8 +216,8 @@ release_all_pinned_caches()
200216
cp->cache->refcount--;
201217
cache_destroy(cp->cache);
202218
}
203-
list_free(pinned_caches);
204-
pinned_caches = NIL;
219+
220+
cache_reset_pinned_caches();
205221
}
206222

207223
static void
@@ -227,6 +243,8 @@ release_subtxn_pinned_caches(SubTransactionId subtxnid, bool abort)
227243
cache_release_subtxn(cp->cache, subtxnid);
228244
}
229245
}
246+
247+
list_free(pinned_caches_copy);
230248
}
231249

232250
/*
@@ -251,12 +269,17 @@ cache_xact_end(XactEvent event, void *arg)
251269
break;
252270
default:
253271
{
272+
/*
273+
* Make a copy of the list of pinned caches since
274+
* cache_release() can manipulate the original list.
275+
*/
276+
List *pinned_caches_copy = list_copy(pinned_caches);
254277
ListCell *lc;
255278

256279
/*
257280
* Only caches left should be marked as non-released
258281
*/
259-
foreach(lc, pinned_caches)
282+
foreach(lc, pinned_caches_copy)
260283
{
261284
CachePin *cp = lfirst(lc);
262285

@@ -273,6 +296,8 @@ cache_xact_end(XactEvent event, void *arg)
273296
if (cp->cache->release_on_commit)
274297
cache_release(cp->cache);
275298
}
299+
300+
list_free(pinned_caches_copy);
276301
}
277302
break;
278303
}
@@ -311,13 +336,17 @@ cache_subxact_abort(SubXactEvent event, SubTransactionId subtxn_id,
311336
void
312337
_cache_init(void)
313338
{
339+
cache_reset_pinned_caches();
314340
RegisterXactCallback(cache_xact_end, NULL);
315341
RegisterSubXactCallback(cache_subxact_abort, NULL);
316342
}
317343

318344
void
319345
_cache_fini(void)
320346
{
347+
MemoryContextDelete(pinned_caches_mctx);
348+
pinned_caches_mctx = NULL;
349+
pinned_caches = NIL;
321350
UnregisterXactCallback(cache_xact_end, NULL);
322351
UnregisterSubXactCallback(cache_subxact_abort, NULL);
323352
}

0 commit comments

Comments
 (0)