text: /*-------------------------------------------------------------------------
   *
   * freepage.h
   *	  Management of page-organized free memory.
   *
   * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
   *
   * src/include/utils/freepage.h
   *
   *-------------------------------------------------------------------------
   */
  
  #ifndef FREEPAGE_H
  #define FREEPAGE_H
  
  #include "storage/lwlock.h"
  #include "utils/relptr.h"
  
  /* Forward declarations. */
  typedef struct FreePageSpanLeader FreePageSpanLeader;
  typedef struct FreePageBtree FreePageBtree;
  typedef struct FreePageManager FreePageManager;
  
  /*
   * PostgreSQL normally uses 8kB pages for most things, but many common
   * architecture/operating system pairings use a 4kB page size for memory
   * allocation, so we do that here also.
   */
  #define FPM_PAGE_SIZE			4096
  
  /*
   * Each freelist except for the last contains only spans of one particular
   * size.  Everything larger goes on the last one.  In some sense this seems
   * like a waste since most allocations are in a few common sizes, but it
   * means that small allocations can simply pop the head of the relevant list
   * without needing to worry about whether the object we find there is of
   * precisely the correct size (because we know it must be).
   */
  #define FPM_NUM_FREELISTS		129
  
  /* Define relative pointer types. */
  relptr_declare(FreePageBtree, RelptrFreePageBtree);
  relptr_declare(FreePageManager, RelptrFreePageManager);
  relptr_declare(FreePageSpanLeader, RelptrFreePageSpanLeader);
  
  /* Everything we need in order to manage free pages (see freepage.c) */
  struct FreePageManager
  {
  	RelptrFreePageManager self;
  	RelptrFreePageBtree btree_root;
  	RelptrFreePageSpanLeader btree_recycle;
  	unsigned	btree_depth;
  	unsigned	btree_recycle_count;
  	Size		singleton_first_page;
  	Size		singleton_npages;
  	Size		contiguous_pages;
  	bool		contiguous_pages_dirty;
  	RelptrFreePageSpanLeader freelist[FPM_NUM_FREELISTS];
  #ifdef FPM_EXTRA_ASSERTS
  	/* For debugging only, pages put minus pages gotten. */
  	Size		free_pages;
  #endif
  };
  
  /* Macros to convert between page numbers (expressed as Size) and pointers. */
  #define fpm_page_to_pointer(base, page) \
  	(AssertVariableIsOfTypeMacro(page, Size), \
  	 (base) + FPM_PAGE_SIZE * (page))
  #define fpm_pointer_to_page(base, ptr)		\
  	(((Size) (((char *) (ptr)) - (base))) / FPM_PAGE_SIZE)
  
  /* Macro to convert an allocation size to a number of pages. */
  #define fpm_size_to_pages(sz) \
  	(((sz) + FPM_PAGE_SIZE - 1) / FPM_PAGE_SIZE)
  
  /* Macros to check alignment of absolute and relative pointers. */
  #define fpm_pointer_is_page_aligned(base, ptr)		\
  	(((Size) (((char *) (ptr)) - (base))) % FPM_PAGE_SIZE == 0)
  #define fpm_relptr_is_page_aligned(base, relptr)		\
  	((relptr).relptr_off % FPM_PAGE_SIZE == 0)
  
  /* Macro to find base address of the segment containing a FreePageManager. */
  #define fpm_segment_base(fpm)	\
  	(((char *) fpm) - fpm->self.relptr_off)
  
  /* Macro to access a FreePageManager's largest consecutive run of pages. */
  #define fpm_largest(fpm) \
  	(fpm->contiguous_pages)
  
  /* Functions to manipulate the free page map. */
  extern void FreePageManagerInitialize(FreePageManager *fpm, char *base);
  extern bool FreePageManagerGet(FreePageManager *fpm, Size npages,
  							   Size *first_page);
  extern void FreePageManagerPut(FreePageManager *fpm, Size first_page,
  							   Size npages);
  extern char *FreePageManagerDump(FreePageManager *fpm);
  
  #endif							/* FREEPAGE_H */
  