Skip to content

Commit

Permalink
[#7535] YSQL: Use geo-location (tablespace) to cost index scans
Browse files Browse the repository at this point in the history
Summary:
This introduces functionality to select an index placement to scan from based on their placements encoded in a tablespace.

We cost a tablespace by first costing each of its placement options and pessimistically choosing the worst of the placement options. Each placement option is scored based on a prefix comparison with our current node placement and assigns costs appropriately. Here are the current cost assignments:

The placement is zone-local (cloud, region and zone match): 9.4
The placement is region-local (cloud and region match): 9.5
The placement is cloud-local (cloud matches): 10.0
The placement is not-local (nothing matches): 10.0

The main motivation behind these costs is to keep the not-local scenario more expensive than the default cost that one obtains without considering tablespaces (10.0).

Test Plan: ybd --scb --sj org.yb.pgsql.TestPgRegressTablespaces#testPgRegressTablespaces

Reviewers: rskannan, dmitry, dsrinivasan, mihnea

Reviewed By: mihnea

Subscribers: jason, zyu, yql

Differential Revision: https://phabricator.dev.yugabyte.com/D10982
  • Loading branch information
Tanuj Nayak committed May 25, 2021
1 parent 2ca94c4 commit bebd181
Show file tree
Hide file tree
Showing 17 changed files with 476 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,60 @@
//
package org.yb.pgsql;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.yb.minicluster.MiniYBClusterBuilder;
import org.yb.util.YBTestRunnerNonTsanOnly;

import com.google.common.collect.ImmutableMap;

/**
* Runs the pg_regress test suite on YB code.
*/
@RunWith(value=YBTestRunnerNonTsanOnly.class)
public class TestPgRegressTablespaces extends BasePgSQLTest {

private List<Map<String, String>> perTserverZonePlacementFlags = Arrays.asList(
ImmutableMap.of(
"placement_cloud", "cloud1",
"placement_region", "region1",
"placement_zone", "zone1"),
ImmutableMap.of(
"placement_cloud", "cloud2",
"placement_region", "region2",
"placement_zone", "zone2"),
ImmutableMap.of(
"placement_cloud", "cloud1",
"placement_region", "region1",
"placement_zone", "zone2"),
ImmutableMap.of(
"placement_cloud", "cloud1",
"placement_region", "region2",
"placement_zone", "zone1"));

private Map<String, String> masterFlags =
ImmutableMap.of(
"placement_cloud", "cloud1",
"placement_region", "region1",
"placement_zone", "zone1");

@Override
protected void customizeMiniClusterBuilder(MiniYBClusterBuilder builder) {
super.customizeMiniClusterBuilder(builder);
builder.enablePgTransactions(true);
builder.perTServerFlags(perTserverZonePlacementFlags);
builder.numTservers(perTserverZonePlacementFlags.size());
builder.addMasterFlags(masterFlags);
}


@Override
public int getTestMethodTimeoutSec() {
return 500;
return 5000;
}

@Test
Expand Down
19 changes: 15 additions & 4 deletions src/postgres/src/backend/access/ybc/ybcam.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "utils/syscache.h"
#include "utils/selfuncs.h"
#include "utils/snapmgr.h"
#include "utils/spccache.h"

#include "yb/yql/pggate/ybc_pggate.h"
#include "pg_yb_utils.h"
Expand Down Expand Up @@ -1410,7 +1411,7 @@ void ybc_heap_endscan(HeapScanDesc scan_desc)

void ybcCostEstimate(RelOptInfo *baserel, Selectivity selectivity,
bool is_backwards_scan, bool is_uncovered_idx_scan,
Cost *startup_cost, Cost *total_cost)
Cost *startup_cost, Cost *total_cost, Oid index_tablespace_oid)
{
/*
* Yugabyte-specific per-tuple cost considerations:
Expand All @@ -1420,7 +1421,18 @@ void ybcCostEstimate(RelOptInfo *baserel, Selectivity selectivity,
* - uncovered index scan is more costly than index-only or seq scan because
* it requires extra request to the main table.
*/
Cost yb_per_tuple_cost_factor = 10;
double tsp_cost = 0.0;
bool is_valid_tsp_cost = !is_uncovered_idx_scan
&& get_yb_tablespace_cost(index_tablespace_oid,
&tsp_cost);
Cost yb_per_tuple_cost_factor = YB_DEFAULT_PER_TUPLE_COST;

if (is_valid_tsp_cost && yb_per_tuple_cost_factor > tsp_cost)
{
yb_per_tuple_cost_factor = tsp_cost;
}

Assert(!is_valid_tsp_cost || tsp_cost != 0);
if (is_backwards_scan)
{
yb_per_tuple_cost_factor *= YBC_BACKWARDS_SCAN_COST_FACTOR;
Expand Down Expand Up @@ -1561,7 +1573,7 @@ void ybcIndexCostEstimate(IndexPath *path, Selectivity *selectivity,
}

ybcCostEstimate(baserel, *selectivity, is_backwards_scan,
is_uncovered_idx_scan, startup_cost, total_cost);
is_uncovered_idx_scan, startup_cost, total_cost, path->indexinfo->reltablespace);

/*
* Try to evaluate the number of rows this baserel might return.
Expand All @@ -1579,7 +1591,6 @@ void ybcIndexCostEstimate(IndexPath *path, Selectivity *selectivity,
baserel->rows = baserel_rows_estimate;
}


if (relation)
RelationClose(relation);

Expand Down
13 changes: 10 additions & 3 deletions src/postgres/src/backend/executor/ybc_fdw.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,16 @@ ybcGetForeignPaths(PlannerInfo *root,

/* Estimate costs */
ybcCostEstimate(baserel, YBC_FULL_SCAN_SELECTIVITY,
false /* is_backwards scan */,
false /* is_uncovered_idx_scan */,
&startup_cost, &total_cost);
false /* is_backwards scan */,
false /* is_uncovered_idx_scan */,
&startup_cost,
&total_cost,
baserel->reltablespace /* tablespace of current path */);

/* add in cpu run factor for compatibility */
double cpu_run_cost = DEFAULT_CPU_TUPLE_COST * baserel->tuples / 2;

total_cost += cpu_run_cost;

/* Create a ForeignPath node and it as the scan path */
add_path(baserel,
Expand Down
21 changes: 20 additions & 1 deletion src/postgres/src/backend/optimizer/path/costsize.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ double cpu_operator_cost = DEFAULT_CPU_OPERATOR_COST;
double parallel_tuple_cost = DEFAULT_PARALLEL_TUPLE_COST;
double parallel_setup_cost = DEFAULT_PARALLEL_SETUP_COST;

double yb_intercloud_cost = YB_DEFAULT_INTERCLOUD_COST;
double yb_interregion_cost = YB_DEFAULT_INTERREGION_COST;
double yb_interzone_cost = YB_DEFAULT_INTERZONE_COST;

double yb_local_cost = YB_DEFAULT_LOCAL_COST;

int effective_cache_size = DEFAULT_EFFECTIVE_CACHE_SIZE;

Cost disable_cost = 1.0e10;
Expand All @@ -139,6 +145,7 @@ bool enable_partitionwise_aggregate = false;
bool enable_parallel_append = true;
bool enable_parallel_hash = true;
bool enable_partition_pruning = true;
bool yb_enable_geolocation_costing = true;

typedef struct
{
Expand Down Expand Up @@ -565,9 +572,21 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
tuples_fetched = clamp_row_est(indexSelectivity * baserel->tuples);

/* fetch estimated page costs for tablespace containing table */
get_tablespace_page_costs(baserel->reltablespace,
if (indexonly && IsYugaByteEnabled())
{
/*
* We already accounted for these costs when we made per-tuple cost
* adjustments based on tablespace.
*/
spc_random_page_cost = 0;
spc_seq_page_cost = 0;
}
else
{
get_tablespace_page_costs(baserel->reltablespace,
&spc_random_page_cost,
&spc_seq_page_cost);
}

/*----------
* Estimate number of main-table pages fetched, and compute I/O cost.
Expand Down
10 changes: 10 additions & 0 deletions src/postgres/src/backend/utils/adt/jsonfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -5577,6 +5577,16 @@ int json_get_int_value(text *json, char *key)
return ret_value;
}

/*
* This differs from json_get_value in that the string it returns does not do
* character escaping.
*/
text *
json_get_denormalized_value(text *json, char *key)
{
return get_worker(json, &key, NULL, 1, true);
}

text*
json_get_value(text *json, char *key)
{
Expand Down
Loading

0 comments on commit bebd181

Please sign in to comment.