Thread: BackgroundWorkerInitializeConnection(NULL, ...) doesn't work
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.
FATAL: database 0 does not exist
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
Andrew Tipton
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
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
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
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 autovacuumI'm pretty sure InitPostgres skips a bunch of stuff if
> 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.
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
Andrew Tipton