Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/src/include/storage/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 2 kB image not shown  

Quelle  fsmpage.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * fsmpage.c
 *   routines to search and manipulate one FSM page.
 *
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *   src/backend/storage/freespace/fsmpage.c
 *
 * NOTES:
 *
 * The public functions in this file form an API that hides the internal
 * structure of a FSM page. This allows freespace.c to treat each FSM page
 * as a black box with SlotsPerPage "slots". fsm_set_avail() and
 * fsm_get_avail() let you get/set the value of a slot, and
 * fsm_search_avail() lets you search for a slot with value >= X.
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "storage/bufmgr.h"
#include "storage/fsm_internals.h"

/* Macros to navigate the tree within a page. Root has index zero. */
#define leftchild(x) (2 * (x) + 1)
#define rightchild(x) (2 * (x) + 2)
#define parentof(x)  (((x) - 1) / 2)

/*
 * Find right neighbor of x, wrapping around within the level
 */

static int
rightneighbor(int x)
{
 /*
  * Move right. This might wrap around, stepping to the leftmost node at
  * the next level.
 */

 x++;

 /*
  * Check if we stepped to the leftmost node at next level, and correct if
  * so. The leftmost nodes at each level are numbered x = 2^level - 1, so
  * check if (x + 1) is a power of two, using a standard
  * twos-complement-arithmetic trick.
 */

 if (((x + 1) & x) == 0)
  x = parentof(x);

 return x;
}

/*
 * Sets the value of a slot on page. Returns true if the page was modified.
 *
 * The caller must hold an exclusive lock on the page.
 */

bool
fsm_set_avail(Page page, int slot, uint8 value)
{
 int   nodeno = NonLeafNodesPerPage + slot;
 FSMPage  fsmpage = (FSMPage) PageGetContents(page);
 uint8  oldvalue;

 Assert(slot < LeafNodesPerPage);

 oldvalue = fsmpage->fp_nodes[nodeno];

 /* If the value hasn't changed, we don't need to do anything */
 if (oldvalue == value && value <= fsmpage->fp_nodes[0])
  return false;

 fsmpage->fp_nodes[nodeno] = value;

 /*
  * Propagate up, until we hit the root or a node that doesn't need to be
  * updated.
 */

 do
 {
  uint8  newvalue = 0;
  int   lchild;
  int   rchild;

  nodeno = parentof(nodeno);
  lchild = leftchild(nodeno);
  rchild = lchild + 1;

  newvalue = fsmpage->fp_nodes[lchild];
  if (rchild < NodesPerPage)
   newvalue = Max(newvalue,
         fsmpage->fp_nodes[rchild]);

  oldvalue = fsmpage->fp_nodes[nodeno];
  if (oldvalue == newvalue)
   break;

  fsmpage->fp_nodes[nodeno] = newvalue;
 } while (nodeno > 0);

 /*
  * sanity check: if the new value is (still) higher than the value at the
  * top, the tree is corrupt.  If so, rebuild.
 */

 if (value > fsmpage->fp_nodes[0])
  fsm_rebuild_page(page);

 return true;
}

/*
 * Returns the value of given slot on page.
 *
 * Since this is just a read-only access of a single byte, the page doesn't
 * need to be locked.
 */

uint8
fsm_get_avail(Page page, int slot)
{
 FSMPage  fsmpage = (FSMPage) PageGetContents(page);

 Assert(slot < LeafNodesPerPage);

 return fsmpage->fp_nodes[NonLeafNodesPerPage + slot];
}

/*
 * Returns the value at the root of a page.
 *
 * Since this is just a read-only access of a single byte, the page doesn't
 * need to be locked.
 */

uint8
fsm_get_max_avail(Page page)
{
 FSMPage  fsmpage = (FSMPage) PageGetContents(page);

 return fsmpage->fp_nodes[0];
}

/*
 * Searches for a slot with category at least minvalue.
 * Returns slot number, or -1 if none found.
 *
 * The caller must hold at least a shared lock on the page, and this
 * function can unlock and lock the page again in exclusive mode if it
 * needs to be updated. exclusive_lock_held should be set to true if the
 * caller is already holding an exclusive lock, to avoid extra work.
 *
 * If advancenext is false, fp_next_slot is set to point to the returned
 * slot, and if it's true, to the slot after the returned slot.
 */

int
fsm_search_avail(Buffer buf, uint8 minvalue, bool advancenext,
     bool exclusive_lock_held)
{
 Page  page = BufferGetPage(buf);
 FSMPage  fsmpage = (FSMPage) PageGetContents(page);
 int   nodeno;
 int   target;
 uint16  slot;

restart:

 /*
  * Check the root first, and exit quickly if there's no leaf with enough
  * free space
 */

 if (fsmpage->fp_nodes[0] < minvalue)
  return -1;

 /*
  * Start search using fp_next_slot.  It's just a hint, so check that it's
  * sane.  (This also handles wrapping around when the prior call returned
  * the last slot on the page.)
 */

 target = fsmpage->fp_next_slot;
 if (target < 0 || target >= LeafNodesPerPage)
  target = 0;
 target += NonLeafNodesPerPage;

 /*----------
  * Start the search from the target slot.  At every step, move one
  * node to the right, then climb up to the parent.  Stop when we reach
  * a node with enough free space (as we must, since the root has enough
  * space).
  *
  * The idea is to gradually expand our "search triangle", that is, all
  * nodes covered by the current node, and to be sure we search to the
  * right from the start point.  At the first step, only the target slot
  * is examined.  When we move up from a left child to its parent, we are
  * adding the right-hand subtree of that parent to the search triangle.
  * When we move right then up from a right child, we are dropping the
  * current search triangle (which we know doesn't contain any suitable
  * page) and instead looking at the next-larger-size triangle to its
  * right.  So we never look left from our original start point, and at
  * each step the size of the search triangle doubles, ensuring it takes
  * only log2(N) work to search N pages.
  *
  * The "move right" operation will wrap around if it hits the right edge
  * of the tree, so the behavior is still good if we start near the right.
  * Note also that the move-and-climb behavior ensures that we can't end
  * up on one of the missing nodes at the right of the leaf level.
  *
  * For example, consider this tree:
  *
  *     7
  *    7    6
  *  5  7  6  5
  * 4 5 5 7 2 6 5 2
  *    T
  *
  * Assume that the target node is the node indicated by the letter T,
  * and we're searching for a node with value of 6 or higher. The search
  * begins at T. At the first iteration, we move to the right, then to the
  * parent, arriving at the rightmost 5. At the second iteration, we move
  * to the right, wrapping around, then climb up, arriving at the 7 on the
  * third level.  7 satisfies our search, so we descend down to the bottom,
  * following the path of sevens.  This is in fact the first suitable page
  * to the right of (allowing for wraparound) our start point.
  *----------
 */

 nodeno = target;
 while (nodeno > 0)
 {
  if (fsmpage->fp_nodes[nodeno] >= minvalue)
   break;

  /*
   * Move to the right, wrapping around on same level if necessary, then
   * climb up.
 */

  nodeno = parentof(rightneighbor(nodeno));
 }

 /*
  * We're now at a node with enough free space, somewhere in the middle of
  * the tree. Descend to the bottom, following a path with enough free
  * space, preferring to move left if there's a choice.
 */

 while (nodeno < NonLeafNodesPerPage)
 {
  int   childnodeno = leftchild(nodeno);

  if (childnodeno < NodesPerPage &&
   fsmpage->fp_nodes[childnodeno] >= minvalue)
  {
   nodeno = childnodeno;
   continue;
  }
  childnodeno++;   /* point to right child */
  if (childnodeno < NodesPerPage &&
   fsmpage->fp_nodes[childnodeno] >= minvalue)
  {
   nodeno = childnodeno;
  }
  else
  {
   /*
    * Oops. The parent node promised that either left or right child
    * has enough space, but neither actually did. This can happen in
    * case of a "torn page", IOW if we crashed earlier while writing
    * the page to disk, and only part of the page made it to disk.
    *
    * Fix the corruption and restart.
 */

   RelFileLocator rlocator;
   ForkNumber forknum;
   BlockNumber blknum;

   BufferGetTag(buf, &rlocator, &forknum, &blknum);
   elog(DEBUG1, "fixing corrupt FSM block %u, relation %u/%u/%u",
     blknum, rlocator.spcOid, rlocator.dbOid, rlocator.relNumber);

   /* make sure we hold an exclusive lock */
   if (!exclusive_lock_held)
   {
    LockBuffer(buf, BUFFER_LOCK_UNLOCK);
    LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
    exclusive_lock_held = true;
   }
   fsm_rebuild_page(page);
   MarkBufferDirtyHint(buf, false);
   goto restart;
  }
 }

 /* We're now at the bottom level, at a node with enough space. */
 slot = nodeno - NonLeafNodesPerPage;

 /*
  * Update the next-target pointer. Note that we do this even if we're only
  * holding a shared lock, on the grounds that it's better to use a shared
  * lock and get a garbled next pointer every now and then, than take the
  * concurrency hit of an exclusive lock.
  *
  * Wrap-around is handled at the beginning of this function.
 */

 fsmpage->fp_next_slot = slot + (advancenext ? 1 : 0);

 return slot;
}

/*
 * Sets the available space to zero for all slots numbered >= nslots.
 * Returns true if the page was modified.
 */

bool
fsm_truncate_avail(Page page, int nslots)
{
 FSMPage  fsmpage = (FSMPage) PageGetContents(page);
 uint8    *ptr;
 bool  changed = false;

 Assert(nslots >= 0 && nslots < LeafNodesPerPage);

 /* Clear all truncated leaf nodes */
 ptr = &fsmpage->fp_nodes[NonLeafNodesPerPage + nslots];
 for (; ptr < &fsmpage->fp_nodes[NodesPerPage]; ptr++)
 {
  if (*ptr != 0)
   changed = true;
  *ptr = 0;
 }

 /* Fix upper nodes. */
 if (changed)
  fsm_rebuild_page(page);

 return changed;
}

/*
 * Reconstructs the upper levels of a page. Returns true if the page
 * was modified.
 */

bool
fsm_rebuild_page(Page page)
{
 FSMPage  fsmpage = (FSMPage) PageGetContents(page);
 bool  changed = false;
 int   nodeno;

 /*
  * Start from the lowest non-leaf level, at last node, working our way
  * backwards, through all non-leaf nodes at all levels, up to the root.
 */

 for (nodeno = NonLeafNodesPerPage - 1; nodeno >= 0; nodeno--)
 {
  int   lchild = leftchild(nodeno);
  int   rchild = lchild + 1;
  uint8  newvalue = 0;

  /* The first few nodes we examine might have zero or one child. */
  if (lchild < NodesPerPage)
   newvalue = fsmpage->fp_nodes[lchild];

  if (rchild < NodesPerPage)
   newvalue = Max(newvalue,
         fsmpage->fp_nodes[rchild]);

  if (fsmpage->fp_nodes[nodeno] != newvalue)
  {
   fsmpage->fp_nodes[nodeno] = newvalue;
   changed = true;
  }
 }

 return changed;
}

Messung V0.5 in Prozent
C=93 H=91 G=91

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.