-
Notifications
You must be signed in to change notification settings - Fork 851
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make INSERTs use a custom plan instead of triggers
With this change, hypertables no longer rely on an INSERT trigger to dispatch tuples to chunks. While an INSERT trigger worked well for both INSERTs and COPYs, it caused issues with supporting some regular triggers on hypertables, and didn't support RETURNING statements and upserts (ON CONFLICT DO UPDATE). INSERTs are now handled by modifying the plan for INSERT statements. A custom plan node is inserted as a subplan to a ModifyTable plan node, taking care of dispatching tuples to chunks by setting the result table for every tuple scanned. COPYs are handled by modifying the regular copy code. Unfortunately, this required copying a significant amount of regular PostgreSQL source code since there are no hooks to add modifications. However, since the modifications are small it should be fairly easy to keep the code in sync with upstream changes.
- Loading branch information
Showing
37 changed files
with
1,661 additions
and
791 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
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 |
---|---|---|
|
@@ -79,6 +79,3 @@ BEGIN | |
WHERE c.hypertable_id = drop_trigger_on_all_chunks.hypertable_id; | ||
END | ||
$BODY$; | ||
|
||
|
||
|
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
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
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
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 |
---|---|---|
@@ -0,0 +1,3 @@ | ||
DROP FUNCTION IF EXISTS _timescaledb_internal.timescale_trigger_names(); | ||
DROP FUNCTION IF EXISTS _timescaledb_internal.main_table_insert_trigger() CASCADE; | ||
DROP FUNCTION IF EXISTS _timescaledb_internal.main_table_after_insert_trigger() CASCADE; |
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 |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#include <postgres.h> | ||
#include <nodes/extensible.h> | ||
#include <nodes/makefuncs.h> | ||
#include <nodes/nodeFuncs.h> | ||
#include <utils/rel.h> | ||
#include <catalog/pg_type.h> | ||
|
||
#include "chunk_dispatch.h" | ||
#include "chunk_insert_state.h" | ||
#include "subspace_store.h" | ||
#include "dimension.h" | ||
|
||
ChunkDispatch * | ||
chunk_dispatch_create(Hypertable *ht, EState *estate) | ||
{ | ||
ChunkDispatch *cp = palloc(sizeof(ChunkDispatch)); | ||
|
||
cp->hypertable = ht; | ||
cp->estate = estate; | ||
cp->hypertable_result_rel_info = NULL; | ||
cp->cache = subspace_store_init(HYPERSPACE_NUM_DIMENSIONS(ht->space), estate->es_query_cxt); | ||
return cp; | ||
} | ||
|
||
void | ||
chunk_dispatch_destroy(ChunkDispatch *cp) | ||
{ | ||
subspace_store_free(cp->cache); | ||
} | ||
|
||
static void | ||
destroy_chunk_insert_state(void *cis) | ||
{ | ||
chunk_insert_state_destroy((ChunkInsertState *) cis); | ||
} | ||
|
||
/* | ||
* Get the chunk insert state for the chunk that matches the given point in the | ||
* partitioned hyperspace. | ||
*/ | ||
extern ChunkInsertState * | ||
chunk_dispatch_get_chunk_insert_state(ChunkDispatch *dispatch, Point *point) | ||
{ | ||
ChunkInsertState *cis; | ||
|
||
cis = subspace_store_get(dispatch->cache, point); | ||
|
||
if (NULL == cis) | ||
{ | ||
Chunk *new_chunk; | ||
|
||
new_chunk = hypertable_get_chunk(dispatch->hypertable, point); | ||
|
||
if (NULL == new_chunk) | ||
elog(ERROR, "No chunk found or created"); | ||
|
||
cis = chunk_insert_state_create(new_chunk, dispatch); | ||
subspace_store_add(dispatch->cache, new_chunk->cube, cis, destroy_chunk_insert_state); | ||
} | ||
|
||
return cis; | ||
} |
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 |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#ifndef TIMESCALEDB_CHUNK_DISPATCH_H | ||
#define TIMESCALEDB_CHUNK_DISPATCH_H | ||
|
||
#include <postgres.h> | ||
#include <nodes/execnodes.h> | ||
|
||
#include "hypertable_cache.h" | ||
#include "cache.h" | ||
#include "subspace_store.h" | ||
|
||
/* ChunkDispatch keeps info needed to dispatch tuples to chunks. */ | ||
typedef struct ChunkDispatch | ||
{ | ||
Hypertable *hypertable; | ||
SubspaceStore *cache; | ||
EState *estate; | ||
/* Keep a pointer to the original (hypertable's) ResultRelInfo since we will | ||
* reset the pointer in EState as we lookup new chunks. */ | ||
ResultRelInfo *hypertable_result_rel_info; | ||
} ChunkDispatch; | ||
|
||
typedef struct Point Point; | ||
typedef struct ChunkInsertState ChunkInsertState; | ||
|
||
ChunkDispatch *chunk_dispatch_create(Hypertable *, EState *); | ||
void chunk_dispatch_destroy(ChunkDispatch *); | ||
ChunkInsertState *chunk_dispatch_get_chunk_insert_state(ChunkDispatch *, Point *); | ||
|
||
#endif /* TIMESCALEDB_CHUNK_DISPATCH_H */ |
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 |
---|---|---|
@@ -0,0 +1,69 @@ | ||
#include <postgres.h> | ||
#include <nodes/extensible.h> | ||
#include <nodes/makefuncs.h> | ||
#include <nodes/nodeFuncs.h> | ||
#include <utils/rel.h> | ||
#include <catalog/pg_type.h> | ||
|
||
#include "chunk_dispatch_plan.h" | ||
#include "chunk_dispatch_state.h" | ||
|
||
/* | ||
* Create a ChunkDispatchState node from this plan. This is the full execution | ||
* state that replaces the plan node as the plan moves from planning to | ||
* execution. | ||
*/ | ||
static Node * | ||
create_chunk_dispatch_state(CustomScan *cscan) | ||
{ | ||
ChunkDispatchInfo *info = linitial(cscan->custom_private); | ||
|
||
return (Node *) chunk_dispatch_state_create(info->hypertable_relid, | ||
linitial(cscan->custom_plans)); | ||
} | ||
|
||
static CustomScanMethods chunk_dispatch_plan_methods = { | ||
.CustomName = "ChunkDispatch", | ||
.CreateCustomScanState = create_chunk_dispatch_state, | ||
}; | ||
|
||
/* Create a chunk dispatch plan node in the form of a CustomScan node. The | ||
* purpose of this plan node is to dispatch (route) tuples to the correct chunk | ||
* in a hypertable. | ||
* | ||
* Note that CustomScan nodes cannot be extended (by struct embedding) because | ||
* they might be copied, therefore we pass any extra info as a ChunkDispatchInfo | ||
* in the custom_private field. | ||
* | ||
* The chunk dispatch plan takes the original tuple-producing subplan, which was | ||
* part of a ModifyTable node, and uses this subplan to produce new tuples to | ||
* dispatch. | ||
*/ | ||
CustomScan * | ||
chunk_dispatch_plan_create(Plan *subplan, Oid hypertable_relid) | ||
{ | ||
CustomScan *cscan = makeNode(CustomScan); | ||
ChunkDispatchInfo *info = palloc(sizeof(ChunkDispatchInfo)); | ||
|
||
info->hypertable_relid = hypertable_relid; | ||
cscan->custom_private = list_make1(info); | ||
cscan->methods = &chunk_dispatch_plan_methods; | ||
cscan->custom_plans = list_make1(subplan); | ||
cscan->scan.scanrelid = 0; /* Indicate this is not a real relation we are | ||
* scanning */ | ||
|
||
/* Copy costs from the original plan */ | ||
cscan->scan.plan.startup_cost = subplan->startup_cost; | ||
cscan->scan.plan.total_cost = subplan->total_cost; | ||
cscan->scan.plan.plan_rows = subplan->plan_rows; | ||
cscan->scan.plan.plan_width = subplan->plan_width; | ||
|
||
/* | ||
* Copy target list from parent table. This should work since hypertables | ||
* mandate that chunks have identical column definitions | ||
*/ | ||
cscan->scan.plan.targetlist = subplan->targetlist; | ||
cscan->custom_scan_tlist = NIL; | ||
|
||
return cscan; | ||
} |
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 |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#ifndef TIMESCALEDB_CHUNK_DISPATCH_PLAN_H | ||
#define TIMESCALEDB_CHUNK_DISPATCH_PLAN_H | ||
|
||
#include <postgres.h> | ||
#include <nodes/plannodes.h> | ||
|
||
typedef struct ChunkDispatchInfo | ||
{ | ||
Oid hypertable_relid; | ||
} ChunkDispatchInfo; | ||
|
||
extern CustomScan *chunk_dispatch_plan_create(Plan *subplan, Oid hypertable_relid); | ||
|
||
#endif /* TIMESCALEDB_CHUNK_DISPATCH_PLAN_H */ |
Oops, something went wrong.