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

Quelle  test_resowner_many.c

  Sprache: C
 

/*--------------------------------------------------------------------------
 *
 * test_resowner_many.c
 *  Test ResourceOwner functionality with lots of resources
 *
 * Copyright (c) 2022-2025, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *  src/test/modules/test_resowner/test_resowner_many.c
 *
 * -------------------------------------------------------------------------
 */

#include "postgres.h"

#include "fmgr.h"
#include "lib/ilist.h"
#include "utils/resowner.h"

/*
 * Define a custom resource type to use in the test.  The resource being
 * tracked is a palloc'd ManyTestResource struct.
 *
 * To cross-check that the ResourceOwner calls the callback functions
 * correctly, we keep track of the remembered resources ourselves in a linked
 * list, and also keep counters of how many times the callback functions have
 * been called.
 */

typedef struct
{
 ResourceOwnerDesc desc;
 int   nremembered;
 int   nforgotten;
 int   nreleased;
 int   nleaked;

 dlist_head current_resources;
} ManyTestResourceKind;

typedef struct
{
 ManyTestResourceKind *kind;
 dlist_node node;
} ManyTestResource;

/*
 * Current release phase, and priority of last call to the release callback.
 * This is used to check that the resources are released in correct order.
 */

static ResourceReleasePhase current_release_phase;
static uint32 last_release_priority = 0;

/* prototypes for local functions */
static void ReleaseManyTestResource(Datum res);
static char *PrintManyTest(Datum res);
static void InitManyTestResourceKind(ManyTestResourceKind *kind, char *name,
          ResourceReleasePhase phase, uint32 priority);
static void RememberManyTestResources(ResourceOwner owner,
           ManyTestResourceKind *kinds, int nkinds,
           int nresources);
static void ForgetManyTestResources(ResourceOwner owner,
         ManyTestResourceKind *kinds, int nkinds,
         int nresources);
static int GetTotalResourceCount(ManyTestResourceKind *kinds, int nkinds);

/* ResourceOwner callback */
static void
ReleaseManyTestResource(Datum res)
{
 ManyTestResource *mres = (ManyTestResource *) DatumGetPointer(res);

 elog(DEBUG1, "releasing resource %p from %s", mres, mres->kind->desc.name);
 Assert(last_release_priority <= mres->kind->desc.release_priority);

 dlist_delete(&mres->node);
 mres->kind->nreleased++;
 last_release_priority = mres->kind->desc.release_priority;
 pfree(mres);
}

/* ResourceOwner callback */
static char *
PrintManyTest(Datum res)
{
 ManyTestResource *mres = (ManyTestResource *) DatumGetPointer(res);

 /*
  * XXX: we assume that the DebugPrint function is called once for each
  * leaked resource, and that there are no other callers.
 */

 mres->kind->nleaked++;

 return psprintf("many-test resource from %s", mres->kind->desc.name);
}

static void
InitManyTestResourceKind(ManyTestResourceKind *kind, char *name,
       ResourceReleasePhase phase, uint32 priority)
{
 kind->desc.name = name;
 kind->desc.release_phase = phase;
 kind->desc.release_priority = priority;
 kind->desc.ReleaseResource = ReleaseManyTestResource;
 kind->desc.DebugPrint = PrintManyTest;
 kind->nremembered = 0;
 kind->nforgotten = 0;
 kind->nreleased = 0;
 kind->nleaked = 0;
 dlist_init(&kind->current_resources);
}

/*
 * Remember 'nresources' resources.  The resources are remembered in round
 * robin fashion with the kinds from 'kinds' array.
 */

static void
RememberManyTestResources(ResourceOwner owner,
        ManyTestResourceKind *kinds, int nkinds,
        int nresources)
{
 int   kind_idx = 0;

 for (int i = 0; i < nresources; i++)
 {
  ManyTestResource *mres = palloc(sizeof(ManyTestResource));

  mres->kind = &kinds[kind_idx];
  dlist_node_init(&mres->node);

  ResourceOwnerEnlarge(owner);
  ResourceOwnerRemember(owner, PointerGetDatum(mres), &kinds[kind_idx].desc);
  kinds[kind_idx].nremembered++;
  dlist_push_tail(&kinds[kind_idx].current_resources, &mres->node);

  elog(DEBUG1, "remembered resource %p from %s", mres, mres->kind->desc.name);

  kind_idx = (kind_idx + 1) % nkinds;
 }
}

/*
 * Forget 'nresources' resources, in round robin fashion from 'kinds'.
 */

static void
ForgetManyTestResources(ResourceOwner owner,
      ManyTestResourceKind *kinds, int nkinds,
      int nresources)
{
 int   kind_idx = 0;
 int   ntotal;

 ntotal = GetTotalResourceCount(kinds, nkinds);
 if (ntotal < nresources)
  elog(PANIC, "cannot free %d resources, only %d remembered", nresources, ntotal);

 for (int i = 0; i < nresources; i++)
 {
  bool  found = false;

  for (int j = 0; j < nkinds; j++)
  {
   kind_idx = (kind_idx + 1) % nkinds;
   if (!dlist_is_empty(&kinds[kind_idx].current_resources))
   {
    ManyTestResource *mres = dlist_head_element(ManyTestResource, node, &kinds[kind_idx].current_resources);

    ResourceOwnerForget(owner, PointerGetDatum(mres), &kinds[kind_idx].desc);
    kinds[kind_idx].nforgotten++;
    dlist_delete(&mres->node);
    pfree(mres);

    found = true;
    break;
   }
  }
  if (!found)
   elog(ERROR, "could not find a test resource to forget");
 }
}

/*
 * Get total number of currently active resources among 'kinds'.
 */

static int
GetTotalResourceCount(ManyTestResourceKind *kinds, int nkinds)
{
 int   ntotal = 0;

 for (int i = 0; i < nkinds; i++)
  ntotal += kinds[i].nremembered - kinds[i].nforgotten - kinds[i].nreleased;

 return ntotal;
}

/*
 * Remember lots of resources, belonging to 'nkinds' different resource types
 * with different priorities.  Then forget some of them, and finally, release
 * the resource owner.  We use a custom resource type that performs various
 * sanity checks to verify that all the resources are released, and in the
 * correct order.
 */

PG_FUNCTION_INFO_V1(test_resowner_many);
Datum
test_resowner_many(PG_FUNCTION_ARGS)
{
 int32  nkinds = PG_GETARG_INT32(0);
 int32  nremember_bl = PG_GETARG_INT32(1);
 int32  nforget_bl = PG_GETARG_INT32(2);
 int32  nremember_al = PG_GETARG_INT32(3);
 int32  nforget_al = PG_GETARG_INT32(4);

 ResourceOwner resowner;

 ManyTestResourceKind *before_kinds;
 ManyTestResourceKind *after_kinds;

 /* Sanity check the arguments */
 if (nkinds < 0)
  elog(ERROR, "nkinds must be >= 0");
 if (nremember_bl < 0)
  elog(ERROR, "nremember_bl must be >= 0");
 if (nforget_bl < 0 || nforget_bl > nremember_bl)
  elog(ERROR, "nforget_bl must between 0 and 'nremember_bl'");
 if (nremember_al < 0)
  elog(ERROR, "nremember_al must be greater than zero");
 if (nforget_al < 0 || nforget_al > nremember_al)
  elog(ERROR, "nforget_al must between 0 and 'nremember_al'");

 /* Initialize all the different resource kinds to use */
 before_kinds = palloc(nkinds * sizeof(ManyTestResourceKind));
 for (int i = 0; i < nkinds; i++)
 {
  InitManyTestResourceKind(&before_kinds[i],
         psprintf("resource before locks %d", i),
         RESOURCE_RELEASE_BEFORE_LOCKS,
         RELEASE_PRIO_FIRST + i);
 }
 after_kinds = palloc(nkinds * sizeof(ManyTestResourceKind));
 for (int i = 0; i < nkinds; i++)
 {
  InitManyTestResourceKind(&after_kinds[i],
         psprintf("resource after locks %d", i),
         RESOURCE_RELEASE_AFTER_LOCKS,
         RELEASE_PRIO_FIRST + i);
 }

 resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");

 /* Remember a bunch of resources */
 if (nremember_bl > 0)
 {
  elog(NOTICE, "remembering %d before-locks resources", nremember_bl);
  RememberManyTestResources(resowner, before_kinds, nkinds, nremember_bl);
 }
 if (nremember_al > 0)
 {
  elog(NOTICE, "remembering %d after-locks resources", nremember_al);
  RememberManyTestResources(resowner, after_kinds, nkinds, nremember_al);
 }

 /* Forget what was remembered */
 if (nforget_bl > 0)
 {
  elog(NOTICE, "forgetting %d before-locks resources", nforget_bl);
  ForgetManyTestResources(resowner, before_kinds, nkinds, nforget_bl);
 }

 if (nforget_al > 0)
 {
  elog(NOTICE, "forgetting %d after-locks resources", nforget_al);
  ForgetManyTestResources(resowner, after_kinds, nkinds, nforget_al);
 }

 /* Start releasing */
 elog(NOTICE, "releasing resources before locks");
 current_release_phase = RESOURCE_RELEASE_BEFORE_LOCKS;
 last_release_priority = 0;
 ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, falsefalse);
 Assert(GetTotalResourceCount(before_kinds, nkinds) == 0);

 elog(NOTICE, "releasing locks");
 current_release_phase = RESOURCE_RELEASE_LOCKS;
 last_release_priority = 0;
 ResourceOwnerRelease(resowner, RESOURCE_RELEASE_LOCKS, falsefalse);

 elog(NOTICE, "releasing resources after locks");
 current_release_phase = RESOURCE_RELEASE_AFTER_LOCKS;
 last_release_priority = 0;
 ResourceOwnerRelease(resowner, RESOURCE_RELEASE_AFTER_LOCKS, falsefalse);
 Assert(GetTotalResourceCount(before_kinds, nkinds) == 0);
 Assert(GetTotalResourceCount(after_kinds, nkinds) == 0);

 ResourceOwnerDelete(resowner);

 PG_RETURN_VOID();
}

Messung V0.5 in Prozent
C=94 H=98 G=95

¤ Dauer der Verarbeitung: 0.20 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.