-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Eliminate core/vendor/site directory configs
Just go back to a default, and let the search path do all the work. The `pg_config` option is `--extdir` and the special string to include in `extension_search_path` is named `$extdir`. Also: * Add context around Peter E's new patch * Mention the CNPG desire for read-only extension images in the "Challenges" section (renamed from "The Problem") * Remove `LINKBINS` and instead allow individual install locations to be customized by passing `datadir`, `bindir`, etc. to `make install`. * Fix the treatment of `MODULE_PATHNAME` to ignore the `$libdir` prefix. Restore the corresponding `module_pathname` control file variable with the preference to omit `$libdir`.
- Loading branch information
Showing
1 changed file
with
118 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ file organization and a search path [GUC] for finding extensions. The | |
inspired this proposal. These threads cover quite a lot of territory, so I | ||
thought it would be useful to pull together a more unified, public proposal. | ||
|
||
## The Problem | ||
## Challenges | ||
|
||
A number of challenges face extension users in various configurations, thanks | ||
to extension file organization in the Postgres core. The common thread among | ||
|
@@ -29,9 +29,9 @@ itself. | |
|
||
On Debian systems, the user account that creates extension packages lacks | ||
permission to add files to Postgres install. But testing extensions requires | ||
installing the extension files where Postgres can find them. Furthermore, | ||
extensions should ideally be built against a clean Postgres install; adding an | ||
extension in order to run `make installcheck` would pollute it. | ||
installing extension files where Postgres can find them. Moreover, extensions | ||
ideally build against a clean Postgres install; adding an extension in order | ||
to run `make installcheck` would pollute it. | ||
|
||
[Christoph's patch][destdir] solves these problems by adding a second lookup | ||
path for extensions and dynamic modules, so that Postgres can load them | ||
|
@@ -44,6 +44,19 @@ the patch will search in `/tmp/build/myext/opt/share`. This approach works for | |
the packaging use case, which explicitly uses full paths with a prefix, but | ||
would be weird for other use cases. | ||
|
||
Peter Eisentraut proposed a [new patch] with a new `GUC`, | ||
`extension_control_path`, that provides a more typical search path pattern to | ||
find extension control files, but doesn't account for shared modules that ship | ||
with an extension, requiring that they still live in the | ||
[`dynamic_library_path`]. Installing into custom directories requires the | ||
`datadir` and `pkglibdir` variables: | ||
|
||
``` sh | ||
make install datadir=/else/where/share pkglibdir=/else/where/lib | ||
``` | ||
|
||
This pattern can probably be simplified. | ||
|
||
### OCI Immutability | ||
|
||
[OCI] (née Docker) images are immutable, while a container running an image | ||
|
@@ -62,25 +75,39 @@ deployment configuration complexity. It would be preferable to have all the | |
files for an extension in one place, rather than scattered across multiple | ||
persistent volumes. | ||
|
||
Peter Eisentraut's [new patch] addresses much of this issue by adding a search | ||
path for extension control files and related data/share files (generally SQL | ||
files). One can create a single volume with a `lib` directory for shared | ||
modules and `share/extension` directory for control and data/share files. | ||
|
||
However, an additional wrinkle is the ambition from the [CloutNativePg][CNPG] | ||
([CNPG]) community to eliminate the need for a persistent volume, and rely | ||
instead on mounting images that each contain all the files for a single | ||
extension as their own volumes (perhaps using [Kubernetes image volume | ||
feature], (currently in alpha)). | ||
|
||
### Postgres.app Immutability | ||
|
||
The macOS [Postgres.app] supports extensions. But installing one into | ||
`SHAREDIR/extensions` changes the contents of the Postgres.app bundle, | ||
breaking Apple-required signature validation. The OS will no longer be able to | ||
validate that the app is legit and refuse to start it. | ||
|
||
Peter Eisentraut's [new patch] addresses this issue as well, with all the same | ||
caveats as for the [packager testing](#packager-testing) challenges. | ||
|
||
## Solution | ||
|
||
To address these issues, this RFC proposes to change file organization and | ||
lookup patterns for PostgreSQL extensions. | ||
To further address these issues, this RFC proposes to change file organization | ||
and lookup patterns for PostgreSQL extensions. | ||
|
||
### Extension Directories | ||
|
||
First, when an extension is installed, all of its files will live in a single | ||
directory named for the extension. The contents include: | ||
First, when an extension is installed, by default all of its files will live | ||
in a single directory named for the extension. The contents include: | ||
|
||
* The Control file that describes extension | ||
* Subdirectories for SQL, shared modules, docs, binaries | ||
* Subdirectories for SQL, shared modules, docs, binaries, etc. | ||
|
||
Subdirectories roughly correspond to the `pg_config --*dir` options: | ||
|
||
|
@@ -96,42 +123,33 @@ This layout reduces the cognitive overhead for understanding what files belong | |
to what extension. Want to know what's included in the `widget` extension? | ||
Everything is in the `widget` directory. | ||
|
||
### Configuration Parameters | ||
### Configuration Parameter | ||
|
||
Add three new `pg_config` values: | ||
Add a new `pg_config` value: | ||
|
||
``` | ||
--extdir-core show location of core extensions | ||
--extdir-vendor show location of vendor extensions | ||
--extdir-site show location of site extensions | ||
--extdir show location of extensions | ||
``` | ||
|
||
All core-distributed extensions, including contrib extensions, will be | ||
installed in the `--extdir-core` directory, each in its own directory as | ||
described [above](#extension-directories). Its contents would look something | ||
like this: | ||
This is the directory into which extensions will by default be installed. Its | ||
default value would be `$(pg_config --sharedir)/extension`, but could be set | ||
at compile time like other configuration parameters. Its contents consist of | ||
subdirectories that each contain an extension, as described in [Extension | ||
Directories](#extension-directories). With a few extensions installed, it | ||
would look something like: | ||
|
||
``` console | ||
❯ ls -1 "$(pg_config --extdir-core)" | ||
❯ ls -1 "$(pg_config --extdir)" | ||
auto_explain | ||
bloom | ||
intagg | ||
isn | ||
pair | ||
plperl | ||
plpgsql | ||
plv8 | ||
xml2 | ||
``` | ||
|
||
OS vendor and packaging systems would install non-core extensions into | ||
`--extdir-vendor`, while user-installed extensions will be put into | ||
`--extdir-site`. | ||
|
||
Like all other `pg_config` options, these values can be customized at compile | ||
time. By default, they'll point to different directories, so that core, | ||
vendor, and end-user extensions are always kept separate. Perhaps default to: | ||
|
||
``` | ||
PG_INSTALL_ROOT/extensions/(core|site|vendor) | ||
semver | ||
vector | ||
``` | ||
|
||
### Extension Path | ||
|
@@ -141,13 +159,12 @@ Add an extension lookup path GUC akin to [`dynamic_library_path`], called | |
extensions and their files. The default value for this GUC will be: | ||
|
||
``` ini | ||
extension_path = '$extdir_site,$extdir_vendor,$extdir_core' | ||
extension_path = '$extdir' | ||
``` | ||
|
||
The special values `$extdir_site`, `$extdir_vendor`, and `$extdir_core` | ||
correspond to the `pg_config` options `--extdir-site`, `--extdir-vendor`, and | ||
`--extdir-core`, respectively, and function exactly as `$libdir` does for the | ||
`dynamic_library_path` GUC, substituting the appropriate values. | ||
The special string `$extdir` corresponds to the `pg_config` option of the same | ||
name, and function exactly as `$libdir` does for the `dynamic_library_path` | ||
GUC, substituting the appropriate values. | ||
|
||
### Lookup Execution | ||
|
||
|
@@ -170,10 +187,9 @@ appropriate subdirectories, e.g.: | |
### PGXS | ||
|
||
Update the extension installation behavior of [PGXS] to install extension | ||
files into the new locations. A new variable, `EXTDIR`, will define the | ||
directory into which to install an extension, and will default to | ||
`--extdir-site`. It can be set to the values `$extdir_site`, `$extdir_vendor`, | ||
or `$extdir_core`, or to any literal path. | ||
files into the new locations by default. A new variable, `EXTDIR`, will define | ||
the directory into which to install an extension, and default to | ||
`$(pg_config --extdir)`. It can be set to any literal path. | ||
|
||
The `$EXTENSION` variable will be changed to allow only one extension name. If | ||
it's set, the installation behavior will be changed for the following | ||
|
@@ -190,37 +206,40 @@ variables: | |
* `PROGRAM`, `SCRIPTS` and `SCRIPTS_built`: Installed into | ||
`$EXTDIR/$EXTENSION/bin` | ||
|
||
Another new variable, `LINKBINS`, will default to true and symlink | ||
`$EXTDIR/$EXTENSION/bin` files in `pg_config --bindir`. Installers can set it | ||
to false to skip the symlinking, e.g., for immutable Postgres installs. | ||
Each of these locations can still be overridden by setting one of the | ||
(currently undocumented) [installation location options]. | ||
|
||
> [!NOTE] External projects that install extensions without using PGXS, like | ||
> [pgrx], must also be updated to either follow the same pattern or to | ||
> delegate installation to [PGXS]. | ||
### MODULE_PATHNAME | ||
|
||
Update the installer to replace `MODULE_PATHNAME` in SQL scripts with the new | ||
install path for shared modules, `$EXTDIR/$EXTENSION/lib`. | ||
Change the behavior of the `MODULE_PATHNAME` string in extension SQL files to | ||
ignore `$libdir` and instead assume named modules are found in the `lib` | ||
subdirectory of the extension's directory. | ||
|
||
### Control File | ||
|
||
The `directory` and `module_pathname` control file variables will be | ||
deprecated and ignored. | ||
The `directory` control file variable will be deprecated and ignored. | ||
|
||
The `module_pathname` variable should only name a shared module in the `lib` | ||
subdirectory of an extension directory. Any existing use of a `$libdir` prefix | ||
will be stripped out and ignored. | ||
|
||
## Use Cases | ||
|
||
Here’s how the proposed file layout and `extension_path` GUC address the [use | ||
cases](#the-problem) that inspired this RFC. | ||
cases](#challenges) that inspired this RFC. | ||
|
||
### Packager Testing | ||
|
||
A packager who wants to run tests without modifying a PostgreSQL install would | ||
follow these steps: | ||
|
||
* Set the `extension_path` GUC to search the site extension directory under | ||
* Set the `extension_path` GUC to search a directory under | ||
the packaging install. Something like | ||
`$RPM_BUILD_ROOT/$(pg_config --extdir-vendor)` | ||
`$RPM_BUILD_ROOT/$(pg_config --extdir)` | ||
* Install the extension into that directory: | ||
`make install EXTDIR=$RPM_BUILD_ROOT` | ||
* Run `make installcheck` | ||
|
@@ -234,35 +253,45 @@ The Postgres installation will not have been modified; only the | |
To allow extensions to be added to a OCI container and to persist beyond its | ||
lifetime, one or more [volumes] could be used. A couple of options: | ||
|
||
* Mount the `--extdir-site` and/or `--extdir-vendor` directories as | ||
persistent volumes (or one volume and a subdirectory for each). Then any | ||
extensions installed into them will persist. Files for any one extension | ||
will live on a single volume. If a new container spins up, as long as it | ||
uses the same persistent volume(s), can access the same extensions. | ||
|
||
* Create separate images for each extension, and then "install" them by | ||
using the [Kubernetes image volume feature] (currently in alpha) to mount | ||
them as read-only volumes in the appropriate subdirectory of | ||
`--extdir-site` or `--extdir-vendor`. Thereafter, any new containers would | ||
simply have to mount all the same extension image volumes persistently | ||
provide the same extensions to all containers. | ||
* Mount the a persistent volume for extensions and append the path to that | ||
directory to the `extension_search_path` GUC. Then Postgres can find any | ||
extensions installed there, and they will persist. Files for all | ||
extensions extension will live on a single volume. Or, to meet a desire to | ||
keep some extensions separate (e.g., to keep open-source and | ||
company-internal extensions separate), two or more persistent volumes | ||
could be mounted, as long as they're all included in | ||
`extension_search_path` and users take care to install extensions in the | ||
proper locations. | ||
|
||
* To meet the [CNPG] ambition, create separate images for each extension, | ||
and then "install" them by using the [Kubernetes image volume feature] | ||
(currently in alpha) to mount them as read-only volumes in the appropriate | ||
subdirectory of `--extdir`. Thereafter, any new containers would simply | ||
have to mount all the same extension image volumes persistently provide | ||
the same extensions to all containers. | ||
|
||
### Postgres.app | ||
|
||
To allow extension installation without invalidating the Postgres.app bundle's | ||
signature, the app could be compiled to have `--extdir-site` and | ||
`--extdir-vendor` point to subdirectories well-known directories outside the | ||
app bundle, such as `/Library/Application Support/Postgres`. | ||
To allow extension installation without invalidating the Postgres.app bundle | ||
signature, the default configuration would specify, in addition to `$extdir`, | ||
a well-known directories outside the app bundle, such as | ||
`/Library/Application Support/Postgres`. Users wishing to install new | ||
extensions would then need to point the `EXTDIR` parameter to that location, | ||
e.g., | ||
|
||
```console | ||
$ make install EXTDIR="/Library/Application Support/Postgres"` | ||
``` | ||
|
||
Any vendor or user extensions installed would be placed in those | ||
subdirectories, without changing the contents of the Postgres.app bundle. | ||
Postgres.app would know to find extensions in that location thanks to the | ||
inclusion of `$extdir_site` in the `extension_path` GUC. | ||
Or the app could get even trickier, setting the `--extdir` value to that | ||
location so that users don't need to use `EXTDIR`. As long as | ||
`extension_search_path` includes both the bundle's extension directory and | ||
this external directory, Postgres will be able to find and load extensions. | ||
|
||
## Extension Directory Examples | ||
|
||
A core extension, like [citext], would live in | ||
`$(pg_config --extdir-core)/citext`, and have a structure such as: | ||
A core extension, like [citext], would live in `$(pg_config --extdir)/citext`, | ||
and have a structure such as: | ||
|
||
``` tree | ||
citext | ||
|
@@ -364,8 +393,8 @@ example: | |
shared_preload_libraries = '$extension_path:pg_partman_bgw' | ||
``` | ||
|
||
But this overloads the semantics of `shared_preload_libraries` and friends | ||
rather heavily, not to mention the [`LOAD`] command. | ||
But this overloads the semantics of `shared_preload_libraries` and the code | ||
that processes it rather heavily, not to mention the [`LOAD`] command. | ||
|
||
Therefore, as a follow up to the [solution](#solution) proposed above, this | ||
RFC proposes additional changes to PostgreSQL. | ||
|
@@ -413,7 +442,7 @@ upgrade. | |
For a future change, consider modifying `CREATE EXTENSION` to support shared | ||
module-only extensions. This would allow extensions with no SQL component, | ||
such as `auto_explain` to be handled like any other extension; it would live | ||
in `--extdir-core` with a directory structure like this: | ||
in `--extdir` with a directory structure like this: | ||
|
||
``` tree | ||
auto_explain | ||
|
@@ -426,18 +455,23 @@ auto_explain | |
└── auto_explain.index.bc | ||
``` | ||
|
||
Note the `auto_explain.control` file. We would need to add a variable to | ||
indicate that the extension includes no SQL files, so `CREATE EXTENSION` and | ||
related commands wouldn't try to find them. | ||
Note the `auto_explain.control` file. We would need to add a new control file | ||
parameter to indicate that the extension includes no SQL files, so | ||
`CREATE EXTENSION` and related commands wouldn't try to find them. | ||
|
||
With these changes, extensions could become the primary, recommended interface | ||
for extending PostgreSQL. Perhaps the `LOAD` command could be deprecated, and | ||
the `*_preload_libraries` GUCs along with it. | ||
|
||
## Compatibility Issues | ||
|
||
* The `directory` and `module_pathname` control file variables and the | ||
`MODULEDIR` PGXS variable would be deprecated and ignored. | ||
* The behavior of the `MODULE_PATHNAME` string in SQL files would be changed | ||
to ignore a `$libdir` prefix and instead be read as a shared library name | ||
to find in `lib` subdirectory of the extension directory. | ||
* The `module_pathname` control file variable would prefer the name of a | ||
shared module, as `$libdir` would be ignored. | ||
* The `directory` control file variable and the `MODULEDIR` PGXS variable | ||
would be deprecated and ignored. | ||
* `*_preload_libraries` would no longer be used to find extension modules | ||
without full paths. Administrators would have to remove module names from | ||
these GUCs and add the relevant extension names to the | ||
|
@@ -470,6 +504,7 @@ This RFC does not include or attempt to address the following issues: | |
[discussion]: https://postgr.es/m/[email protected] | ||
[Christoph Berg]: https://www.df7cb.de | ||
[destdir]: https://commitfest.postgresql.org/50/4913/ | ||
[new patch]: https://postgr.es/m/[email protected] | ||
[OCI]: https://opencontainers.org "Open Container Initiative" | ||
[symlink magic]: https://speakerdeck.com/ongres/postgres-extensions-in-kubernetes?slide=14 | ||
"Postgres Extensions in Kubernetes: StackGres" | ||
|
@@ -495,4 +530,5 @@ This RFC does not include or attempt to address the following issues: | |
"PostgreSQL Docs: LOAD" | ||
[auto_explain]: https://www.postgresql.org/docs/current/auto-explain.html | ||
"PostgreSQL Docs: auto_explain— log execution plans of slow queries" | ||
|
||
[installation location options]: https://github.com/postgres/postgres/blob/master/src/Makefile.global.in#L82-L90 | ||
[CNPG]: https://cloudnative-pg.io "CloudNativePG — PostgreSQL Operator for Kubernetes" |