Skip to content

Commit fbfa1d2

Browse files
authored
Merge pull request #23 from mbakli/feature_upgrade
Feature upgrade: auto-clean catalog & bug fixes
2 parents 3a0781f + 3b80b0f commit fbfa1d2

30 files changed

Lines changed: 811 additions & 234 deletions

CMakeLists.txt

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -59,42 +59,28 @@ find_program(POSTGRESQL_EXECUTABLE NAMES postgres
5959
)
6060

6161

62-
find_path(PostgreSQL_TYPE_INCLUDE_DIR
63-
NAMES catalog/pg_type.h
64-
PATHS
65-
# Look in other places.
66-
${PostgreSQL_ROOT_DIRECTORIES}
67-
PATH_SUFFIXES
68-
postgresql
69-
pgsql/server
70-
postgresql/server
71-
include/server
72-
# Help the user find it if we cannot.
73-
DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}"
74-
)
75-
76-
find_package(PostgreSQL)
62+
# Resolve include directories from the same pg_config used for --bindir above,
63+
# instead of find_package(PostgreSQL) (which only locates the client libpq
64+
# headers and can pick a different, unrelated PostgreSQL installation when
65+
# several major versions are installed side by side).
66+
execute_process(
67+
COMMAND ${POSTGRESQL_PG_CONFIG} --includedir-server
68+
OUTPUT_STRIP_TRAILING_WHITESPACE
69+
OUTPUT_VARIABLE PostgreSQL_SERVER_INCLUDE_DIR)
70+
execute_process(
71+
COMMAND ${POSTGRESQL_PG_CONFIG} --includedir
72+
OUTPUT_STRIP_TRAILING_WHITESPACE
73+
OUTPUT_VARIABLE PostgreSQL_INCLUDE_DIR)
7774

78-
if (PostgreSQL_INCLUDE_DIRS)
79-
message(STATUS "POSTGRES_INCLUDE_PATH ${PostgreSQL_INCLUDE_DIRS}")
80-
set (PostgreSQL_INCLUDE_DIRS /usr/local/pgsql/include)
81-
include_directories(SYSTEM ${PostgreSQL_INCLUDE_DIRS}/server)
82-
message(STATUS "POSTGRES_SERVER_PATH ${PostgreSQL_INCLUDE_DIRS}/server")
83-
else()
84-
set (PostgreSQL_INCLUDE_DIRS /usr/local/pgsql/include)
85-
message(STATUS "POSTGRES_INCLUDE_PATH ${PostgreSQL_INCLUDE_DIRS}")
86-
include_directories(SYSTEM ${PostgreSQL_INCLUDE_DIR}/server)
87-
message(STATUS "POSTGRES_SERVER_PATH ${PostgreSQL_INCLUDE_DIR}/server")
75+
if (NOT PostgreSQL_SERVER_INCLUDE_DIR)
76+
message(FATAL_ERROR "pg_config --includedir-server failed to return a value. Please check your PostgreSQL installation!")
8877
endif()
8978

90-
include_directories(SYSTEM ${PostgreSQL_INCLUDE_DIRS})
79+
message(STATUS "POSTGRES_INCLUDE_PATH ${PostgreSQL_INCLUDE_DIR}")
80+
message(STATUS "POSTGRES_SERVER_PATH ${PostgreSQL_SERVER_INCLUDE_DIR}")
81+
include_directories(SYSTEM ${PostgreSQL_SERVER_INCLUDE_DIR})
9182
include_directories(SYSTEM ${PostgreSQL_INCLUDE_DIR})
9283

93-
if (${PostgreSQL_VERSION_STRING} GREATER ${PG_MIN_MAJOR_VERSION})
94-
message(STATUS "PostgreSQL version: ${PostgreSQL_VERSION_STRING}")
95-
include_directories(SYSTEM ${PostgreSQL_INCLUDE_DIR}/${PG_MAX_MAJOR_VERSION}/server)
96-
endif()
97-
9884
#---------------------------------------------
9985
# library directory
10086
#---------------------------------------------
@@ -144,6 +130,13 @@ if(PROJ_INCLUDE_DIRS)
144130
message(STATUS "POSTGIS_PROJ_VERSION: ${POSTGIS_PROJ_VERSION}")
145131
endif()
146132

133+
# liblwgeom.h (used for GBOX) is PostGIS' own internal header and is not
134+
# shipped by any postgresql-*-postgis-3 package; it must be sourced from a
135+
# PostGIS/MobilityDB checkout. See README for how to place a copy under
136+
# /usr/local/include/postgis-lwgeom/liblwgeom (alongside its required
137+
# ../postgis_config.h).
138+
include_directories(SYSTEM /usr/local/include/postgis-lwgeom/liblwgeom)
139+
147140
#-------------------
148141
# add the MobilityDB link
149142
#-------------------
@@ -180,8 +173,12 @@ foreach (subdir ${DistMobilityDB_SOURCE_NAMES} )
180173
endforeach()
181174

182175

183-
set(POSTGRESQL_DYNLIB_DIR /usr/local/pgsql/lib)
184-
set(POSTGRESQL_SHARE_DIR /usr/local/pgsql/share)
176+
# Install into the actual pg_config-reported directories for this PostgreSQL
177+
# installation (LIBRARY_INSTALL_PATH/SHARE_DIR, computed above), rather than
178+
# an author-specific /usr/local/pgsql source-build layout. Note SHARE_DIR
179+
# already has "/extension" appended (see the extension-directory block above).
180+
set(POSTGRESQL_DYNLIB_DIR ${LIBRARY_INSTALL_PATH})
181+
set(POSTGRESQL_SHARE_DIR ${SHARE_DIR})
185182

186183
set(MOBILITYDB_LIB_NAME "${CMAKE_PROJECT_NAME}-1.0")
187184
add_library(${MOBILITYDB_LIB_NAME} MODULE ${PROJECT_OBJECTS})
@@ -196,4 +193,4 @@ add_custom_target(control ALL DEPENDS ${CMAKE_BINARY_DIR}/distributed_mobilitydb
196193
install(TARGETS ${MOBILITYDB_LIB_NAME} DESTINATION "${POSTGRESQL_DYNLIB_DIR}")
197194
install(FILES "${CMAKE_BINARY_DIR}/distributed_mobilitydb.control"
198195
"${CMAKE_BINARY_DIR}/${DISTRIBUTED_MOBILITYDB_EXTENSION_FILE}"
199-
DESTINATION "${POSTGRESQL_SHARE_DIR}/extension")
196+
DESTINATION "${POSTGRESQL_SHARE_DIR}")

include/catalog/nodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ extern Datum GetDBName();
2323
/* Coordinator/worker node info (host, port, role) for the local backend. */
2424
extern TaskNode *GetNodeInfo();
2525

26+
/* Node (host, port) actually hosting relationId's shard for rand_tile. */
27+
extern TaskNode *GetShardHostNode(Oid relationId, int rand_tile);
28+
2629
/* Table id of the tile assigned to a randomly-picked worker for relationId. */
2730
extern char* GetRandomTileId(Oid relationId, ExecTaskType taskType, int rand_tile);
2831

include/executor/tile_tasks.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ extern char *taskQuery (List *tasks, ExecTaskType taskType);
2626
/* Rebalances relid's data into numTiles tiles, materializing into reshuffledTable. */
2727
extern void RearrangeTiles(Oid relid, int numTiles, char *reshuffledTable);
2828

29-
/* Appends the tile-key projection for a distributed (spatiotemporal) relation to query_string. */
30-
extern Datum AddTilingKey(STMultirelationCatalog tblCatalog, Alias *alias , char * query_string);
29+
/* Appends the tile-key equi-join predicate between alias and otherAlias for a distributed (spatiotemporal) relation to query_string. */
30+
extern Datum AddTilingKey(STMultirelationCatalog tblCatalog, Alias *alias, Alias *otherAlias, char * query_string);
3131

3232
/* Appends the tile-key projection for a non-spatiotemporal (plain) rte to query_string. */
3333
extern Datum AddNonStRteTilingKey(Rte *tbl, Alias *alias ,char * query_string);

include/multirelation/multirelation_utils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ typedef struct STMultirelations
9292
int stCount;
9393
int nonStCount;
9494
int length;
95+
/* Count of nonStCount entries that are Citus reference tables -- these
96+
* are already replicated to every node, so they never need reshuffling
97+
* and shouldn't count as a "different distributed table" when deciding
98+
* whether a join needs the NonColocation strategy. */
99+
int refCount;
95100
} STMultirelations;
96101

97102
/* True if relationId is registered as a distributed spatiotemporal table. */

include/planner/distributed_mobilitydb_explain.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,9 @@ typedef struct SpatiotemporalScanState
5050
} SpatiotemporalScanState;
5151

5252

53-
/* A query paired with its (possibly rewritten) SQL text, for EXPLAIN output. */
53+
/* The (possibly rewritten) SQL text of the query being explained. */
5454
typedef struct DistributedQueryExplain
5555
{
56-
Query *query;
5756
char *query_string;
5857

5958
}DistributedQueryExplain;

include/planner/predicate_management.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,20 @@ extern bool IsDistanceOperation(Oid operationId);
7575
/* True if operationId is a registered intersection operator (e.g. eIntersects). */
7676
extern bool IsIntersectionOperation(Oid operationId);
7777

78-
/* Computes the query's search bounding box from tbls and the range/distance predicate opExpr. */
79-
extern Datum get_query_range(STMultirelations *tbls, OpExpr *opExpr);
78+
/*
79+
* Extracts the callable identifier and argument list from a WHERE-clause
80+
* predicate node, regardless of whether MobilityDB/PostGIS exposed it as an
81+
* infix operator (OpExpr, e.g. `&&`) or a plain function call (FuncExpr,
82+
* e.g. eDwithin(...), ST_Intersects(...)) -- both forms appear in practice
83+
* and pg_spatiotemporal_join_operations is keyed by either an operator or a
84+
* function oid. Returns false (leaving *oid/*args unset) for any other node
85+
* type.
86+
*/
87+
extern bool GetPredicateOidAndArgs(Node *clause, Oid *oid, List **args);
8088

81-
/* True if opExpr's search box spans enough tiles of tbls to warrant rebalancing first. */
82-
extern bool CheckTileRebalancerActivation(STMultirelations *tbls, OpExpr *opExpr, Datum box);
89+
/* Computes the query's search bounding box from tbls and the range/distance predicate clause. */
90+
extern Datum get_query_range(STMultirelations *tbls, Node *clause);
91+
92+
/* True if clause's search box spans enough tiles of tbls to warrant rebalancing first. */
93+
extern bool CheckTileRebalancerActivation(STMultirelations *tbls, Node *clause, Datum box);
8394
#endif /* PREDICATE_MANAGMENT_H */

include/utils/helper_functions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,10 @@ extern char *toLower(char *str);
3838

3939
/* True if val is a NULL/zero Datum (no value set). */
4040
extern bool IsDatumEmpty(Datum val);
41+
42+
/* Renders datum (of the given PostgreSQL type oid) as a palloc'd C string via its type's output function. */
43+
extern char *DatumToString(Datum datum, Oid typeoid);
44+
45+
/* Runs query via SPI, erroring out if its result status doesn't match expectedSpiOk (an SPI_OK_* constant). */
46+
extern void ExecuteQueryViaSPI(char *query, int expectedSpiOk);
4147
#endif /* HELPER_FUNCTIONS_H */

sql/helper_functions/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ SET(LOCAL_FILES
22
write_to_catalog.sql
33
colocation_utils.sql
44
catalog_info_check.sql
5+
catalog_cleanup.sql
56
)
67

78
foreach (f ${LOCAL_FILES})
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--------------------------------------------------------------------------------------------------------------------------------------------------------
2+
-- Catalog Cleanup
3+
--------------------------------------------------------------------------------------------------------------------------------------------------------
4+
-- Dropping a distributed spatiotemporal table (e.g. DROP TABLE ... CASCADE)
5+
-- only removes the table itself and its Citus shards; Postgres has no
6+
-- dependency link between it and the rows this extension keeps in
7+
-- pg_dist_spatiotemporal_tables/pg_dist_spatiotemporal_tiles, so those rows
8+
-- are silently orphaned otherwise. This event trigger removes them
9+
-- automatically whenever a registered table is dropped.
10+
CREATE OR REPLACE FUNCTION distributed_mobilitydb_drop_cleanup()
11+
RETURNS event_trigger AS $$
12+
DECLARE
13+
obj record;
14+
dropped_table_id integer;
15+
BEGIN
16+
IF to_regclass('pg_dist_spatiotemporal_tables') IS NULL THEN
17+
-- The extension itself (and its catalog tables) is being dropped;
18+
-- nothing left to clean up.
19+
RETURN;
20+
END IF;
21+
FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects()
22+
WHERE object_type = 'table'
23+
LOOP
24+
SELECT id INTO dropped_table_id
25+
FROM pg_dist_spatiotemporal_tables
26+
WHERE tableName = obj.object_name;
27+
28+
IF dropped_table_id IS NOT NULL THEN
29+
DELETE FROM pg_dist_spatiotemporal_tiles WHERE table_id = dropped_table_id;
30+
DELETE FROM pg_dist_spatiotemporal_tables WHERE id = dropped_table_id;
31+
END IF;
32+
END LOOP;
33+
END;
34+
$$ LANGUAGE 'plpgsql';
35+
36+
DROP EVENT TRIGGER IF EXISTS distributed_mobilitydb_drop_cleanup_trigger;
37+
CREATE EVENT TRIGGER distributed_mobilitydb_drop_cleanup_trigger
38+
ON sql_drop
39+
EXECUTE FUNCTION distributed_mobilitydb_drop_cleanup();

sql/helper_functions/colocation_utils.sql

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -34,47 +34,38 @@ END;
3434
$$;
3535

3636
----------------------------------------------------------------------------------------------------------------------
37-
-- colocate_multirelation colocates one multirelation with another
37+
-- colocate_shards physically moves table2's shards so each one lands on the
38+
-- same node as table1's shard sharing the same tile_key range (shardminvalue).
39+
-- Citus' own colocate_with option doesn't support range-distributed tables,
40+
-- so this does the move explicitly with citus_move_shard_placement() instead
41+
-- of relying on Citus' colocation groups.
3842
----------------------------------------------------------------------------------------------------------------------
39-
CREATE OR REPLACE FUNCTION colocate_multirelation(table1 text, table2 text)
43+
DROP FUNCTION IF EXISTS colocate_multirelation;
44+
CREATE OR REPLACE FUNCTION colocate_shards(table1 text, table2 text)
4045
RETURNS boolean
4146
LANGUAGE plpgsql
4247
AS $$
4348
DECLARE
44-
i integer;
45-
shard_info record;
46-
node_info record;
47-
node text;
48-
shardid_test bigint;
49+
tile_pair record;
4950
BEGIN
50-
--Move one of them to a new place because one node contains 10 and the other contains 11
51-
--It is an enterpise feature
52-
--SELECT master_move_shard_placement(102660,'pgxl4', 5432,'pgxl2', 5432);
53-
--For every node, update shards information
54-
FOR node_info in SELECT * FROM master_get_active_worker_nodes()
51+
FOR tile_pair IN
52+
SELECT s2.shardid AS moving_shard,
53+
n1.nodename AS target_node, n1.nodeport AS target_port,
54+
n2.nodename AS source_node, n2.nodeport AS source_port
55+
FROM pg_dist_shard s1
56+
JOIN pg_dist_placement p1 ON p1.shardid = s1.shardid
57+
JOIN pg_dist_node n1 ON n1.groupid = p1.groupid AND n1.noderole = 'primary'
58+
JOIN pg_dist_shard s2 ON s2.shardminvalue = s1.shardminvalue
59+
JOIN pg_dist_placement p2 ON p2.shardid = s2.shardid
60+
JOIN pg_dist_node n2 ON n2.groupid = p2.groupid AND n2.noderole = 'primary'
61+
WHERE s1.logicalrelid = table1::regclass
62+
AND s2.logicalrelid = table2::regclass
63+
AND (n1.nodename, n1.nodeport) IS DISTINCT FROM (n2.nodename, n2.nodeport)
5564
LOOP
56-
i = 0;
57-
--Get the shards of every table in every node
58-
FOR shard_info in SELECT shard.shardid, shard.shardminvalue, shard.shardmaxvalue
59-
FROM pg_dist_placement AS placement, pg_dist_node AS node, pg_dist_shard As shard
60-
WHERE placement.groupid = node.groupid
61-
AND shard.logicalrelid = table1::regclass
62-
AND placement.shardid = shard.shardid
63-
AND node.noderole = 'primary'
64-
AND nodename=node_info.node_name
65-
LOOP
66-
SELECT shard.shardid
67-
FROM pg_dist_placement AS placement, pg_dist_node AS node, pg_dist_shard As shard
68-
WHERE placement.groupid = node.groupid
69-
AND shard.logicalrelid = table2::regclass
70-
AND placement.shardid = shard.shardid
71-
AND node.noderole = 'primary'
72-
AND nodename=node_info.node_name offset i limit 1 INTO shardid_test;
73-
--RAISE NOTICE 'Update:%',shardid_test;
74-
UPDATE pg_dist_shard SET shardminvalue = shard_info.shardminvalue, shardmaxvalue=shard_info.shardmaxvalue
75-
WHERE shardid = shardid_test;
76-
i := i + 1;
77-
END LOOP;
65+
PERFORM citus_move_shard_placement(tile_pair.moving_shard,
66+
tile_pair.source_node, tile_pair.source_port,
67+
tile_pair.target_node, tile_pair.target_port,
68+
'block_writes');
7869
END LOOP;
7970
RETURN TRUE;
8071
END;
@@ -101,11 +92,15 @@ i integer;
10192
results json;
10293
BEGIN
10394
PERFORM create_range_shards(shards, reshuffled_table);
104-
--Modify the ranges
105-
UPDATE pg_catalog.pg_dist_partition
106-
SET colocationid=2
107-
WHERE logicalrelid=reshuffled_table::regclass;
108-
PERFORM colocate_multirelation(tableName, reshuffled_table);
95+
/* create_range_shards() above already assigns reshuffled_table's shards
96+
* the correct tile_key-aligned ranges (1..shards), matching tableName's
97+
* own tile numbering by convention -- both tables tile the same way.
98+
* Citus' shard placement for the newly-created shards is otherwise
99+
* independent of tableName's placement, so without this, a tile-key
100+
* join between the two tables is a cross-node repartition even though
101+
* both sides cover the same tile_key range. colocate_shards() moves
102+
* each of reshuffled_table's shards onto tableName's matching-tile node. */
103+
PERFORM colocate_shards(tableName, reshuffled_table);
109104
RETURN true;
110105
END;
111106
$$;

0 commit comments

Comments
 (0)