Skip to content

Commit 679badd

Browse files
author
Rachel Heaton
authored
Add support for tablespaces (#870)
* Add support for tablespaces There is a new folder of tests, using volumes to keep data persistant against pod restarts and to allow for interaction within and without of the running containers. An additional Dockerfile has been added based off a local pg14 image. This adds a newly _destructive_ action removes the data within a tablespace directory. Perhaps this can be rebased off of the work that will do in-place resotre before merging, depending on the caution of the core team. Implementation note: this permits tablespace data directories to created at the top level of mounted volumes. Fixes #844 To run tests: `TEST=tablespaces make test` Allows for test-tablespaces to be run for all supported postgres versions `PGVERSION=14 TEST=tablespaces make test` * Run tablespace tests in travis for pg14
1 parent 93f9958 commit 679badd

37 files changed

Lines changed: 640 additions & 170 deletions

.travis.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ cache:
77
apt: true
88
directories:
99
- /home/travis/postgresql
10+
services:
11+
- docker
1012
matrix:
1113
fast_finish: true
1214
include:
@@ -30,6 +32,7 @@ matrix:
3032
- env: PGVERSION=12 TEST=ssl
3133
- env: PGVERSION=13 TEST=ssl
3234
- env: PGVERSION=14 TEST=ssl
35+
- env: PGVERSION=14 TEST=tablespaces DOCKERTEST=true
3336
- env: LINTING=true
3437
before_install:
3538
- git clone -b v0.7.18 --depth 1 https://github.com/citusdata/tools.git
@@ -60,6 +63,9 @@ script:
6063
- 'if [ -n "$LINTING" ]; then citus_indent --check; fi'
6164
- 'if [ -n "$LINTING" ]; then black --check .; fi'
6265
- 'if [ -n "$LINTING" ]; then ci/banned.h.sh; fi'
63-
- 'if [ -z "$LINTING" ]; then make -j5 CFLAGS=-Werror; fi'
64-
- 'if [ -z "$LINTING" ]; then sudo make install; fi'
65-
- 'if [ -z "$LINTING" ]; then PATH=`pg_config --bindir`:$PATH make test; fi'
66+
- 'if [ -z "$LINTING"] && [ -z "$DOCKERTEST" ]; then make -j5 CFLAGS=-Werror; fi'
67+
- 'if [ -z "$LINTING"] && [ -z "$DOCKERTEST" ]; then sudo make install; fi'
68+
- 'if [ -z "$LINTING"] && [ -z "$DOCKERTEST" ]; then PATH=`pg_config --bindir`:$PATH make test; fi'
69+
- 'if [ -n "$LINTING"] && [ -n "$DOCKERTEST" ]; then make test; fi'
70+
after_script:
71+
- 'if [ -n "$LINTING"] && [ -n "$DOCKERTEST" ]; then make -C tests/tablespaces teardown; fi'

CONTRIBUTING.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,41 @@ make TEST=single run-test # runs tests _not_ matching tests/test_multi*
8080
make TEST=test_auth run-test # runs tests/test_auth.py
8181
```
8282

83+
#### Running tablespace tests
84+
85+
The tablespace tests are similarly written using Python and the nose framework,
86+
with as much shared code as possible. They run using
87+
[docker compose](https://docs.docker.com/compose/), as postgres assumes that
88+
tablespaces live in the same location across replicas. This necessitates
89+
matching directory structures across the nodes, and thus, multiple,
90+
simultaneously running containers.
91+
92+
Interaction with each node is done using `docker-compose` commands. Refer to
93+
the [Makefile](tests/tablespaces/Makefile) in the test directory for examples.
94+
95+
To run the tests from the top-level directory:
96+
97+
```bash
98+
TEST=tablespaces make test
99+
```
100+
101+
Like the other tests, you can use `PGVERSION` to test against supported versions
102+
of postgres, for example:
103+
104+
```bash
105+
PGVERSION=14 TEST=tablespaces make test
106+
```
107+
108+
If the tests fail, the docker containers may be left around, and there is a
109+
companion teardown target:
110+
111+
```bash
112+
make -C tests/tablespaces teardown
113+
```
114+
115+
Refer to the [Makefile](tests/tablespaces/Makefile) for more potentially
116+
useful targets to use while developing with tablespaces.
117+
83118
### Producing the documentation diagrams
84119

85120
The diagrams are TikZ sources, which means they're edited with your usual

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,19 @@ clean-bin:
132132
install-bin: bin
133133
$(MAKE) -C src/bin/ install
134134

135+
135136
test:
137+
ifeq ($(TEST),tablespaces)
138+
$(MAKE) -C tests/tablespaces run-test
139+
else
136140
sudo -E env "PATH=${PATH}" USER=$(shell whoami) \
137141
$(NOSETESTS) \
138142
--verbose \
139143
--nologcapture \
140144
--nocapture \
141145
--stop \
142146
${TEST_ARGUMENT}
147+
endif
143148

144149
indent:
145150
citus_indent

src/bin/pg_autoctl/pgctl.c

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ static bool pg_write_recovery_conf(const char *pgdata,
8383
ReplicationSource *replicationSource);
8484
static bool pg_write_standby_signal(const char *pgdata,
8585
ReplicationSource *replicationSource);
86-
86+
static bool ensure_empty_tablespace_dirs(const char *pgdata);
8787

8888
/*
8989
* Get pg_ctl --version output in pgSetup->pg_version.
@@ -1172,6 +1172,83 @@ prepare_guc_settings_from_pgsetup(const char *configFilePath,
11721172
}
11731173

11741174

1175+
bool
1176+
ensure_empty_tablespace_dirs(const char *pgdata)
1177+
{
1178+
char *dirName = "pg_tblspc";
1179+
struct dirent *dirEntry = NULL;
1180+
1181+
char pgTblspcFullPath[MAXPGPATH] = { 0 };
1182+
sformat(pgTblspcFullPath, MAXPGPATH, "%s/%s", pgdata, dirName);
1183+
1184+
if (!directory_exists(pgTblspcFullPath))
1185+
{
1186+
log_debug("Postgres dir pg_tblspc does not exist at \"%s\"",
1187+
pgTblspcFullPath);
1188+
return true;
1189+
}
1190+
1191+
1192+
/* open and scan through the Postgres tablespace directory */
1193+
DIR *tblspcDir = opendir(pgTblspcFullPath);
1194+
1195+
if (tblspcDir == NULL)
1196+
{
1197+
log_error("Failed to open Postgres tablespace directory \"%s\" at \"%s\"",
1198+
dirName, pgdata);
1199+
return false;
1200+
}
1201+
1202+
while ((dirEntry = readdir(tblspcDir)) != NULL)
1203+
{
1204+
char tblspcDataDirPath[MAXPGPATH] = { 0 };
1205+
1206+
/* skip non-symlinks, as all tablespace dirs are symlinks */
1207+
if (dirEntry->d_type == DT_UNKNOWN)
1208+
{
1209+
struct stat structStat;
1210+
char dirEntryFullPath[MAXPGPATH] = { 0 };
1211+
sformat(dirEntryFullPath, MAXPGPATH, "%s/%s", pgTblspcFullPath,
1212+
dirEntry->d_name);
1213+
if (lstat(dirEntryFullPath, &structStat) != 0)
1214+
{
1215+
log_error("Failed to get file information for \"%s/%s\": %m",
1216+
pgTblspcFullPath, dirEntry->d_name);
1217+
return false;
1218+
}
1219+
if (!S_ISLNK(structStat.st_mode))
1220+
{
1221+
log_debug("Non-symlink file found in tablespace directory: \"%s/%s\"",
1222+
pgTblspcFullPath, dirEntry->d_name);
1223+
continue;
1224+
}
1225+
}
1226+
else if (dirEntry->d_type != DT_LNK)
1227+
{
1228+
log_debug("Non-symlink file found in tablespace directory: \"%s/%s\"",
1229+
pgTblspcFullPath, dirEntry->d_name);
1230+
continue;
1231+
}
1232+
1233+
join_path_components(tblspcDataDirPath, pgTblspcFullPath, dirEntry->d_name);
1234+
1235+
log_debug("Removing contents of tablespace data directory \"%s\"",
1236+
tblspcDataDirPath);
1237+
1238+
/* remove contents of tablespace data directory */
1239+
if (!rmtree(tblspcDataDirPath, false))
1240+
{
1241+
log_error(
1242+
"Failed to remove contents of existing tablespace data directory \"%s\": %m",
1243+
tblspcDataDirPath);
1244+
return false;
1245+
}
1246+
}
1247+
1248+
return true;
1249+
}
1250+
1251+
11751252
/*
11761253
* Call pg_basebackup, using a temporary directory for the duration of the data
11771254
* transfer.
@@ -1199,6 +1276,12 @@ pg_basebackup(const char *pgdata,
11991276
return false;
12001277
}
12011278

1279+
if (!ensure_empty_tablespace_dirs(pgdata))
1280+
{
1281+
/* errors have already been logged. */
1282+
return false;
1283+
}
1284+
12021285
/* call pg_basebackup */
12031286
path_in_same_directory(pg_ctl, "pg_basebackup", pg_basebackup);
12041287

tests/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Initialize the tests package
2+
# https://docs.python.org/3/tutorial/modules.html#packages

0 commit comments

Comments
 (0)