Skip to content

Commit 861ddd3

Browse files
committed
check that user uses tablespace_mapping
1 parent 2e3adf1 commit 861ddd3

File tree

2 files changed

+89
-6
lines changed

2 files changed

+89
-6
lines changed

src/catchup.c

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
static PGconn *catchup_collect_info(PGNodeInfo *source_node_info, const char *source_pgdata, const char *dest_pgdata);
3030
static void catchup_preflight_checks(PGNodeInfo *source_node_info, PGconn *source_conn, const char *source_pgdata,
3131
const char *dest_pgdata);
32+
static void check_tablespaces_existance_in_tbsmapping(PGconn *conn);
3233
static void do_catchup_instance(const char *source_pgdata, const char *dest_pgdata, PGconn *source_conn,
3334
PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs);
3435
static void *catchup_thread_runner(void *arg);
@@ -126,18 +127,18 @@ catchup_preflight_checks(PGNodeInfo *source_node_info, PGconn *source_conn,
126127
* kulaginm -- I think this is a harmful feature. If user requested an incremental catchup, then
127128
* he expects that this will be done quickly and efficiently. If, for example, he made a mistake
128129
* with dest_dir, then he will receive a second full copy instead of an error message, and I think
129-
* that in some cases he would prefer the error.
130+
* that in some cases he would prefer the error.
130131
* I propose in future versions to offer a backup_mode auto, in which we will look to the dest_dir
131132
* and decide which of the modes will be the most effective.
132133
* I.e.:
133134
* if(requested_backup_mode == BACKUP_MODE_DIFF_AUTO)
134135
* {
135136
* if(dest_pgdata_is_empty)
136137
* backup_mode = BACKUP_MODE_FULL;
137-
* else
138-
* if(ptrack supported and applicable)
138+
* else
139+
* if(ptrack supported and applicable)
139140
* backup_mode = BACKUP_MODE_DIFF_PTRACK;
140-
* else
141+
* else
141142
* backup_mode = BACKUP_MODE_DIFF_DELTA;
142143
* }
143144
*/
@@ -179,8 +180,48 @@ catchup_preflight_checks(PGNodeInfo *source_node_info, PGconn *source_conn,
179180
if (current.from_replica && exclusive_backup)
180181
elog(ERROR, "Catchup from standby is available only for PG >= 9.6");
181182

182-
//REVIEW FIXME Let's fix it before release. This one seems like a potential bug.
183-
// TODO check if it is local catchup and source contain tablespaces
183+
if (!fio_is_remote(FIO_DB_HOST))
184+
check_tablespaces_existance_in_tbsmapping(source_conn);
185+
}
186+
187+
/*
188+
* Check that all tablespaces exists in tablespace mapping (--tablespace-mapping option)
189+
* Emit fatal error if that tablespace found
190+
*/
191+
static void
192+
check_tablespaces_existance_in_tbsmapping(PGconn *conn)
193+
{
194+
PGresult *res;
195+
int i;
196+
char *tablespace_path = NULL;
197+
const char *linked_path = NULL;
198+
char *query = "SELECT pg_catalog.pg_tablespace_location(oid) "
199+
"FROM pg_catalog.pg_tablespace "
200+
"WHERE pg_catalog.pg_tablespace_location(oid) <> '';";
201+
202+
res = pgut_execute(conn, query, 0, NULL);
203+
204+
if (!res)
205+
elog(ERROR, "Failed to get list of tablespaces");
206+
207+
for (i = 0; i < res->ntups; i++)
208+
{
209+
tablespace_path = PQgetvalue(res, i, 0);
210+
Assert (strlen(tablespace_path) > 0);
211+
212+
canonicalize_path(tablespace_path);
213+
linked_path = leaked_abstraction_get_tablespace_mapping(tablespace_path);
214+
215+
if (strcmp(tablespace_path, linked_path) == 0)
216+
/* same result -> not found in mapping */
217+
elog(ERROR, "Local catchup executed, but source database contains "
218+
"tablespace (\"%s\"), that are not listed in the map", tablespace_path);
219+
220+
if (!is_absolute_path(linked_path))
221+
elog(ERROR, "Tablespace directory path must be an absolute path: %s\n",
222+
linked_path);
223+
}
224+
PQclear(res);
184225
}
185226

186227
/*

tests/catchup.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,3 +381,45 @@ def test_tablefile_truncation(self):
381381
# Clean after yourself
382382
source_pg.stop()
383383
self.del_test_dir(module_name, fname)
384+
385+
# @unittest.skip("skip")
386+
def test_local_tablespace_without_mapping(self):
387+
fname = self.id().split('.')[3]
388+
389+
source_pg = self.make_simple_node(
390+
base_dir = os.path.join(module_name, fname, 'src'),
391+
initdb_params = ['--data-checksums'])
392+
source_pg.slow_start()
393+
394+
tblspace_path = self.get_tblspace_path(source_pg, 'tblspace')
395+
self.create_tblspace_in_node(
396+
source_pg, 'tblspace',
397+
tblspc_path = tblspace_path)
398+
399+
source_pg.safe_psql(
400+
"postgres",
401+
"CREATE TABLE ultimate_question TABLESPACE tblspace AS SELECT 42 AS answer")
402+
403+
dest_pg = self.make_empty_node(os.path.join(module_name, fname, 'dst'))
404+
try:
405+
dest_pg = self.catchup_node(
406+
backup_mode = 'FULL',
407+
source_pgdata = source_pg.data_dir,
408+
destination_node = dest_pg,
409+
options = [
410+
'-d', 'postgres',
411+
'-p', str(source_pg.port),
412+
'--stream',
413+
]
414+
)
415+
self.assertEqual(1, 0, "Expecting Error because '-T' parameter is not specified.\n Output: {0} \n CMD: {1}".format(
416+
repr(self.output), self.cmd))
417+
except ProbackupException as e:
418+
self.assertIn(
419+
'ERROR: Local catchup executed, but source database contains tablespace',
420+
e.message,
421+
'\n Unexpected Error Message: {0}\n CMD: {1}'.format(repr(e.message), self.cmd))
422+
423+
source_pg.stop()
424+
# Clean after yourself
425+
self.del_test_dir(module_name, fname)

0 commit comments

Comments
 (0)