Dear Hou, Thanks for creating a patch!
> When reviewing the code in logical/worker.c, I noticed that when applying a > cross-partition update action, it scans the old partition twice. > I am attaching the patch 0001 to remove this duplicate table scan. Just to clarify, you meant that FindReplTupleInLocalRel() are called in apply_handle_tuple_routing() and apply_handle_tuple_routing()->apply_handle_delete_internal(), which requires the index or sequential scan, right? LGTM. > Apart from above, I found there are quite a few duplicate codes related to > partition > handling(e.g. apply_handle_tuple_routing), so I tried to extract some > common logic to simplify the codes. Please see 0002 for this refactoring. IIUC, you wanted to remove the application code from apply_handle_tuple_routing() and put only a part partition detection. Is it right? Anyway, here are comments. 01. apply_handle_insert() ``` + targetRelInfo = edata->targetRelInfo; + /* For a partitioned table, insert the tuple into a partition. */ if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) - apply_handle_tuple_routing(edata, - remoteslot, NULL, CMD_INSERT); - else - apply_handle_insert_internal(edata, edata->targetRelInfo, - remoteslot); + remoteslot = apply_handle_tuple_routing(edata, CMD_INSERT, remoteslot, + &targetRelInfo); + + /* For a partitioned table, insert the tuple into a partition. */ + apply_handle_insert_internal(edata, targetRelInfo, remoteslot); ``` This part contains same comments, and no need to subsctitute in case of normal tables. How about: ``` - /* For a partitioned table, insert the tuple into a partition. */ + /* + * Find the actual target table if the table is partitioned. Otherwise, use + * the same table as the remote one. + */ if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) - apply_handle_tuple_routing(edata, - remoteslot, NULL, CMD_INSERT); + remoteslot = apply_handle_tuple_routing(edata, CMD_INSERT, remoteslot, + &targetRelInfo); else - apply_handle_insert_internal(edata, edata->targetRelInfo, - remoteslot); + targetRelInfo = edata->targetRelInfo; + + /* Insert a tuple to the target table */ + apply_handle_insert_internal(edata, targetRelInfo, remoteslot); ``` 02. apply_handle_tuple_routing() ``` /* - * This handles insert, update, delete on a partitioned table. + * Determine the partition in which the tuple in slot is to be inserted, and ... ``` But this function is called from delete_internal(). How about "Determine the partition to which the tuple in the slot belongs."? 03. apply_handle_tuple_routing() Do you have a reason why this does not return `ResultRelInfo *` but `TupleTableSlot *`? Not sure, but it is more proper for me to return the table info because this is a routing function. 04. apply_handle_update() ``` + targetRelInfo = edata->targetRelInfo; + targetrel = rel; + remoteslot_root = remoteslot; ``` Here I can say the same thing as 1. 05. apply_handle_update_internal() It looks the ordering of function's implementations are changed. Is it intentaional? before apply_handle_update apply_handle_update_internal apply_handle_delete apply_handle_delete_internal FindReplTupleInLocalRel apply_handle_tuple_routing after apply_handle_update apply_handle_delete apply_handle_delete_internal FindReplTupleInLocalRel apply_handle_tuple_routing apply_handle_update_internal 06. apply_handle_delete_internal() ``` + targetRelInfo = edata->targetRelInfo; + targetrel = rel; + ``` Here I can say the same thing as 1. Best regards, Hayato Kuroda FUJITSU LIMITED