aset.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,129 行 · 第 1/3 页
C
1,129 行
set->isReset = false; AllocAllocInfo(set, chunk); return AllocChunkGetPointer(chunk);}/* * AllocSetFree * Frees allocated memory; memory is removed from the set. */static voidAllocSetFree(MemoryContext context, void *pointer){ AllocSet set = (AllocSet) context; AllocChunk chunk = AllocPointerGetChunk(pointer); AllocFreeInfo(set, chunk);#ifdef MEMORY_CONTEXT_CHECKING /* Test for someone scribbling on unused space in chunk */ if (chunk->requested_size < chunk->size) if (((char *) pointer)[chunk->requested_size] != 0x7E) elog(WARNING, "detected write past chunk end in %s %p", set->header.name, chunk);#endif if (chunk->size > set->allocChunkLimit) { /* * Big chunks are certain to have been allocated as single-chunk * blocks. Find the containing block and return it to malloc(). */ AllocBlock block = set->blocks; AllocBlock prevblock = NULL; while (block != NULL) { if (chunk == (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ)) break; prevblock = block; block = block->next; } if (block == NULL) elog(ERROR, "could not find block containing chunk %p", chunk); /* let's just make sure chunk is the only one in the block */ Assert(block->freeptr == ((char *) block) + (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)); /* OK, remove block from aset's list and free it */ if (prevblock == NULL) set->blocks = block->next; else prevblock->next = block->next;#ifdef CLOBBER_FREED_MEMORY /* Wipe freed memory for debugging purposes */ memset(block, 0x7F, block->freeptr - ((char *) block));#endif free(block); } else { /* Normal case, put the chunk into appropriate freelist */ int fidx = AllocSetFreeIndex(chunk->size); chunk->aset = (void *) set->freelist[fidx];#ifdef CLOBBER_FREED_MEMORY /* Wipe freed memory for debugging purposes */ memset(pointer, 0x7F, chunk->size);#endif#ifdef MEMORY_CONTEXT_CHECKING /* Reset requested_size to 0 in chunks that are on freelist */ chunk->requested_size = 0;#endif set->freelist[fidx] = chunk; }}/* * AllocSetRealloc * Returns new pointer to allocated memory of given size; this memory * is added to the set. Memory associated with given pointer is copied * into the new memory, and the old memory is freed. */static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size){ AllocSet set = (AllocSet) context; AllocChunk chunk = AllocPointerGetChunk(pointer); Size oldsize = chunk->size;#ifdef MEMORY_CONTEXT_CHECKING /* Test for someone scribbling on unused space in chunk */ if (chunk->requested_size < oldsize) if (((char *) pointer)[chunk->requested_size] != 0x7E) elog(WARNING, "detected write past chunk end in %s %p", set->header.name, chunk);#endif /* isReset must be false already */ Assert(!set->isReset); /* * Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the * allocated area already is >= the new size. (In particular, we always * fall out here if the requested size is a decrease.) */ if (oldsize >= size) {#ifdef MEMORY_CONTEXT_CHECKING chunk->requested_size = size; /* set mark to catch clobber of "unused" space */ if (size < oldsize) ((char *) pointer)[size] = 0x7E;#endif return pointer; } if (oldsize > set->allocChunkLimit) { /* * The chunk must have been allocated as a single-chunk block. Find * the containing block and use realloc() to make it bigger with * minimum space wastage. */ AllocBlock block = set->blocks; AllocBlock prevblock = NULL; Size chksize; Size blksize; while (block != NULL) { if (chunk == (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ)) break; prevblock = block; block = block->next; } if (block == NULL) elog(ERROR, "could not find block containing chunk %p", chunk); /* let's just make sure chunk is the only one in the block */ Assert(block->freeptr == ((char *) block) + (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)); /* Do the realloc */ chksize = MAXALIGN(size); blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ; block = (AllocBlock) realloc(block, blksize); if (block == NULL) { MemoryContextStats(TopMemoryContext); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed on request of size %lu.", (unsigned long) size))); } block->freeptr = block->endptr = ((char *) block) + blksize; /* Update pointers since block has likely been moved */ chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ); if (prevblock == NULL) set->blocks = block; else prevblock->next = block; chunk->size = chksize;#ifdef MEMORY_CONTEXT_CHECKING chunk->requested_size = size; /* set mark to catch clobber of "unused" space */ if (size < chunk->size) ((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;#endif return AllocChunkGetPointer(chunk); } else { /* * Small-chunk case. We just do this by brute force, ie, allocate a * new chunk and copy the data. Since we know the existing data isn't * huge, this won't involve any great memcpy expense, so it's not * worth being smarter. (At one time we tried to avoid memcpy when it * was possible to enlarge the chunk in-place, but that turns out to * misbehave unpleasantly for repeated cycles of * palloc/repalloc/pfree: the eventually freed chunks go into the * wrong freelist for the next initial palloc request, and so we leak * memory indefinitely. See pgsql-hackers archives for 2007-08-11.) */ AllocPointer newPointer; /* allocate new chunk */ newPointer = AllocSetAlloc((MemoryContext) set, size); /* transfer existing data (certain to fit) */ memcpy(newPointer, pointer, oldsize); /* free old chunk */ AllocSetFree((MemoryContext) set, pointer); return newPointer; }}/* * AllocSetGetChunkSpace * Given a currently-allocated chunk, determine the total space * it occupies (including all memory-allocation overhead). */static SizeAllocSetGetChunkSpace(MemoryContext context, void *pointer){ AllocChunk chunk = AllocPointerGetChunk(pointer); return chunk->size + ALLOC_CHUNKHDRSZ;}/* * AllocSetIsEmpty * Is an allocset empty of any allocated space? */static boolAllocSetIsEmpty(MemoryContext context){ AllocSet set = (AllocSet) context; /* * For now, we say "empty" only if the context is new or just reset. We * could examine the freelists to determine if all space has been freed, * but it's not really worth the trouble for present uses of this * functionality. */ if (set->isReset) return true; return false;}/* * AllocSetStats * Displays stats about memory consumption of an allocset. */static voidAllocSetStats(MemoryContext context, int level){ AllocSet set = (AllocSet) context; long nblocks = 0; long nchunks = 0; long totalspace = 0; long freespace = 0; AllocBlock block; AllocChunk chunk; int fidx; int i; for (block = set->blocks; block != NULL; block = block->next) { nblocks++; totalspace += block->endptr - ((char *) block); freespace += block->endptr - block->freeptr; } for (fidx = 0; fidx < ALLOCSET_NUM_FREELISTS; fidx++) { for (chunk = set->freelist[fidx]; chunk != NULL; chunk = (AllocChunk) chunk->aset) { nchunks++; freespace += chunk->size + ALLOC_CHUNKHDRSZ; } } for (i = 0; i < level; i++) fprintf(stderr, " "); fprintf(stderr, "%s: %lu total in %ld blocks; %lu free (%ld chunks); %lu used\n", set->header.name, totalspace, nblocks, freespace, nchunks, totalspace - freespace);}#ifdef MEMORY_CONTEXT_CHECKING/* * AllocSetCheck * Walk through chunks and check consistency of memory. * * NOTE: report errors as WARNING, *not* ERROR or FATAL. Otherwise you'll * find yourself in an infinite loop when trouble occurs, because this * routine will be entered again when elog cleanup tries to release memory! */static voidAllocSetCheck(MemoryContext context){ AllocSet set = (AllocSet) context; char *name = set->header.name; AllocBlock block; for (block = set->blocks; block != NULL; block = block->next) { char *bpoz = ((char *) block) + ALLOC_BLOCKHDRSZ; long blk_used = block->freeptr - bpoz; long blk_data = 0; long nchunks = 0; /* * Empty block - empty can be keeper-block only */ if (!blk_used) { if (set->keeper != block) elog(WARNING, "problem in alloc set %s: empty block %p", name, block); } /* * Chunk walker */ while (bpoz < block->freeptr) { AllocChunk chunk = (AllocChunk) bpoz; Size chsize, dsize; char *chdata_end; chsize = chunk->size; /* aligned chunk size */ dsize = chunk->requested_size; /* real data */ chdata_end = ((char *) chunk) + (ALLOC_CHUNKHDRSZ + dsize); /* * Check chunk size */ if (dsize > chsize) elog(WARNING, "problem in alloc set %s: req size > alloc size for chunk %p in block %p", name, chunk, block); if (chsize < (1 << ALLOC_MINBITS)) elog(WARNING, "problem in alloc set %s: bad size %lu for chunk %p in block %p", name, (unsigned long) chsize, chunk, block); /* single-chunk block? */ if (chsize > set->allocChunkLimit && chsize + ALLOC_CHUNKHDRSZ != blk_used) elog(WARNING, "problem in alloc set %s: bad single-chunk %p in block %p", name, chunk, block); /* * If chunk is allocated, check for correct aset pointer. (If it's * free, the aset is the freelist pointer, which we can't check as * easily...) */ if (dsize > 0 && chunk->aset != (void *) set) elog(WARNING, "problem in alloc set %s: bogus aset link in block %p, chunk %p", name, block, chunk); /* * Check for overwrite of "unallocated" space in chunk */ if (dsize > 0 && dsize < chsize && *chdata_end != 0x7E) elog(WARNING, "problem in alloc set %s: detected write past chunk end in block %p, chunk %p", name, block, chunk); blk_data += chsize; nchunks++; bpoz += ALLOC_CHUNKHDRSZ + chsize; } if ((blk_data + (nchunks * ALLOC_CHUNKHDRSZ)) != blk_used) elog(WARNING, "problem in alloc set %s: found inconsistent memory block %p", name, block); }}#endif /* MEMORY_CONTEXT_CHECKING */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?