aset.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:10k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * aset.c
  4.  *   Allocation set definitions.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.16.2.1 1999/08/02 05:25:15 scrappy Exp $
  11.  *
  12.  * NOTE:
  13.  * This is a new (Feb. 05, 1999) implementation of the allocation set
  14.  * routines. AllocSet...() does not use OrderedSet...() any more.
  15.  * Instead it manages allocations in a block pool by itself, combining
  16.  * many small allocations in a few bigger blocks. AllocSetFree() does
  17.  * never free() memory really. It just add's the free'd area to some
  18.  * list for later reuse by AllocSetAlloc(). All memory blocks are free()'d
  19.  * at once on AllocSetReset(), which happens when the memory context gets
  20.  * destroyed.
  21.  * Jan Wieck
  22.  *-------------------------------------------------------------------------
  23.  */
  24. #include "postgres.h"
  25. #include "utils/memutils.h"
  26. #undef AllocSetReset
  27. #undef malloc
  28. #undef free
  29. #undef realloc
  30. /*--------------------
  31.  * Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
  32.  * for k = 0 .. ALLOCSET_NUM_FREELISTS-2.
  33.  * The last freelist holds all larger chunks.
  34.  *
  35.  * CAUTION: ALLOC_MINBITS must be large enough so that
  36.  * 1<<ALLOC_MINBITS is at least MAXALIGN,
  37.  * or we may fail to align the smallest chunks adequately.
  38.  * 16-byte alignment is enough on all currently known machines.
  39.  *--------------------
  40.  */
  41. #define ALLOC_MINBITS 4 /* smallest chunk size is 16 bytes */
  42. #define ALLOC_SMALLCHUNK_LIMIT (1 << (ALLOCSET_NUM_FREELISTS-2+ALLOC_MINBITS))
  43. /* Size of largest chunk that we use a fixed size for */
  44. /*--------------------
  45.  * The first block allocated for an allocset has size ALLOC_MIN_BLOCK_SIZE.
  46.  * Each time we have to allocate another block, we double the block size
  47.  * (if possible, and without exceeding ALLOC_MAX_BLOCK_SIZE), so as to reduce
  48.  * the load on "malloc".
  49.  *
  50.  * Blocks allocated to hold oversize chunks do not follow this rule, however;
  51.  * they are just however big they need to be.
  52.  *--------------------
  53.  */
  54. #define ALLOC_MIN_BLOCK_SIZE 8192
  55. #define ALLOC_MAX_BLOCK_SIZE (8 * 1024 * 1024)
  56. #define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
  57. #define ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData))
  58. #define AllocPointerGetChunk(ptr)
  59. ((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))
  60. #define AllocChunkGetPointer(chk)
  61. ((AllocPointer)(((char *)(chk)) + ALLOC_CHUNKHDRSZ))
  62. #define AllocPointerGetAset(ptr) ((AllocSet)(AllocPointerGetChunk(ptr)->aset))
  63. #define AllocPointerGetSize(ptr) (AllocPointerGetChunk(ptr)->size)
  64. /* ----------
  65.  * AllocSetFreeIndex -
  66.  *
  67.  * Depending on the size of an allocation compute which freechunk
  68.  * list of the alloc set it belongs to.
  69.  * ----------
  70.  */
  71. static inline int
  72. AllocSetFreeIndex(Size size)
  73. {
  74. int idx = 0;
  75. if (size > 0)
  76. {
  77. size = (size - 1) >> ALLOC_MINBITS;
  78. while (size != 0 && idx < ALLOCSET_NUM_FREELISTS - 1)
  79. {
  80. idx++;
  81. size >>= 1;
  82. }
  83. }
  84. return idx;
  85. }
  86. /*
  87.  * Public routines
  88.  */
  89. /*
  90.  * AllocPointerIsValid(pointer)
  91.  * AllocSetIsValid(set)
  92.  *
  93.  * .. are now macros in aset.h -cim 4/27/91
  94.  */
  95. /*
  96.  * AllocSetInit
  97.  * Initializes given allocation set.
  98.  *
  99.  * Note:
  100.  * The semantics of the mode are explained above. Limit is ignored
  101.  * for dynamic and static modes.
  102.  *
  103.  * Exceptions:
  104.  * BadArg if set is invalid pointer.
  105.  * BadArg if mode is invalid.
  106.  */
  107. void
  108. AllocSetInit(AllocSet set, AllocMode mode, Size limit)
  109. {
  110. AssertArg(PointerIsValid(set));
  111. AssertArg((int) DynamicAllocMode <= (int) mode);
  112. AssertArg((int) mode <= (int) BoundedAllocMode);
  113. /*
  114.  * XXX mode is currently ignored and treated as DynamicAllocMode. XXX
  115.  * limit is also ignored.  This affects this whole file.
  116.  */
  117. memset(set, 0, sizeof(AllocSetData));
  118. }
  119. /*
  120.  * AllocSetReset
  121.  * Frees memory which is allocated in the given set.
  122.  *
  123.  * Exceptions:
  124.  * BadArg if set is invalid.
  125.  */
  126. void
  127. AllocSetReset(AllocSet set)
  128. {
  129. AllocBlock block = set->blocks;
  130. AllocBlock next;
  131. AssertArg(AllocSetIsValid(set));
  132. while (block != NULL)
  133. {
  134. next = block->next;
  135. free(block);
  136. block = next;
  137. }
  138. memset(set, 0, sizeof(AllocSetData));
  139. }
  140. /*
  141.  * AllocSetContains
  142.  * True iff allocation set contains given allocation element.
  143.  *
  144.  * Exceptions:
  145.  * BadArg if set is invalid.
  146.  * BadArg if pointer is invalid.
  147.  */
  148. bool
  149. AllocSetContains(AllocSet set, AllocPointer pointer)
  150. {
  151. AssertArg(AllocSetIsValid(set));
  152. AssertArg(AllocPointerIsValid(pointer));
  153. return (AllocPointerGetAset(pointer) == set);
  154. }
  155. /*
  156.  * AllocSetAlloc
  157.  * Returns pointer to allocated memory of given size; memory is added
  158.  * to the set.
  159.  *
  160.  * Exceptions:
  161.  * BadArg if set is invalid.
  162.  * MemoryExhausted if allocation fails.
  163.  */
  164. AllocPointer
  165. AllocSetAlloc(AllocSet set, Size size)
  166. {
  167. AllocBlock block;
  168. AllocChunk chunk;
  169. AllocChunk freeref = NULL;
  170. int fidx;
  171. Size chunk_size;
  172. Size blksize;
  173. AssertArg(AllocSetIsValid(set));
  174. /*
  175.  * Lookup in the corresponding free list if there is a free chunk we
  176.  * could reuse
  177.  *
  178.  */
  179. fidx = AllocSetFreeIndex(size);
  180. for (chunk = set->freelist[fidx]; chunk; chunk = (AllocChunk) chunk->aset)
  181. {
  182. if (chunk->size >= size)
  183. break;
  184. freeref = chunk;
  185. }
  186. /*
  187.  * If one is found, remove it from the free list, make it again a
  188.  * member of the alloc set and return it's data address.
  189.  *
  190.  */
  191. if (chunk != NULL)
  192. {
  193. if (freeref == NULL)
  194. set->freelist[fidx] = (AllocChunk) chunk->aset;
  195. else
  196. freeref->aset = chunk->aset;
  197. chunk->aset = (void *) set;
  198. return AllocChunkGetPointer(chunk);
  199. }
  200. /*
  201.  * Choose the actual chunk size to allocate.
  202.  */
  203. if (size > ALLOC_SMALLCHUNK_LIMIT)
  204. chunk_size = MAXALIGN(size);
  205. else
  206. chunk_size = 1 << (fidx + ALLOC_MINBITS);
  207. Assert(chunk_size >= size);
  208. /*
  209.  * If there is enough room in the active allocation block, always
  210.  * allocate the chunk there.
  211.  */
  212. if ((block = set->blocks) != NULL)
  213. {
  214. Size have_free = block->endptr - block->freeptr;
  215. if (have_free < (chunk_size + ALLOC_CHUNKHDRSZ))
  216. block = NULL;
  217. }
  218. /*
  219.  * Otherwise, if requested size exceeds smallchunk limit, allocate an
  220.  * entire separate block for this allocation
  221.  *
  222.  */
  223. if (block == NULL && size > ALLOC_SMALLCHUNK_LIMIT)
  224. {
  225. blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
  226. block = (AllocBlock) malloc(blksize);
  227. if (block == NULL)
  228. elog(FATAL, "Memory exhausted in AllocSetAlloc()");
  229. block->aset = set;
  230. block->freeptr = block->endptr = ((char *) block) + blksize;
  231. chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
  232. chunk->aset = set;
  233. chunk->size = chunk_size;
  234. /*
  235.  * Try to stick the block underneath the active allocation block,
  236.  * so that we don't lose the use of the space remaining therein.
  237.  */
  238. if (set->blocks != NULL)
  239. {
  240. block->next = set->blocks->next;
  241. set->blocks->next = block;
  242. }
  243. else
  244. {
  245. block->next = NULL;
  246. set->blocks = block;
  247. }
  248. return AllocChunkGetPointer(chunk);
  249. }
  250. /*
  251.  * Time to create a new regular block?
  252.  */
  253. if (block == NULL)
  254. {
  255. if (set->blocks == NULL)
  256. {
  257. blksize = ALLOC_MIN_BLOCK_SIZE;
  258. block = (AllocBlock) malloc(blksize);
  259. }
  260. else
  261. {
  262. /* Get size of prior block */
  263. blksize = set->blocks->endptr - ((char *) set->blocks);
  264. /*
  265.  * Special case: if very first allocation was for a large
  266.  * chunk, could have a funny-sized top block.  Do something
  267.  * reasonable.
  268.  */
  269. if (blksize < ALLOC_MIN_BLOCK_SIZE)
  270. blksize = ALLOC_MIN_BLOCK_SIZE;
  271. /* Crank it up, but not past max */
  272. blksize <<= 1;
  273. if (blksize > ALLOC_MAX_BLOCK_SIZE)
  274. blksize = ALLOC_MAX_BLOCK_SIZE;
  275. /* Try to allocate it */
  276. block = (AllocBlock) malloc(blksize);
  277. /*
  278.  * We could be asking for pretty big blocks here, so cope if
  279.  * malloc fails.  But give up if there's less than a meg or so
  280.  * available...
  281.  */
  282. while (block == NULL && blksize > 1024 * 1024)
  283. {
  284. blksize >>= 1;
  285. block = (AllocBlock) malloc(blksize);
  286. }
  287. }
  288. if (block == NULL)
  289. elog(FATAL, "Memory exhausted in AllocSetAlloc()");
  290. block->aset = set;
  291. block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
  292. block->endptr = ((char *) block) + blksize;
  293. block->next = set->blocks;
  294. set->blocks = block;
  295. }
  296. /*
  297.  * OK, do the allocation
  298.  */
  299. chunk = (AllocChunk) (block->freeptr);
  300. chunk->aset = (void *) set;
  301. chunk->size = chunk_size;
  302. block->freeptr += (chunk_size + ALLOC_CHUNKHDRSZ);
  303. Assert(block->freeptr <= block->endptr);
  304. return AllocChunkGetPointer(chunk);
  305. }
  306. /*
  307.  * AllocSetFree
  308.  * Frees allocated memory; memory is removed from the set.
  309.  *
  310.  * Exceptions:
  311.  * BadArg if set is invalid.
  312.  * BadArg if pointer is invalid.
  313.  * BadArg if pointer is not member of set.
  314.  */
  315. void
  316. AllocSetFree(AllocSet set, AllocPointer pointer)
  317. {
  318. int fidx;
  319. AllocChunk chunk;
  320. /* AssertArg(AllocSetIsValid(set)); */
  321. /* AssertArg(AllocPointerIsValid(pointer)); */
  322. AssertArg(AllocSetContains(set, pointer));
  323. chunk = AllocPointerGetChunk(pointer);
  324. fidx = AllocSetFreeIndex(chunk->size);
  325. chunk->aset = (void *) set->freelist[fidx];
  326. set->freelist[fidx] = chunk;
  327. }
  328. /*
  329.  * AllocSetRealloc
  330.  * Returns new pointer to allocated memory of given size; this memory
  331.  * is added to the set.  Memory associated with given pointer is copied
  332.  * into the new memory, and the old memory is freed.
  333.  *
  334.  * Exceptions:
  335.  * BadArg if set is invalid.
  336.  * BadArg if pointer is invalid.
  337.  * BadArg if pointer is not member of set.
  338.  * MemoryExhausted if allocation fails.
  339.  */
  340. AllocPointer
  341. AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
  342. {
  343. AllocPointer newPointer;
  344. Size oldsize;
  345. /* AssertArg(AllocSetIsValid(set)); */
  346. /* AssertArg(AllocPointerIsValid(pointer)); */
  347. AssertArg(AllocSetContains(set, pointer));
  348. /*
  349.  * Chunk sizes are aligned to power of 2 on AllocSetAlloc(). Maybe the
  350.  * allocated area already is >= the new size.
  351.  *
  352.  */
  353. oldsize = AllocPointerGetSize(pointer);
  354. if (oldsize >= size)
  355. return pointer;
  356. /* allocate new pointer */
  357. newPointer = AllocSetAlloc(set, size);
  358. /* fill new memory */
  359. memmove(newPointer, pointer, (oldsize < size) ? oldsize : size);
  360. /* free old pointer */
  361. AllocSetFree(set, pointer);
  362. return newPointer;
  363. }
  364. /*
  365.  * AllocSetDump
  366.  * Displays allocated set.
  367.  */
  368. void
  369. AllocSetDump(AllocSet set)
  370. {
  371. elog(DEBUG, "Currently unable to dump AllocSet");
  372. }