Обсуждение: BackgroundWorkerInitializeConnection(NULL, ...) doesn't work

Поиск
Список
Период
Сортировка

BackgroundWorkerInitializeConnection(NULL, ...) doesn't work

От
Andrew Tipton
Дата:
The documentation for 9.4 says, in the "Background Worker Processes" section:

Once running, the process can connect to a database by calling BackgroundWorkerInitializeConnection(char *dbname, char *username). This allows the process to run transactions and queries using the SPI interface. If dbname is NULL, the session is not connected to any particular database, but shared catalogs can be accessed. If username is NULL, the process will run as the superuser created during initdb.

However, should one attempt to pass NULL for the dbname parameter, the process will die with:

FATAL: database 0 does not exist

BackgroundWorkerInitializeConnection() is essentially just a wrapper around InitPostgres(), passing it the supplied dbname and username.  (And passing InvalidOid for the dboid parameter.)  When InitPostgres() finds that dbname is null, it falls back on dboid.  GetDatabaseTupleByOid() returns NULL when given InvalidOid, resulting in the aforementioned elog(FATAL).

Based on my quick read through InitPostgres() and postinit.c, it's not even clear that there's a way to access the shared catalogs without connecting to a specific database.  Certainly the rest of the code in InitPostgres expects MyDatabaseId to be set to something useful.


Regards,
Andrew Tipton

Re: BackgroundWorkerInitializeConnection(NULL, ...) doesn't work

От
Alvaro Herrera
Дата:
Andrew Tipton wrote:

> However, should one attempt to pass NULL for the dbname parameter, the
> process will die with:
> 
> FATAL: database 0 does not exist
> 
> BackgroundWorkerInitializeConnection() is essentially just a wrapper around
> InitPostgres(), passing it the supplied dbname and username.  (And passing
> InvalidOid for the dboid parameter.)  When InitPostgres() finds that dbname
> is null, it falls back on dboid.  GetDatabaseTupleByOid() returns NULL when
> given InvalidOid, resulting in the aforementioned elog(FATAL).

Hmm, the intention is that this code path mimics what the autovacuum
launcher does to establish its connection.  It did work at some point;
maybe I broke this before commit.  I will give it a look next week.

-- 
Álvaro Herrera                http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services



Re: BackgroundWorkerInitializeConnection(NULL, ...) doesn't work

От
Tom Lane
Дата:
Andrew Tipton <andrew@kiwidrew.com> writes:
> The documentation for 9.4 says, in the "Background Worker Processes"
> section:
> Once running, the process can connect to a database by calling
> BackgroundWorkerInitializeConnection(char *dbname, char *username). This
> allows the process to run transactions and queries using the SPI interface.
> If dbname is NULL, the session is not connected to any particular database,
> but shared catalogs can be accessed.

> Based on my quick read through InitPostgres() and postinit.c, it's not even
> clear that there's a way to access the shared catalogs without connecting
> to a specific database.

There is not, because you need e.g. pg_class and pg_attribute to be
available in order to open any relation whatsoever.  So this documentation
is just wrong.  A bg worker that chooses not to connect to a database
is shutting itself out of access to all relations.

There's been occasional talk of trying to refactor system catalogs into
separate shared and local components.  The main motivation for that was
to reduce the bloat from having many copies of pg_proc etc, but it could
conceivably also make it practical for processes to run with only a
view of the shared catalogs.  The work required seems far out of
proportion to these benefits, unfortunately ...
        regards, tom lane



Re: BackgroundWorkerInitializeConnection(NULL, ...) doesn't work

От
Tom Lane
Дата:
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
> Andrew Tipton wrote:
>> However, should one attempt to pass NULL for the dbname parameter, the
>> process will die with:
>> FATAL: database 0 does not exist

> Hmm, the intention is that this code path mimics what the autovacuum
> launcher does to establish its connection.  It did work at some point;
> maybe I broke this before commit.  I will give it a look next week.

I'm pretty sure InitPostgres skips a bunch of stuff if
IsAutoVacuumLauncherProcess().  If you just want to make an environment
equivalent to that process's, maybe those tests should be replaced with
"if (dbname == NULL)".  But the claim that you have access to shared
catalogs in this state is still wrong.
        regards, tom lane



Re: BackgroundWorkerInitializeConnection(NULL, ...) doesn't work

От
Andrew Tipton
Дата:
On Sat, Aug 10, 2013 at 10:40 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
> Hmm, the intention is that this code path mimics what the autovacuum
> launcher does to establish its connection.  It did work at some point;
> maybe I broke this before commit.  I will give it a look next week.

I'm pretty sure InitPostgres skips a bunch of stuff if
IsAutoVacuumLauncherProcess().  If you just want to make an environment
equivalent to that process's, maybe those tests should be replaced with
"if (dbname == NULL)".  But the claim that you have access to shared
catalogs in this state is still wrong.

I've written up a quick proof-of-concept that splits InitPostgres(dbname, username) into two phases;  InitPostgresPhase1() is equivalent to what was set up prior to the autovacuum launcher bailing out, while InitPostgresPhase2(dbname, username) contains all of the authentication and database selection logic.

After calling InitPostgresPhase1(), certain accesses to shared catalogs *do* work.  For example, ClientAuthentication() searches the AUTHNAME syscache.  Later, a call to InitPostgresPhase2() with the dbname and username brings things to a state where normal SPI can be used.  This behaviour would be quite useful for certain classes of bgworker.

Documentation-wise, it would be helpful to specify precisely what is/isn't allowed in this "shared catalogs only" mode.

See the attached patch -- which is just a proof-of-concept -- for the details.


Regards,
Andrew Tipton
Вложения