postgresql/src/backend/utils/resowner
Tom Lane 8f59f6b9c0 Improve performance of "simple expressions" in PL/pgSQL.
For relatively simple expressions (say, "x + 1" or "x > 0"), plpgsql's
management overhead exceeds the cost of evaluating the expression.
This patch substantially improves that situation, providing roughly
2X speedup for such trivial expressions.

First, add infrastructure in the plancache to allow fast re-validation
of cached plans that contain no table access, and hence need no locks.
Teach plpgsql to use this infrastructure for expressions that it's
already deemed "simple" (which in particular will never contain table
references).

The fast path still requires checking that search_path hasn't changed,
so provide a fast path for OverrideSearchPathMatchesCurrent by
counting changes that have occurred to the active search path in the
current session.  This is simplistic but seems enough for now, seeing
that PushOverrideSearchPath is not used in any performance-critical
cases.

Second, manage the refcounts on simple expressions' cached plans using
a transaction-lifespan resource owner, so that we only need to take
and release an expression's refcount once per transaction not once per
expression evaluation.  The management of this resource owner exactly
parallels the existing management of plpgsql's simple-expression EState.

Add some regression tests covering this area, in particular verifying
that expression caching doesn't break semantics for search_path changes.

Patch by me, but it owes something to previous work by Amit Langote,
who recognized that getting rid of plancache-related overhead would
be a useful thing to do here.  Also thanks to Andres Freund for review.

Discussion: https://postgr.es/m/CAFj8pRDRVfLdAxsWeVLzCAbkLFZhW549K+67tpOc-faC8uH8zw@mail.gmail.com
2020-03-26 18:58:57 -04:00
..
Makefile Split all OBJS style lines in makefiles into one-line-per-entry style. 2019-11-05 14:41:07 -08:00
README Remove unnecessary PG_TRY overhead for CurrentResourceOwner changes. 2017-10-11 17:44:09 -04:00
resowner.c Improve performance of "simple expressions" in PL/pgSQL. 2020-03-26 18:58:57 -04:00

README

src/backend/utils/resowner/README

Notes About Resource Owners
===========================

ResourceOwner objects are a concept invented to simplify management of
query-related resources, such as buffer pins and table locks.  These
resources need to be tracked in a reliable way to ensure that they will
be released at query end, even if the query fails due to an error.
Rather than expecting the entire executor to have bulletproof data
structures, we localize the tracking of such resources into a single
module.

The design of the ResourceOwner API is modeled on our MemoryContext API,
which has proven very flexible and successful in preventing memory leaks.
In particular we allow ResourceOwners to have child ResourceOwner objects
so that there can be forests of the things; releasing a parent
ResourceOwner acts on all its direct and indirect children as well.

(It is tempting to consider unifying ResourceOwners and MemoryContexts
into a single object type, but their usage patterns are sufficiently
different that this is probably not really a helpful thing to do.)

We create a ResourceOwner for each transaction or subtransaction as
well as one for each Portal.  During execution of a Portal, the global
variable CurrentResourceOwner points to the Portal's ResourceOwner.
This causes operations such as ReadBuffer and LockAcquire to record
ownership of the acquired resources in that ResourceOwner object.

When a Portal is closed, any remaining resources (typically only locks)
become the responsibility of the current transaction.  This is represented
by making the Portal's ResourceOwner a child of the current transaction's
ResourceOwner.  resowner.c automatically transfers the resources to the
parent object when releasing the child.  Similarly, subtransaction
ResourceOwners are children of their immediate parent.

We need transaction-related ResourceOwners as well as Portal-related ones
because transactions may initiate operations that require resources (such
as query parsing) when no associated Portal exists yet.


API Overview
------------

The basic operations on a ResourceOwner are:

* create a ResourceOwner

* associate or deassociate some resource with a ResourceOwner

* release a ResourceOwner's assets (free all owned resources, but not the
  owner object itself)

* delete a ResourceOwner (including child owner objects); all resources
  must have been released beforehand

Locks are handled specially because in non-error situations a lock should
be held until end of transaction, even if it was originally taken by a
subtransaction or portal.  Therefore, the "release" operation on a child
ResourceOwner transfers lock ownership to the parent instead of actually
releasing the lock, if isCommit is true.

Currently, ResourceOwners contain direct support for recording ownership of
buffer pins, lmgr locks, and catcache, relcache, plancache, tupdesc, and
snapshot references.  Other objects can be associated with a ResourceOwner by
recording the address of the owning ResourceOwner in such an object.  There is
an API for other modules to get control during ResourceOwner release, so that
they can scan their own data structures to find the objects that need to be
deleted.

Whenever we are inside a transaction, the global variable
CurrentResourceOwner shows which resource owner should be assigned
ownership of acquired resources.  Note however that CurrentResourceOwner
is NULL when not inside any transaction (or when inside a failed
transaction).  In this case it is not valid to acquire query-lifespan
resources.

When unpinning a buffer or releasing a lock or cache reference,
CurrentResourceOwner must point to the same resource owner that was current
when the buffer, lock, or cache reference was acquired.  It would be possible
to relax this restriction given additional bookkeeping effort, but at present
there seems no need.