mirror of https://github.com/citusdata/citus.git
Tenant monitoring performance improvements (#6868)
- [x] Use spinlock instead of lwlock per tenant [release-11.3-gokhan-1b437aa9
](b437aa9e52
) - [x] Use hashtable to store tenant stats [ccd464b
](ccd464ba04
) - [x] Introduce a new GUC for specifying the sampling rate of new tenant entries in the tenant monitor. [a8d3805
](a8d3805bd6
) Below are the pgbench metrics with select-only workloads from my local machine. Here is the [script](https://gist.github.com/gokhangulbiz/7a2308470597dc06734ff7c08f87c656) I used for benchmarking. | | Connection Count | Initial Implementation (TPS) | On/Off Diff | Final Implementation -Run#1 (TPS) | On/Off Diff | Final Implementation -Run#2 (TPS) | On/Off Diff | Final Implementation -Run#3 (TPS) | On/Off Diff | Avg On/Off Diff | | --- | ---------------- | ---------------------------- | ----------- | ---------------------------------- | ----------- | ---------------------------------- | ----------- | ---------------------------------- | ----------- | --------------- | | On | 32 | 37488.69839 | \-17% | 42859.94402 | \-5% | 43379.63121 | \-2% | 42636.2264 | \-7% | \-5% | | Off | 32 | 43909.83121 | | 45139.63151 | | 44188.77425 | | 45451.9548 | | | | On | 300 | 30463.03538 | \-15% | 33265.19957 | \-7% | 34685.87233 | \-2% | 34682.5214 | \-1% | \-3% | | Off | 300 | 35105.73594 | | 35637.45423 | | 35331.33447 | | 35113.3214 | | | (cherry picked from commit2c509b712a
)
parent
2de879dc59
commit
76236f072e
|
@ -2012,7 +2012,7 @@ GenerateTaskMoveDependencyList(PlacementUpdateEvent *move, int64 colocationId,
|
|||
* overlaps with the current move's target node.
|
||||
* The earlier/first move might make space for the later/second move.
|
||||
* So we could run out of disk space (or at least overload the node)
|
||||
* if we move the second shard to it before the first one is moved away.
|
||||
* if we move the second shard to it before the first one is moved away.
|
||||
*/
|
||||
ShardMoveSourceNodeHashEntry *shardMoveSourceNodeHashEntry = hash_search(
|
||||
shardMoveDependencies.nodeDependencies, &move->targetNode->nodeId, HASH_FIND,
|
||||
|
|
|
@ -2395,7 +2395,6 @@ RegisterCitusConfigVariables(void)
|
|||
PGC_POSTMASTER,
|
||||
GUC_STANDARD,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
DefineCustomEnumVariable(
|
||||
"citus.stat_tenants_log_level",
|
||||
gettext_noop("Sets the level of citus_stat_tenants log messages"),
|
||||
|
@ -2417,6 +2416,17 @@ RegisterCitusConfigVariables(void)
|
|||
GUC_STANDARD,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
|
||||
DefineCustomIntVariable(
|
||||
"citus.stat_tenants_sample_rate_for_new_tenants",
|
||||
gettext_noop("Sampling rate for new tenants in citus_stat_tenants."),
|
||||
NULL,
|
||||
&StatTenantsSampleRateForNewTenants,
|
||||
100, 1, 100,
|
||||
PGC_USERSET,
|
||||
GUC_STANDARD,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
DefineCustomEnumVariable(
|
||||
"citus.stat_tenants_track",
|
||||
gettext_noop("Enables/Disables the stats collection for citus_stat_tenants."),
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "postgres.h"
|
||||
#include "unistd.h"
|
||||
|
||||
#include "access/hash.h"
|
||||
#include "distributed/citus_safe_lib.h"
|
||||
#include "distributed/colocation_utils.h"
|
||||
#include "distributed/distributed_planner.h"
|
||||
|
@ -50,7 +51,6 @@ static clock_t QueryEndClock = { 0 };
|
|||
|
||||
static const char *SharedMemoryNameForMultiTenantMonitor =
|
||||
"Shared memory for multi tenant monitor";
|
||||
static char *TenantTrancheName = "Tenant Tranche";
|
||||
static char *MonitorTrancheName = "Multi Tenant Monitor Tranche";
|
||||
|
||||
static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
|
||||
|
@ -60,12 +60,14 @@ static void UpdatePeriodsIfNecessary(TenantStats *tenantStats, TimestampTz query
|
|||
static void ReduceScoreIfNecessary(TenantStats *tenantStats, TimestampTz queryTime);
|
||||
static void EvictTenantsIfNecessary(TimestampTz queryTime);
|
||||
static void RecordTenantStats(TenantStats *tenantStats, TimestampTz queryTime);
|
||||
static void CreateMultiTenantMonitor(void);
|
||||
static MultiTenantMonitor * CreateSharedMemoryForMultiTenantMonitor(void);
|
||||
static MultiTenantMonitor * GetMultiTenantMonitor(void);
|
||||
static void MultiTenantMonitorSMInit(void);
|
||||
static int CreateTenantStats(MultiTenantMonitor *monitor, TimestampTz queryTime);
|
||||
static int FindTenantStats(MultiTenantMonitor *monitor);
|
||||
static TenantStats * CreateTenantStats(MultiTenantMonitor *monitor, TimestampTz
|
||||
queryTime);
|
||||
static void FillTenantStatsHashKey(TenantStatsHashKey *key, char *tenantAttribute, uint32
|
||||
colocationGroupId);
|
||||
static TenantStats * FindTenantStats(MultiTenantMonitor *monitor);
|
||||
static size_t MultiTenantMonitorshmemSize(void);
|
||||
static char * ExtractTopComment(const char *inputString);
|
||||
static char * EscapeCommentChars(const char *str);
|
||||
|
@ -75,7 +77,7 @@ int StatTenantsLogLevel = CITUS_LOG_LEVEL_OFF;
|
|||
int StatTenantsPeriod = (time_t) 60;
|
||||
int StatTenantsLimit = 100;
|
||||
int StatTenantsTrack = STAT_TENANTS_TRACK_NONE;
|
||||
|
||||
int StatTenantsSampleRateForNewTenants = 100;
|
||||
|
||||
PG_FUNCTION_INFO_V1(citus_stat_tenants_local);
|
||||
PG_FUNCTION_INFO_V1(citus_stat_tenants_local_reset);
|
||||
|
@ -113,21 +115,36 @@ citus_stat_tenants_local(PG_FUNCTION_ARGS)
|
|||
LWLockAcquire(&monitor->lock, LW_EXCLUSIVE);
|
||||
|
||||
int numberOfRowsToReturn = 0;
|
||||
int tenantStatsCount = hash_get_num_entries(monitor->tenants);
|
||||
if (returnAllTenants)
|
||||
{
|
||||
numberOfRowsToReturn = monitor->tenantCount;
|
||||
numberOfRowsToReturn = tenantStatsCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
numberOfRowsToReturn = Min(monitor->tenantCount, StatTenantsLimit);
|
||||
numberOfRowsToReturn = Min(tenantStatsCount,
|
||||
StatTenantsLimit);
|
||||
}
|
||||
|
||||
for (int tenantIndex = 0; tenantIndex < monitor->tenantCount; tenantIndex++)
|
||||
/* Allocate an array to hold the tenants. */
|
||||
TenantStats **stats = palloc(tenantStatsCount *
|
||||
sizeof(TenantStats *));
|
||||
|
||||
HASH_SEQ_STATUS hash_seq;
|
||||
TenantStats *stat;
|
||||
|
||||
/* Get all the tenants from the hash table. */
|
||||
int j = 0;
|
||||
hash_seq_init(&hash_seq, monitor->tenants);
|
||||
while ((stat = hash_seq_search(&hash_seq)) != NULL)
|
||||
{
|
||||
UpdatePeriodsIfNecessary(&monitor->tenants[tenantIndex], monitoringTime);
|
||||
ReduceScoreIfNecessary(&monitor->tenants[tenantIndex], monitoringTime);
|
||||
stats[j++] = stat;
|
||||
UpdatePeriodsIfNecessary(stat, monitoringTime);
|
||||
ReduceScoreIfNecessary(stat, monitoringTime);
|
||||
}
|
||||
SafeQsort(monitor->tenants, monitor->tenantCount, sizeof(TenantStats),
|
||||
|
||||
/* Sort the tenants by their score. */
|
||||
SafeQsort(stats, j, sizeof(TenantStats *),
|
||||
CompareTenantScore);
|
||||
|
||||
for (int i = 0; i < numberOfRowsToReturn; i++)
|
||||
|
@ -135,10 +152,10 @@ citus_stat_tenants_local(PG_FUNCTION_ARGS)
|
|||
memset(values, 0, sizeof(values));
|
||||
memset(isNulls, false, sizeof(isNulls));
|
||||
|
||||
TenantStats *tenantStats = &monitor->tenants[i];
|
||||
TenantStats *tenantStats = stats[i];
|
||||
|
||||
values[0] = Int32GetDatum(tenantStats->colocationGroupId);
|
||||
values[1] = PointerGetDatum(cstring_to_text(tenantStats->tenantAttribute));
|
||||
values[0] = Int32GetDatum(tenantStats->key.colocationGroupId);
|
||||
values[1] = PointerGetDatum(cstring_to_text(tenantStats->key.tenantAttribute));
|
||||
values[2] = Int32GetDatum(tenantStats->readsInThisPeriod);
|
||||
values[3] = Int32GetDatum(tenantStats->readsInLastPeriod);
|
||||
values[4] = Int32GetDatum(tenantStats->readsInThisPeriod +
|
||||
|
@ -152,6 +169,8 @@ citus_stat_tenants_local(PG_FUNCTION_ARGS)
|
|||
tuplestore_putvalues(tupleStore, tupleDescriptor, values, isNulls);
|
||||
}
|
||||
|
||||
pfree(stats);
|
||||
|
||||
LWLockRelease(&monitor->lock);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
|
@ -166,7 +185,25 @@ Datum
|
|||
citus_stat_tenants_local_reset(PG_FUNCTION_ARGS)
|
||||
{
|
||||
MultiTenantMonitor *monitor = GetMultiTenantMonitor();
|
||||
monitor->tenantCount = 0;
|
||||
|
||||
/* if monitor is not created yet, there is nothing to reset */
|
||||
if (monitor == NULL)
|
||||
{
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
HASH_SEQ_STATUS hash_seq;
|
||||
TenantStats *stats;
|
||||
|
||||
LWLockAcquire(&monitor->lock, LW_EXCLUSIVE);
|
||||
|
||||
hash_seq_init(&hash_seq, monitor->tenants);
|
||||
while ((stats = hash_seq_search(&hash_seq)) != NULL)
|
||||
{
|
||||
hash_search(monitor->tenants, &stats->key, HASH_REMOVE, NULL);
|
||||
}
|
||||
|
||||
LWLockRelease(&monitor->lock);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
@ -226,6 +263,24 @@ AttributeTask(char *tenantId, int colocationId, CmdType commandType)
|
|||
return;
|
||||
}
|
||||
|
||||
TenantStatsHashKey key = { 0 };
|
||||
FillTenantStatsHashKey(&key, tenantId, colocationId);
|
||||
|
||||
MultiTenantMonitor *monitor = GetMultiTenantMonitor();
|
||||
bool found = false;
|
||||
hash_search(monitor->tenants, &key, HASH_FIND, &found);
|
||||
|
||||
/* If the tenant is not found in the hash table, we will track the query with a probability of StatTenantsSampleRateForNewTenants. */
|
||||
if (!found)
|
||||
{
|
||||
int randomValue = rand() % 100;
|
||||
bool shouldTrackQuery = randomValue < StatTenantsSampleRateForNewTenants;
|
||||
if (!shouldTrackQuery)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AttributeToColocationGroupId = colocationId;
|
||||
strncpy_s(AttributeToTenant, MAX_TENANT_ATTRIBUTE_LENGTH, tenantId,
|
||||
MAX_TENANT_ATTRIBUTE_LENGTH - 1);
|
||||
|
@ -295,14 +350,14 @@ CitusAttributeToEnd(QueryDesc *queryDesc)
|
|||
static int
|
||||
CompareTenantScore(const void *leftElement, const void *rightElement)
|
||||
{
|
||||
const TenantStats *leftTenant = (const TenantStats *) leftElement;
|
||||
const TenantStats *rightTenant = (const TenantStats *) rightElement;
|
||||
double l_usage = (*(TenantStats *const *) leftElement)->score;
|
||||
double r_usage = (*(TenantStats *const *) rightElement)->score;
|
||||
|
||||
if (leftTenant->score > rightTenant->score)
|
||||
if (l_usage > r_usage)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (leftTenant->score < rightTenant->score)
|
||||
else if (l_usage < r_usage)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@ -353,45 +408,43 @@ AttributeMetricsIfApplicable()
|
|||
*/
|
||||
LWLockAcquire(&monitor->lock, LW_SHARED);
|
||||
|
||||
int currentTenantIndex = FindTenantStats(monitor);
|
||||
TenantStats *tenantStats = FindTenantStats(monitor);
|
||||
|
||||
if (currentTenantIndex != -1)
|
||||
if (tenantStats != NULL)
|
||||
{
|
||||
TenantStats *tenantStats = &monitor->tenants[currentTenantIndex];
|
||||
LWLockAcquire(&tenantStats->lock, LW_EXCLUSIVE);
|
||||
SpinLockAcquire(&tenantStats->lock);
|
||||
|
||||
UpdatePeriodsIfNecessary(tenantStats, queryTime);
|
||||
ReduceScoreIfNecessary(tenantStats, queryTime);
|
||||
RecordTenantStats(tenantStats, queryTime);
|
||||
|
||||
LWLockRelease(&tenantStats->lock);
|
||||
SpinLockRelease(&tenantStats->lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
LWLockRelease(&monitor->lock);
|
||||
|
||||
LWLockAcquire(&monitor->lock, LW_EXCLUSIVE);
|
||||
currentTenantIndex = FindTenantStats(monitor);
|
||||
tenantStats = FindTenantStats(monitor);
|
||||
|
||||
if (currentTenantIndex == -1)
|
||||
if (tenantStats == NULL)
|
||||
{
|
||||
currentTenantIndex = CreateTenantStats(monitor, queryTime);
|
||||
tenantStats = CreateTenantStats(monitor, queryTime);
|
||||
}
|
||||
|
||||
LWLockRelease(&monitor->lock);
|
||||
|
||||
LWLockAcquire(&monitor->lock, LW_SHARED);
|
||||
currentTenantIndex = FindTenantStats(monitor);
|
||||
if (currentTenantIndex != -1)
|
||||
tenantStats = FindTenantStats(monitor);
|
||||
if (tenantStats != NULL)
|
||||
{
|
||||
TenantStats *tenantStats = &monitor->tenants[currentTenantIndex];
|
||||
LWLockAcquire(&tenantStats->lock, LW_EXCLUSIVE);
|
||||
SpinLockAcquire(&tenantStats->lock);
|
||||
|
||||
UpdatePeriodsIfNecessary(tenantStats, queryTime);
|
||||
ReduceScoreIfNecessary(tenantStats, queryTime);
|
||||
RecordTenantStats(tenantStats, queryTime);
|
||||
|
||||
LWLockRelease(&tenantStats->lock);
|
||||
SpinLockRelease(&tenantStats->lock);
|
||||
}
|
||||
}
|
||||
LWLockRelease(&monitor->lock);
|
||||
|
@ -507,15 +560,29 @@ EvictTenantsIfNecessary(TimestampTz queryTime)
|
|||
*
|
||||
* Every time tenant count hits StatTenantsLimit * 3, we reduce it back to StatTenantsLimit * 2.
|
||||
*/
|
||||
if (monitor->tenantCount >= StatTenantsLimit * 3)
|
||||
long tenantStatsCount = hash_get_num_entries(monitor->tenants);
|
||||
if (tenantStatsCount >= StatTenantsLimit * 3)
|
||||
{
|
||||
for (int tenantIndex = 0; tenantIndex < monitor->tenantCount; tenantIndex++)
|
||||
HASH_SEQ_STATUS hash_seq;
|
||||
TenantStats *stat;
|
||||
TenantStats **stats = palloc(tenantStatsCount *
|
||||
sizeof(TenantStats *));
|
||||
|
||||
int i = 0;
|
||||
hash_seq_init(&hash_seq, monitor->tenants);
|
||||
while ((stat = hash_seq_search(&hash_seq)) != NULL)
|
||||
{
|
||||
ReduceScoreIfNecessary(&monitor->tenants[tenantIndex], queryTime);
|
||||
stats[i++] = stat;
|
||||
}
|
||||
SafeQsort(monitor->tenants, monitor->tenantCount, sizeof(TenantStats),
|
||||
CompareTenantScore);
|
||||
monitor->tenantCount = StatTenantsLimit * 2;
|
||||
|
||||
SafeQsort(stats, i, sizeof(TenantStats *), CompareTenantScore);
|
||||
|
||||
for (i = StatTenantsLimit * 2; i < tenantStatsCount; i++)
|
||||
{
|
||||
hash_search(monitor->tenants, &stats[i]->key, HASH_REMOVE, NULL);
|
||||
}
|
||||
|
||||
pfree(stats);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -553,17 +620,6 @@ RecordTenantStats(TenantStats *tenantStats, TimestampTz queryTime)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* CreateMultiTenantMonitor creates the data structure for multi tenant monitor.
|
||||
*/
|
||||
static void
|
||||
CreateMultiTenantMonitor()
|
||||
{
|
||||
MultiTenantMonitor *monitor = CreateSharedMemoryForMultiTenantMonitor();
|
||||
monitor->tenantCount = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CreateSharedMemoryForMultiTenantMonitor creates a dynamic shared memory segment for multi tenant monitor.
|
||||
*/
|
||||
|
@ -586,6 +642,17 @@ CreateSharedMemoryForMultiTenantMonitor()
|
|||
monitor->namedLockTranche.trancheName);
|
||||
LWLockInitialize(&monitor->lock, monitor->namedLockTranche.trancheId);
|
||||
|
||||
HASHCTL info;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.keysize = sizeof(TenantStatsHashKey);
|
||||
info.entrysize = sizeof(TenantStats);
|
||||
|
||||
monitor->tenants = ShmemInitHash("citus_stats_tenants hash",
|
||||
StatTenantsLimit * 3, StatTenantsLimit * 3,
|
||||
&info, HASH_ELEM |
|
||||
HASH_SHARED_MEM | HASH_BLOBS);
|
||||
|
||||
return monitor;
|
||||
}
|
||||
|
||||
|
@ -629,7 +696,7 @@ InitializeMultiTenantMonitorSMHandleManagement()
|
|||
static void
|
||||
MultiTenantMonitorSMInit()
|
||||
{
|
||||
CreateMultiTenantMonitor();
|
||||
CreateSharedMemoryForMultiTenantMonitor();
|
||||
|
||||
if (prev_shmem_startup_hook != NULL)
|
||||
{
|
||||
|
@ -643,7 +710,7 @@ MultiTenantMonitorSMInit()
|
|||
*
|
||||
* Calling this function should be protected by the monitor->lock in LW_EXCLUSIVE mode.
|
||||
*/
|
||||
static int
|
||||
static TenantStats *
|
||||
CreateTenantStats(MultiTenantMonitor *monitor, TimestampTz queryTime)
|
||||
{
|
||||
/*
|
||||
|
@ -652,45 +719,50 @@ CreateTenantStats(MultiTenantMonitor *monitor, TimestampTz queryTime)
|
|||
*/
|
||||
EvictTenantsIfNecessary(queryTime);
|
||||
|
||||
int tenantIndex = monitor->tenantCount;
|
||||
TenantStatsHashKey key = { 0 };
|
||||
FillTenantStatsHashKey(&key, AttributeToTenant, AttributeToColocationGroupId);
|
||||
|
||||
memset(&monitor->tenants[tenantIndex], 0, sizeof(monitor->tenants[tenantIndex]));
|
||||
TenantStats *stats = (TenantStats *) hash_search(monitor->tenants, &key,
|
||||
HASH_ENTER, NULL);
|
||||
|
||||
strcpy_s(monitor->tenants[tenantIndex].tenantAttribute,
|
||||
sizeof(monitor->tenants[tenantIndex].tenantAttribute), AttributeToTenant);
|
||||
monitor->tenants[tenantIndex].colocationGroupId = AttributeToColocationGroupId;
|
||||
stats->writesInLastPeriod = 0;
|
||||
stats->writesInThisPeriod = 0;
|
||||
stats->readsInLastPeriod = 0;
|
||||
stats->readsInThisPeriod = 0;
|
||||
stats->cpuUsageInLastPeriod = 0;
|
||||
stats->cpuUsageInThisPeriod = 0;
|
||||
stats->score = 0;
|
||||
stats->lastScoreReduction = 0;
|
||||
|
||||
monitor->tenants[tenantIndex].namedLockTranche.trancheId = LWLockNewTrancheId();
|
||||
monitor->tenants[tenantIndex].namedLockTranche.trancheName = TenantTrancheName;
|
||||
SpinLockInit(&stats->lock);
|
||||
|
||||
LWLockRegisterTranche(monitor->tenants[tenantIndex].namedLockTranche.trancheId,
|
||||
monitor->tenants[tenantIndex].namedLockTranche.trancheName);
|
||||
LWLockInitialize(&monitor->tenants[tenantIndex].lock,
|
||||
monitor->tenants[tenantIndex].namedLockTranche.trancheId);
|
||||
|
||||
monitor->tenantCount++;
|
||||
|
||||
return tenantIndex;
|
||||
return stats;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FindTenantStats finds the index for the current tenant's statistics.
|
||||
* FindTenantStats finds the current tenant's statistics.
|
||||
*/
|
||||
static int
|
||||
static TenantStats *
|
||||
FindTenantStats(MultiTenantMonitor *monitor)
|
||||
{
|
||||
for (int i = 0; i < monitor->tenantCount; i++)
|
||||
{
|
||||
TenantStats *tenantStats = &monitor->tenants[i];
|
||||
if (strcmp(tenantStats->tenantAttribute, AttributeToTenant) == 0 &&
|
||||
tenantStats->colocationGroupId == AttributeToColocationGroupId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
TenantStatsHashKey key = { 0 };
|
||||
FillTenantStatsHashKey(&key, AttributeToTenant, AttributeToColocationGroupId);
|
||||
|
||||
return -1;
|
||||
TenantStats *stats = (TenantStats *) hash_search(monitor->tenants, &key,
|
||||
HASH_FIND, NULL);
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
FillTenantStatsHashKey(TenantStatsHashKey *key, char *tenantAttribute, uint32
|
||||
colocationGroupId)
|
||||
{
|
||||
memset(key->tenantAttribute, 0, MAX_TENANT_ATTRIBUTE_LENGTH);
|
||||
strlcpy(key->tenantAttribute, tenantAttribute, MAX_TENANT_ATTRIBUTE_LENGTH);
|
||||
key->colocationGroupId = colocationGroupId;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -11,24 +11,33 @@
|
|||
#ifndef CITUS_ATTRIBUTE_H
|
||||
#define CITUS_ATTRIBUTE_H
|
||||
|
||||
#include "distributed/hash_helpers.h"
|
||||
#include "executor/execdesc.h"
|
||||
#include "executor/executor.h"
|
||||
#include "storage/lwlock.h"
|
||||
#include "utils/datetime.h"
|
||||
#include "utils/hsearch.h"
|
||||
|
||||
#define MAX_TENANT_ATTRIBUTE_LENGTH 100
|
||||
|
||||
/*
|
||||
* Hashtable key that defines the identity of a hashtable entry.
|
||||
* The key is the attribute value, e.g distribution column and the colocation group id of the tenant.
|
||||
*/
|
||||
typedef struct TenantStatsHashKey
|
||||
{
|
||||
char tenantAttribute[MAX_TENANT_ATTRIBUTE_LENGTH];
|
||||
int colocationGroupId;
|
||||
} TenantStatsHashKey;
|
||||
assert_valid_hash_key2(TenantStatsHashKey, tenantAttribute, colocationGroupId);
|
||||
|
||||
/*
|
||||
* TenantStats is the struct that keeps statistics about one tenant.
|
||||
*/
|
||||
typedef struct TenantStats
|
||||
{
|
||||
/*
|
||||
* The attribute value, e.g distribution column, and colocation group id
|
||||
* of the tenant.
|
||||
*/
|
||||
char tenantAttribute[MAX_TENANT_ATTRIBUTE_LENGTH];
|
||||
int colocationGroupId;
|
||||
TenantStatsHashKey key; /* hash key of entry - MUST BE FIRST */
|
||||
|
||||
|
||||
/*
|
||||
* Number of SELECT queries this tenant ran in this and last periods.
|
||||
|
@ -70,8 +79,7 @@ typedef struct TenantStats
|
|||
/*
|
||||
* Locks needed to update this tenant's statistics.
|
||||
*/
|
||||
NamedLWLockTranche namedLockTranche;
|
||||
LWLock lock;
|
||||
slock_t lock;
|
||||
} TenantStats;
|
||||
|
||||
/*
|
||||
|
@ -89,12 +97,9 @@ typedef struct MultiTenantMonitor
|
|||
LWLock lock;
|
||||
|
||||
/*
|
||||
* tenantCount is the number of items in the tenants array.
|
||||
* The total length of tenants array is set up at CreateSharedMemoryForMultiTenantMonitor
|
||||
* and is 3 * citus.stat_tenants_limit
|
||||
* The max length of tenants hashtable is 3 * citus.stat_tenants_limit
|
||||
*/
|
||||
int tenantCount;
|
||||
TenantStats tenants[FLEXIBLE_ARRAY_MEMBER];
|
||||
HTAB *tenants;
|
||||
} MultiTenantMonitor;
|
||||
|
||||
typedef enum
|
||||
|
@ -116,5 +121,6 @@ extern int StatTenantsLogLevel;
|
|||
extern int StatTenantsPeriod;
|
||||
extern int StatTenantsLimit;
|
||||
extern int StatTenantsTrack;
|
||||
extern int StatTenantsSampleRateForNewTenants;
|
||||
|
||||
#endif /*CITUS_ATTRIBUTE_H */
|
||||
|
|
|
@ -137,6 +137,18 @@ SELECT count(*)>=0 FROM dist_tbl WHERE a = 2;
|
|||
t
|
||||
(1 row)
|
||||
|
||||
SELECT count(*)>=0 FROM dist_tbl WHERE a = 2;
|
||||
?column?
|
||||
---------------------------------------------------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT count(*)>=0 FROM dist_tbl WHERE a = 3;
|
||||
?column?
|
||||
---------------------------------------------------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT count(*)>=0 FROM dist_tbl WHERE a = 3;
|
||||
?column?
|
||||
---------------------------------------------------------------------
|
||||
|
@ -158,8 +170,8 @@ SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'abcd';
|
|||
SELECT tenant_attribute, query_count_in_this_period, score FROM citus_stat_tenants(true) WHERE nodeid = :worker_2_nodeid ORDER BY score DESC, tenant_attribute;
|
||||
tenant_attribute | query_count_in_this_period | score
|
||||
---------------------------------------------------------------------
|
||||
2 | 1 | 1000000000
|
||||
3 | 1 | 1000000000
|
||||
2 | 2 | 2000000000
|
||||
3 | 2 | 2000000000
|
||||
4 | 1 | 1000000000
|
||||
abcd | 1 | 1000000000
|
||||
(4 rows)
|
||||
|
@ -192,8 +204,8 @@ SELECT tenant_attribute, query_count_in_this_period, score FROM citus_stat_tenan
|
|||
tenant_attribute | query_count_in_this_period | score
|
||||
---------------------------------------------------------------------
|
||||
abcd | 3 | 3000000000
|
||||
2 | 1 | 1000000000
|
||||
3 | 1 | 1000000000
|
||||
2 | 2 | 2000000000
|
||||
3 | 2 | 2000000000
|
||||
4 | 1 | 1000000000
|
||||
bcde | 1 | 1000000000
|
||||
cdef | 1 | 1000000000
|
||||
|
@ -222,10 +234,8 @@ SELECT tenant_attribute, query_count_in_this_period, score FROM citus_stat_tenan
|
|||
---------------------------------------------------------------------
|
||||
abcd | 3 | 3000000000
|
||||
bcde | 3 | 3000000000
|
||||
2 | 1 | 1000000000
|
||||
3 | 1 | 1000000000
|
||||
4 | 1 | 1000000000
|
||||
cdef | 1 | 1000000000
|
||||
2 | 2 | 2000000000
|
||||
3 | 2 | 2000000000
|
||||
defg | 1 | 1000000000
|
||||
(7 rows)
|
||||
|
||||
|
@ -791,7 +801,7 @@ SELECT select_from_dist_tbl_text(U&'\0061\0308bc');
|
|||
t
|
||||
(1 row)
|
||||
|
||||
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants;
|
||||
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants ORDER BY tenant_attribute;
|
||||
tenant_attribute | query_count_in_this_period
|
||||
---------------------------------------------------------------------
|
||||
/b*c/de | 2
|
||||
|
@ -817,7 +827,7 @@ CALL citus_stat_tenants.select_from_dist_tbl_text_proc(U&'\0061\0308bc');
|
|||
CALL citus_stat_tenants.select_from_dist_tbl_text_proc(U&'\0061\0308bc');
|
||||
CALL citus_stat_tenants.select_from_dist_tbl_text_proc(U&'\0061\0308bc');
|
||||
CALL citus_stat_tenants.select_from_dist_tbl_text_proc(NULL);
|
||||
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants;
|
||||
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants ORDER BY tenant_attribute;
|
||||
tenant_attribute | query_count_in_this_period
|
||||
---------------------------------------------------------------------
|
||||
/b*c/de | 8
|
||||
|
@ -864,7 +874,7 @@ SELECT count(*)>=0 FROM select_from_dist_tbl_text_view WHERE a = U&'\0061\0308bc
|
|||
t
|
||||
(1 row)
|
||||
|
||||
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants;
|
||||
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants ORDER BY tenant_attribute;
|
||||
tenant_attribute | query_count_in_this_period
|
||||
---------------------------------------------------------------------
|
||||
/b*c/de | 11
|
||||
|
|
|
@ -61,6 +61,8 @@ SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants(true
|
|||
SELECT nodeid AS worker_2_nodeid FROM pg_dist_node WHERE nodeport = :worker_2_port \gset
|
||||
|
||||
SELECT count(*)>=0 FROM dist_tbl WHERE a = 2;
|
||||
SELECT count(*)>=0 FROM dist_tbl WHERE a = 2;
|
||||
SELECT count(*)>=0 FROM dist_tbl WHERE a = 3;
|
||||
SELECT count(*)>=0 FROM dist_tbl WHERE a = 3;
|
||||
SELECT count(*)>=0 FROM dist_tbl WHERE a = 4;
|
||||
SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'abcd';
|
||||
|
@ -272,7 +274,7 @@ SELECT select_from_dist_tbl_text('/b*c/de');
|
|||
SELECT select_from_dist_tbl_text(U&'\0061\0308bc');
|
||||
SELECT select_from_dist_tbl_text(U&'\0061\0308bc');
|
||||
|
||||
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants;
|
||||
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants ORDER BY tenant_attribute;
|
||||
|
||||
CREATE OR REPLACE PROCEDURE select_from_dist_tbl_text_proc(
|
||||
p_keyword text
|
||||
|
@ -295,7 +297,7 @@ CALL citus_stat_tenants.select_from_dist_tbl_text_proc(U&'\0061\0308bc');
|
|||
CALL citus_stat_tenants.select_from_dist_tbl_text_proc(U&'\0061\0308bc');
|
||||
CALL citus_stat_tenants.select_from_dist_tbl_text_proc(NULL);
|
||||
|
||||
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants;
|
||||
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants ORDER BY tenant_attribute;
|
||||
|
||||
CREATE OR REPLACE VIEW
|
||||
select_from_dist_tbl_text_view
|
||||
|
@ -309,7 +311,7 @@ SELECT count(*)>=0 FROM select_from_dist_tbl_text_view WHERE a = U&'\0061\0308bc
|
|||
SELECT count(*)>=0 FROM select_from_dist_tbl_text_view WHERE a = U&'\0061\0308bc';
|
||||
SELECT count(*)>=0 FROM select_from_dist_tbl_text_view WHERE a = U&'\0061\0308bc';
|
||||
|
||||
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants;
|
||||
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants ORDER BY tenant_attribute;
|
||||
|
||||
SET client_min_messages TO ERROR;
|
||||
DROP SCHEMA citus_stat_tenants CASCADE;
|
||||
|
|
Loading…
Reference in New Issue