mcxt.c 17.3 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * mcxt.c
4 5 6 7 8 9 10
 *	  POSTGRES memory context management code.
 *
 * This module handles context management operations that are independent
 * of the particular kind of context being operated on.  It calls
 * context-type-specific operations via the function pointers in a
 * context's MemoryContextMethods struct.
 *
11
 *
B
Bruce Momjian 已提交
12
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
13
 * Portions Copyright (c) 1994, Regents of the University of California
14 15 16
 *
 *
 * IDENTIFICATION
17
 *	  $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.40 2003/05/02 20:54:35 tgl Exp $
18 19 20 21 22 23 24
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "nodes/memnodes.h"
25
#include "utils/memutils.h"
26 27 28


/*****************************************************************************
29
 *	  GLOBAL MEMORY															 *
30 31 32
 *****************************************************************************/

/*
B
Bruce Momjian 已提交
33
 * CurrentMemoryContext
34
 *		Default memory context for allocations.
35
 */
36
MemoryContext CurrentMemoryContext = NULL;
37 38

/*
39 40
 * Standard top-level contexts. For a description of the purpose of each
 * of these contexts, refer to src/backend/utils/mmgr/README
41
 */
42 43 44 45
MemoryContext TopMemoryContext = NULL;
MemoryContext ErrorContext = NULL;
MemoryContext PostmasterContext = NULL;
MemoryContext CacheMemoryContext = NULL;
46
MemoryContext MessageContext = NULL;
47
MemoryContext TopTransactionContext = NULL;
48 49 50
/* These two are transient links to contexts owned by other objects: */
MemoryContext QueryContext = NULL;
MemoryContext PortalContext = NULL;
51 52


53 54 55
/*****************************************************************************
 *	  EXPORTED ROUTINES														 *
 *****************************************************************************/
56 57 58


/*
59 60
 * MemoryContextInit
 *		Start up the memory-context subsystem.
61
 *
62 63 64
 * This must be called before creating contexts or allocating memory in
 * contexts.  TopMemoryContext and ErrorContext are initialized here;
 * other contexts must be created afterwards.
65
 *
66 67 68 69
 * In normal multi-backend operation, this is called once during
 * postmaster startup, and not at all by individual backend startup
 * (since the backends inherit an already-initialized context subsystem
 * by virtue of being forked off the postmaster).
70
 *
71
 * In a standalone backend this must be called during backend startup.
72 73
 */
void
74
MemoryContextInit(void)
75
{
76
	AssertState(TopMemoryContext == NULL);
B
Bruce Momjian 已提交
77

78
	/*
B
Bruce Momjian 已提交
79 80
	 * Initialize TopMemoryContext as an AllocSetContext with slow growth
	 * rate --- we don't really expect much to be allocated in it.
81 82 83 84 85
	 *
	 * (There is special-case code in MemoryContextCreate() for this call.)
	 */
	TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
											 "TopMemoryContext",
86
											 0,
87 88
											 8 * 1024,
											 8 * 1024);
B
Bruce Momjian 已提交
89

90
	/*
B
Bruce Momjian 已提交
91 92
	 * Not having any other place to point CurrentMemoryContext, make it
	 * point to TopMemoryContext.  Caller should change this soon!
93 94
	 */
	CurrentMemoryContext = TopMemoryContext;
B
Bruce Momjian 已提交
95

96
	/*
B
Bruce Momjian 已提交
97 98 99 100 101 102
	 * Initialize ErrorContext as an AllocSetContext with slow growth rate
	 * --- we don't really expect much to be allocated in it. More to the
	 * point, require it to contain at least 8K at all times. This is the
	 * only case where retained memory in a context is *essential* --- we
	 * want to be sure ErrorContext still has some memory even if we've
	 * run out elsewhere!
103 104 105 106 107 108
	 */
	ErrorContext = AllocSetContextCreate(TopMemoryContext,
										 "ErrorContext",
										 8 * 1024,
										 8 * 1024,
										 8 * 1024);
109 110 111
}

/*
112 113 114
 * MemoryContextReset
 *		Release all space allocated within a context and its descendants,
 *		but don't delete the contexts themselves.
115
 *
116 117
 * The type-specific reset routine handles the context itself, but we
 * have to do the recursion for the children.
118
 */
119 120
void
MemoryContextReset(MemoryContext context)
121
{
T
Tom Lane 已提交
122 123
	AssertArg(MemoryContextIsValid(context));

124 125
	MemoryContextResetChildren(context);
	(*context->methods->reset) (context);
126 127 128
}

/*
129 130 131 132
 * MemoryContextResetChildren
 *		Release all space allocated within a context's descendants,
 *		but don't delete the contexts themselves.  The named context
 *		itself is not touched.
133 134
 */
void
135
MemoryContextResetChildren(MemoryContext context)
136
{
B
Bruce Momjian 已提交
137
	MemoryContext child;
138

T
Tom Lane 已提交
139 140
	AssertArg(MemoryContextIsValid(context));

141 142
	for (child = context->firstchild; child != NULL; child = child->nextchild)
		MemoryContextReset(child);
143 144 145
}

/*
146 147 148
 * MemoryContextDelete
 *		Delete a context and its descendants, and release all space
 *		allocated therein.
149
 *
150 151
 * The type-specific delete routine removes all subsidiary storage
 * for the context, but we have to delete the context node itself,
B
Bruce Momjian 已提交
152
 * as well as recurse to get the children.	We must also delink the
153
 * node from its parent, if it has one.
154
 */
155 156
void
MemoryContextDelete(MemoryContext context)
157
{
T
Tom Lane 已提交
158
	AssertArg(MemoryContextIsValid(context));
159 160 161 162 163 164
	/* We had better not be deleting TopMemoryContext ... */
	Assert(context != TopMemoryContext);
	/* And not CurrentMemoryContext, either */
	Assert(context != CurrentMemoryContext);

	MemoryContextDeleteChildren(context);
B
Bruce Momjian 已提交
165

166
	/*
B
Bruce Momjian 已提交
167 168 169
	 * We delink the context from its parent before deleting it, so that
	 * if there's an error we won't have deleted/busted contexts still
	 * attached to the context tree.  Better a leak than a crash.
170 171 172
	 */
	if (context->parent)
	{
B
Bruce Momjian 已提交
173
		MemoryContext parent = context->parent;
174

175 176 177 178
		if (context == parent->firstchild)
			parent->firstchild = context->nextchild;
		else
		{
B
Bruce Momjian 已提交
179
			MemoryContext child;
180

181 182 183 184 185 186 187 188 189 190 191 192
			for (child = parent->firstchild; child; child = child->nextchild)
			{
				if (context == child->nextchild)
				{
					child->nextchild = context->nextchild;
					break;
				}
			}
		}
	}
	(*context->methods->delete) (context);
	pfree(context);
193 194 195
}

/*
196 197 198
 * MemoryContextDeleteChildren
 *		Delete all the descendants of the named context and release all
 *		space allocated therein.  The named context itself is not touched.
199
 */
200 201
void
MemoryContextDeleteChildren(MemoryContext context)
202
{
T
Tom Lane 已提交
203
	AssertArg(MemoryContextIsValid(context));
B
Bruce Momjian 已提交
204

205
	/*
B
Bruce Momjian 已提交
206 207
	 * MemoryContextDelete will delink the child from me, so just iterate
	 * as long as there is a child.
208 209 210
	 */
	while (context->firstchild != NULL)
		MemoryContextDelete(context->firstchild);
211
}
212

213
/*
214 215 216
 * MemoryContextResetAndDeleteChildren
 *		Release all space allocated within a context and delete all
 *		its descendants.
217
 *
218 219
 * This is a common combination case where we want to preserve the
 * specific context but get rid of absolutely everything under it.
220
 */
221 222
void
MemoryContextResetAndDeleteChildren(MemoryContext context)
223
{
T
Tom Lane 已提交
224 225
	AssertArg(MemoryContextIsValid(context));

226 227
	MemoryContextDeleteChildren(context);
	(*context->methods->reset) (context);
228
}
229

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
/*
 * GetMemoryChunkSpace
 *		Given a currently-allocated chunk, determine the total space
 *		it occupies (including all memory-allocation overhead).
 *
 * This is useful for measuring the total space occupied by a set of
 * allocated chunks.
 */
Size
GetMemoryChunkSpace(void *pointer)
{
	StandardChunkHeader *header;

	/*
	 * Try to detect bogus pointers handed to us, poorly though we can.
	 * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
	 * allocated chunk.
	 */
	Assert(pointer != NULL);
	Assert(pointer == (void *) MAXALIGN(pointer));

	/*
	 * OK, it's probably safe to look at the chunk header.
	 */
	header = (StandardChunkHeader *)
		((char *) pointer - STANDARDCHUNKHEADERSIZE);

	AssertArg(MemoryContextIsValid(header->context));

	return (*header->context->methods->get_chunk_space) (header->context,
														 pointer);
}

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
/*
 * GetMemoryChunkContext
 *		Given a currently-allocated chunk, determine the context
 *		it belongs to.
 */
MemoryContext
GetMemoryChunkContext(void *pointer)
{
	StandardChunkHeader *header;

	/*
	 * Try to detect bogus pointers handed to us, poorly though we can.
	 * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
	 * allocated chunk.
	 */
	Assert(pointer != NULL);
	Assert(pointer == (void *) MAXALIGN(pointer));

	/*
	 * OK, it's probably safe to look at the chunk header.
	 */
	header = (StandardChunkHeader *)
		((char *) pointer - STANDARDCHUNKHEADERSIZE);

	AssertArg(MemoryContextIsValid(header->context));

	return header->context;
}

292
/*
293 294
 * MemoryContextStats
 *		Print statistics about the named context and all its descendants.
295
 *
296 297
 * This is just a debugging utility, so it's not fancy.  The statistics
 * are merely sent to stderr.
298
 */
299 300
void
MemoryContextStats(MemoryContext context)
301
{
B
Bruce Momjian 已提交
302
	MemoryContext child;
303

T
Tom Lane 已提交
304 305
	AssertArg(MemoryContextIsValid(context));

306 307 308
	(*context->methods->stats) (context);
	for (child = context->firstchild; child != NULL; child = child->nextchild)
		MemoryContextStats(child);
309 310
}

311 312 313 314 315

/*
 * MemoryContextCheck
 *		Check all chunks in the named context.
 *
B
Bruce Momjian 已提交
316
 * This is just a debugging utility, so it's not fancy.
317 318 319 320 321
 */
#ifdef MEMORY_CONTEXT_CHECKING
void
MemoryContextCheck(MemoryContext context)
{
B
Bruce Momjian 已提交
322
	MemoryContext child;
323

T
Tom Lane 已提交
324 325
	AssertArg(MemoryContextIsValid(context));

326 327 328 329 330 331
	(*context->methods->check) (context);
	for (child = context->firstchild; child != NULL; child = child->nextchild)
		MemoryContextCheck(child);
}
#endif

332
/*
333 334 335
 * MemoryContextContains
 *		Detect whether an allocated chunk of memory belongs to a given
 *		context or not.
336
 *
337 338 339 340 341
 * Caution: this test is reliable as long as 'pointer' does point to
 * a chunk of memory allocated from *some* context.  If 'pointer' points
 * at memory obtained in some other way, there is a small chance of a
 * false-positive result, since the bits right before it might look like
 * a valid chunk header by chance.
342
 */
343 344
bool
MemoryContextContains(MemoryContext context, void *pointer)
345
{
B
Bruce Momjian 已提交
346
	StandardChunkHeader *header;
347 348 349

	/*
	 * Try to detect bogus pointers handed to us, poorly though we can.
B
Bruce Momjian 已提交
350 351
	 * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
	 * allocated chunk.
352 353 354
	 */
	if (pointer == NULL || pointer != (void *) MAXALIGN(pointer))
		return false;
B
Bruce Momjian 已提交
355

356 357 358 359 360
	/*
	 * OK, it's probably safe to look at the chunk header.
	 */
	header = (StandardChunkHeader *)
		((char *) pointer - STANDARDCHUNKHEADERSIZE);
B
Bruce Momjian 已提交
361

362 363
	/*
	 * If the context link doesn't match then we certainly have a
B
Bruce Momjian 已提交
364 365
	 * non-member chunk.  Also check for a reasonable-looking size as
	 * extra guard against being fooled by bogus pointers.
366 367 368 369
	 */
	if (header->context == context && AllocSizeIsValid(header->size))
		return true;
	return false;
370 371
}

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
/*--------------------
 * MemoryContextCreate
 *		Context-type-independent part of context creation.
 *
 * This is only intended to be called by context-type-specific
 * context creation routines, not by the unwashed masses.
 *
 * The context creation procedure is a little bit tricky because
 * we want to be sure that we don't leave the context tree invalid
 * in case of failure (such as insufficient memory to allocate the
 * context node itself).  The procedure goes like this:
 *	1.	Context-type-specific routine first calls MemoryContextCreate(),
 *		passing the appropriate tag/size/methods values (the methods
 *		pointer will ordinarily point to statically allocated data).
 *		The parent and name parameters usually come from the caller.
 *	2.	MemoryContextCreate() attempts to allocate the context node,
 *		plus space for the name.  If this fails we can elog() with no
 *		damage done.
 *	3.	We fill in all of the type-independent MemoryContext fields.
 *	4.	We call the type-specific init routine (using the methods pointer).
 *		The init routine is required to make the node minimally valid
 *		with zero chance of failure --- it can't allocate more memory,
 *		for example.
 *	5.	Now we have a minimally valid node that can behave correctly
 *		when told to reset or delete itself.  We link the node to its
 *		parent (if any), making the node part of the context tree.
 *	6.	We return to the context-type-specific routine, which finishes
 *		up type-specific initialization.  This routine can now do things
 *		that might fail (like allocate more memory), so long as it's
 *		sure the node is left in a state that delete will handle.
 *
 * This protocol doesn't prevent us from leaking memory if step 6 fails
 * during creation of a top-level context, since there's no parent link
 * in that case.  However, if you run out of memory while you're building
 * a top-level context, you might as well go home anyway...
407
 *
408 409
 * Normally, the context node and the name are allocated from
 * TopMemoryContext (NOT from the parent context, since the node must
B
Bruce Momjian 已提交
410
 * survive resets of its parent context!).	However, this routine is itself
411 412 413 414 415 416 417 418
 * used to create TopMemoryContext!  If we see that TopMemoryContext is NULL,
 * we assume we are creating TopMemoryContext and use malloc() to allocate
 * the node.
 *
 * Note that the name field of a MemoryContext does not point to
 * separately-allocated storage, so it should not be freed at context
 * deletion.
 *--------------------
419
 */
420 421 422 423 424
MemoryContext
MemoryContextCreate(NodeTag tag, Size size,
					MemoryContextMethods *methods,
					MemoryContext parent,
					const char *name)
425
{
B
Bruce Momjian 已提交
426 427
	MemoryContext node;
	Size		needed = size + strlen(name) + 1;
428

429 430 431 432 433 434 435 436 437 438 439 440 441
	/* Get space for node and name */
	if (TopMemoryContext != NULL)
	{
		/* Normal case: allocate the node in TopMemoryContext */
		node = (MemoryContext) MemoryContextAlloc(TopMemoryContext,
												  needed);
	}
	else
	{
		/* Special case for startup: use good ol' malloc */
		node = (MemoryContext) malloc(needed);
		Assert(node != NULL);
	}
442

443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
	/* Initialize the node as best we can */
	MemSet(node, 0, size);
	node->type = tag;
	node->methods = methods;
	node->parent = NULL;		/* for the moment */
	node->firstchild = NULL;
	node->nextchild = NULL;
	node->name = ((char *) node) + size;
	strcpy(node->name, name);

	/* Type-specific routine finishes any other essential initialization */
	(*node->methods->init) (node);

	/* OK to link node to parent (if any) */
	if (parent)
	{
		node->parent = parent;
		node->nextchild = parent->firstchild;
		parent->firstchild = node;
	}
463

464 465
	/* Return to type-specific creation routine to finish up */
	return node;
466 467 468
}

/*
469 470
 * MemoryContextAlloc
 *		Allocate space within the specified context.
471
 *
472 473
 * This could be turned into a macro, but we'd have to import
 * nodes/memnodes.h into postgres.h which seems a bad idea.
474
 */
475 476
void *
MemoryContextAlloc(MemoryContext context, Size size)
477
{
478
	AssertArg(MemoryContextIsValid(context));
479

480 481 482
	if (!AllocSizeIsValid(size))
		elog(ERROR, "MemoryContextAlloc: invalid request size %lu",
			 (unsigned long) size);
483 484

	return (*context->methods->alloc) (context, size);
485 486
}

487
/*
488
 * MemoryContextAllocZero
489 490 491
 *		Like MemoryContextAlloc, but clears allocated memory
 *
 *	We could just call MemoryContextAlloc then clear the memory, but this
492
 *	is a very common combination, so we provide the combined operation.
493 494
 */
void *
495
MemoryContextAllocZero(MemoryContext context, Size size)
496 497 498 499 500 501
{
	void *ret;

	AssertArg(MemoryContextIsValid(context));

	if (!AllocSizeIsValid(size))
502
		elog(ERROR, "MemoryContextAlloc: invalid request size %lu",
503 504 505
			 (unsigned long) size);

	ret = (*context->methods->alloc) (context, size);
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531

	MemSetAligned(ret, 0, size);

	return ret;
}

/*
 * MemoryContextAllocZeroAligned
 *		MemoryContextAllocZero where length is suitable for MemSetLoop
 *
 *	This might seem overly specialized, but it's not because newNode()
 *	is so often called with compile-time-constant sizes.
 */
void *
MemoryContextAllocZeroAligned(MemoryContext context, Size size)
{
	void *ret;

	AssertArg(MemoryContextIsValid(context));

	if (!AllocSizeIsValid(size))
		elog(ERROR, "MemoryContextAlloc: invalid request size %lu",
			 (unsigned long) size);

	ret = (*context->methods->alloc) (context, size);

532
	MemSetLoop(ret, 0, size);
533

534 535 536
	return ret;
}

537
/*
538 539
 * pfree
 *		Release an allocated chunk.
540
 */
541 542
void
pfree(void *pointer)
543
{
B
Bruce Momjian 已提交
544
	StandardChunkHeader *header;
545 546 547

	/*
	 * Try to detect bogus pointers handed to us, poorly though we can.
B
Bruce Momjian 已提交
548 549
	 * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
	 * allocated chunk.
550 551 552
	 */
	Assert(pointer != NULL);
	Assert(pointer == (void *) MAXALIGN(pointer));
B
Bruce Momjian 已提交
553

554 555 556 557 558 559 560 561
	/*
	 * OK, it's probably safe to look at the chunk header.
	 */
	header = (StandardChunkHeader *)
		((char *) pointer - STANDARDCHUNKHEADERSIZE);

	AssertArg(MemoryContextIsValid(header->context));

B
Bruce Momjian 已提交
562
	(*header->context->methods->free_p) (header->context, pointer);
563 564 565
}

/*
566
 * repalloc
567 568
 *
 */
569 570
void *
repalloc(void *pointer, Size size)
571
{
B
Bruce Momjian 已提交
572
	StandardChunkHeader *header;
573 574 575

	/*
	 * Try to detect bogus pointers handed to us, poorly though we can.
B
Bruce Momjian 已提交
576 577
	 * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
	 * allocated chunk.
578 579 580
	 */
	Assert(pointer != NULL);
	Assert(pointer == (void *) MAXALIGN(pointer));
B
Bruce Momjian 已提交
581

582 583 584 585 586 587 588
	/*
	 * OK, it's probably safe to look at the chunk header.
	 */
	header = (StandardChunkHeader *)
		((char *) pointer - STANDARDCHUNKHEADERSIZE);

	AssertArg(MemoryContextIsValid(header->context));
589

590 591 592
	if (!AllocSizeIsValid(size))
		elog(ERROR, "repalloc: invalid request size %lu",
			 (unsigned long) size);
593

B
Bruce Momjian 已提交
594
	return (*header->context->methods->realloc) (header->context,
595
												 pointer, size);
596 597 598
}

/*
599 600
 * MemoryContextSwitchTo
 *		Returns the current context; installs the given context.
601
 */
602 603
MemoryContext
MemoryContextSwitchTo(MemoryContext context)
604
{
605
	MemoryContext old;
606

607
	AssertArg(MemoryContextIsValid(context));
608

609 610 611
	old = CurrentMemoryContext;
	CurrentMemoryContext = context;
	return old;
612
}
613

614
/*
615 616
 * MemoryContextStrdup
 *		Like strdup(), but allocate from the specified context
617
 */
618 619
char *
MemoryContextStrdup(MemoryContext context, const char *string)
620
{
621 622
	char	   *nstr;
	Size		len = strlen(string) + 1;
623

624
	nstr = (char *) MemoryContextAlloc(context, len);
625

626 627 628
	memcpy(nstr, string, len);

	return nstr;
629
}