diff --git a/src/common/backend/catalog/builtin_funcs.ini b/src/common/backend/catalog/builtin_funcs.ini index 3b8a187d12d7af4aa59b29e7c7d75702e1713849..370c7c4e23bcf5ce66d1667575bba766c50139b8 100755 --- a/src/common/backend/catalog/builtin_funcs.ini +++ b/src/common/backend/catalog/builtin_funcs.ini @@ -3743,6 +3743,10 @@ "gs_is_recycle_obj", 1, AddBuiltinFunc(_0(4896), _1("gs_is_recycle_obj"), _2(3), _3(false), _4(false), _5(gs_is_recycle_obj), _6(16), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(3, 26, 26, 19), _21(4, 26, 26, 19, 16), _22(4, 'i', 'i', 'i', 'o'), _23(4, "classid", "objid", "objname", "output_result"), _24(NULL), _25("gs_is_recycle_obj"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), + AddFuncGroup( + "gs_lwlock_status", 1, + AddBuiltinFunc(_0(8888), _1("gs_lwlock_status"), _2(0), _3(false), _4(true), _5(gs_lwlock_status), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(1000), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(0), _21(9, 25, 25, 20, 20, 20, 25, 25, 16, 1184), _22(9, 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o'), _23(9, "node_name", "lock_name", "lock_unique_id", "pid", "sessionid", "global_sessionid","mode", "granted", "start_time"), _24(NULL), _25("gs_lwlock_status"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(false), _32(false), _33("View system lwlock information"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), AddFuncGroup( "gs_parse_page_bypath", 1, AddBuiltinFunc(_0(2620), _1("gs_parse_page_bypath"), _2(4), _3(true), _4(false), _5(gs_parse_page_bypath), _6(25), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(4, 25, 20, 25, 16), _21(5, 25, 20, 25, 16, 25), _22(5, 'i', 'i', 'i', 'i', 'o'), _23(5, "path", "blocknum", "relation_type", "read_memory", "output_filepath"), _24(NULL), _25("gs_parse_page_bypath"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("parse data page to output file based on given filepath"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) diff --git a/src/common/backend/utils/error/be_module.cpp b/src/common/backend/utils/error/be_module.cpp index f74db8b61a002097b93ae88d9240a140065173be..91ae32152b2ad4b60d9594d87fef17452eecef6c 100755 --- a/src/common/backend/utils/error/be_module.cpp +++ b/src/common/backend/utils/error/be_module.cpp @@ -136,6 +136,7 @@ const module_data module_map[] = {{MOD_ALL, "ALL"}, {MOD_GPI, "GPI"}, {MOD_PARTITION, "PARTITION"}, {MOD_SRF, "SRF"}, + {MOD_LWLOCK, "LWLOCK"}, /* add your module name above */ {MOD_MAX, "BACKEND"}}; diff --git a/src/common/backend/utils/init/globals.cpp b/src/common/backend/utils/init/globals.cpp index 09eca49f2d84b69589b64cec0e7b8526a7a1aa02..2f4661e2db41566cffefc60294ad418a0be8fc1f 100644 --- a/src/common/backend/utils/init/globals.cpp +++ b/src/common/backend/utils/init/globals.cpp @@ -74,7 +74,7 @@ bool will_shutdown = false; * NEXT | 92899 | ? | ? * ********************************************/ -const uint32 GRAND_VERSION_NUM = 92863; +const uint32 GRAND_VERSION_NUM = 92864; /******************************************** * 2.VERSION NUM FOR EACH FEATURE diff --git a/src/gausskernel/process/postmaster/pgstat.cpp b/src/gausskernel/process/postmaster/pgstat.cpp index 1933054d189e71b70e63de50634b12be32f52f36..50bd58e2d2631350e2af194fbe23f63e84ca63ba 100644 --- a/src/gausskernel/process/postmaster/pgstat.cpp +++ b/src/gausskernel/process/postmaster/pgstat.cpp @@ -3169,8 +3169,10 @@ void pgstat_bestart(void) beentry->lw_count++; } while (CHANGECOUNT_IS_EVEN(beentry->lw_count)); beentry->lw_want_lock = NULL; + beentry->lw_want_start_time = (TimestampTz)0; beentry->lw_held_num = get_held_lwlocks_num(); beentry->lw_held_locks = get_held_lwlocks(); + beentry->lw_held_times = get_lwlock_held_times(); beentry->st_lw_access_flag = false; beentry->st_lw_is_cleanning_flag = false; @@ -3294,6 +3296,7 @@ void pgstat_couple_decouple_session(bool is_couple) beentry->st_tid = is_couple ? gettid() : 0; beentry->lw_held_num = is_couple ? get_held_lwlocks_num() : NULL; beentry->lw_held_locks = is_couple ? get_held_lwlocks() : NULL; + beentry->lw_held_times = is_couple ? get_lwlock_held_times() : NULL; /* make this count be odd */ do { beentry->lw_count++; diff --git a/src/gausskernel/process/threadpool/knl_thread.cpp b/src/gausskernel/process/threadpool/knl_thread.cpp index 298e0935bc1848d7ecd653945c20e4040f739551..70b827f07846c750a8d68840c5d8e81c51948dc9 100755 --- a/src/gausskernel/process/threadpool/knl_thread.cpp +++ b/src/gausskernel/process/threadpool/knl_thread.cpp @@ -1406,6 +1406,8 @@ static void knl_t_storage_init(knl_t_storage_context* storage_cxt) storage_cxt->isSwitchoverLockHolder = false; storage_cxt->num_held_lwlocks = 0; storage_cxt->held_lwlocks = (LWLockHandle*)palloc0(MAX_SIMUL_LWLOCKS * sizeof(LWLockHandle)); + storage_cxt->lwlock_held_times = (TimestampTz*)palloc0(MAX_SIMUL_LWLOCKS * sizeof(TimestampTz)); + storage_cxt->trace_lwlock_time = false; storage_cxt->lock_addin_request = 0; storage_cxt->lock_addin_request_allowed = true; storage_cxt->counts_for_pid = 0; diff --git a/src/gausskernel/storage/access/transam/xact.cpp b/src/gausskernel/storage/access/transam/xact.cpp index 6670768714f5684e784295d407f40c7bd7096466..cf2c3f77e53cc72c9e69f390691991d910d1d6da 100755 --- a/src/gausskernel/storage/access/transam/xact.cpp +++ b/src/gausskernel/storage/access/transam/xact.cpp @@ -2545,6 +2545,7 @@ static void StartTransaction(bool begin_on_gtm) CallXactCallbacks(XACT_EVENT_START); #endif + t_thrd.storage_cxt.trace_lwlock_time = module_logging_is_on(MOD_LWLOCK); if (module_logging_is_on(MOD_TRANS_XACT)) { ereport(LOG, (errmodule(MOD_TRANS_XACT), errmsg("start transaction succ. In Node %s, trans state: %s -> %s.", @@ -3151,6 +3152,7 @@ static void CommitTransaction(bool STP_commit) oldstate = s->state; s->state = TRANS_DEFAULT; + t_thrd.storage_cxt.trace_lwlock_time = false; if (module_logging_is_on(MOD_TRANS_XACT)) { ereport(LOG, (errmodule(MOD_TRANS_XACT), errmsg("Local Node %s: local commit process completed, trans state : %s -> %s", @@ -3585,6 +3587,7 @@ static void PrepareTransaction(bool STP_commit) * back to default */ s->state = TRANS_DEFAULT; + t_thrd.storage_cxt.trace_lwlock_time = false; RESUME_INTERRUPTS(); @@ -4027,6 +4030,7 @@ static void AbortTransaction(bool PerfectRollback, bool STP_rollback) t_thrd.xact_cxt.callPrint = false; u_sess->catalog_cxt.myLobTempToastNamespace = InvalidOid; u_sess->plsql_cxt.ActiveLobToastOid = InvalidOid; + t_thrd.storage_cxt.trace_lwlock_time = false; } static void CleanupTransaction(void) diff --git a/src/gausskernel/storage/lmgr/lwlock.cpp b/src/gausskernel/storage/lmgr/lwlock.cpp index 31c7c2c4a3c89e1d91551f7e508e00b1ea5d0b62..178eee5b6dd74d3df4c8ba77e4cb216baf5a1660 100644 --- a/src/gausskernel/storage/lmgr/lwlock.cpp +++ b/src/gausskernel/storage/lmgr/lwlock.cpp @@ -73,9 +73,11 @@ #include "access/csnlog.h" #include "access/multixact.h" #include "access/subtrans.h" +#include "access/tableam.h" #include "access/ustore/undo/knl_uundoapi.h" #include "commands/async.h" #include "commands/copy.h" +#include "funcapi.h" #include "lib/ilist.h" #include "miscadmin.h" #include "pg_trace.h" @@ -86,6 +88,7 @@ #include "storage/lock/lwlock_be.h" #include "storage/predicate.h" #include "storage/proc.h" +#include "storage/procarray.h" #include "storage/lock/s_lock.h" #include "storage/spin.h" #include "storage/cucache_mgr.h" @@ -1303,7 +1306,7 @@ bool LWLockAcquire(LWLock *lock, LWLockMode mode, bool need_update_lockid) ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("too many LWLocks taken"))); } - remember_lwlock_acquire(lock); + remember_lwlock_acquire(lock, mode); /* * Lock out cancel/die interrupts until we exit the code section protected @@ -1430,7 +1433,10 @@ bool LWLockAcquire(LWLock *lock, LWLockMode mode, bool need_update_lockid) /* Add lock to list of locks held by this backend */ t_thrd.storage_cxt.held_lwlocks[t_thrd.storage_cxt.num_held_lwlocks].lock = lock; - t_thrd.storage_cxt.held_lwlocks[t_thrd.storage_cxt.num_held_lwlocks++].mode = mode; + t_thrd.storage_cxt.held_lwlocks[t_thrd.storage_cxt.num_held_lwlocks].mode = mode; + t_thrd.storage_cxt.lwlock_held_times[t_thrd.storage_cxt.num_held_lwlocks] = + t_thrd.storage_cxt.trace_lwlock_time ? GetCurrentTimestamp() : 0; + t_thrd.storage_cxt.num_held_lwlocks++; /* * Fix the process wait semaphore's count for any absorbed wakeups. @@ -1479,7 +1485,10 @@ bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode) } else { /* Add lock to list of locks held by this backend */ t_thrd.storage_cxt.held_lwlocks[t_thrd.storage_cxt.num_held_lwlocks].lock = lock; - t_thrd.storage_cxt.held_lwlocks[t_thrd.storage_cxt.num_held_lwlocks++].mode = mode; + t_thrd.storage_cxt.held_lwlocks[t_thrd.storage_cxt.num_held_lwlocks].mode = mode; + t_thrd.storage_cxt.lwlock_held_times[t_thrd.storage_cxt.num_held_lwlocks] = + t_thrd.storage_cxt.trace_lwlock_time ? GetCurrentTimestamp() : 0; + t_thrd.storage_cxt.num_held_lwlocks++; TRACE_POSTGRESQL_LWLOCK_CONDACQUIRE(T_NAME(lock), mode); } return !mustwait; @@ -1543,7 +1552,7 @@ bool LWLockAcquireOrWait(LWLock *lock, LWLockMode mode) #ifdef LWLOCK_STATS lwstats->block_count++; #endif - remember_lwlock_acquire(lock); + remember_lwlock_acquire(lock, mode); for (;;) { /* "false" means cannot accept cancel/die interrupt here. */ @@ -1599,7 +1608,10 @@ bool LWLockAcquireOrWait(LWLock *lock, LWLockMode mode) LOG_LWDEBUG("LWLockAcquireOrWait", lock, "succeeded"); /* Add lock to list of locks held by this backend */ t_thrd.storage_cxt.held_lwlocks[t_thrd.storage_cxt.num_held_lwlocks].lock = lock; - t_thrd.storage_cxt.held_lwlocks[t_thrd.storage_cxt.num_held_lwlocks++].mode = mode; + t_thrd.storage_cxt.held_lwlocks[t_thrd.storage_cxt.num_held_lwlocks].mode = mode; + t_thrd.storage_cxt.lwlock_held_times[t_thrd.storage_cxt.num_held_lwlocks] = + t_thrd.storage_cxt.trace_lwlock_time ? GetCurrentTimestamp() : 0; + t_thrd.storage_cxt.num_held_lwlocks++; TRACE_POSTGRESQL_LWLOCK_WAIT_UNTIL_FREE(T_NAME(lock), mode); } @@ -1809,6 +1821,7 @@ void LWLockRelease(LWLock *lock) uint64 oldstate; bool check_waiters = false; int i; + TimestampTz now = t_thrd.storage_cxt.trace_lwlock_time ? GetCurrentTimestamp() : (TimestampTz)0; /* Remove lock from list of locks held. Usually, but not always, it will * be the latest-acquired lock; so search array backwards. */ @@ -1821,9 +1834,22 @@ void LWLockRelease(LWLock *lock) if (i < 0) { ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("lock %s is not held", T_NAME(lock)))); } + /* if lwlock is held longer than 1min, ereport the detail and backtrace */ + if (t_thrd.storage_cxt.trace_lwlock_time && + TimestampDifferenceExceeds(t_thrd.storage_cxt.lwlock_held_times[i], now, MSECS_PER_MIN)) { + force_backtrace_messages = true; + int old_backtrace_min_messages = u_sess->attr.attr_common.backtrace_min_messages; + u_sess->attr.attr_common.backtrace_min_messages = LOG; + ereport(LOG, (errmodule(MOD_LWLOCK), (errmsg("lwlock %s mode %d is held " + "for %ld ms longer than 1 min", T_NAME(lock), (int)(t_thrd.storage_cxt.held_lwlocks[i].mode), + now - t_thrd.storage_cxt.lwlock_held_times[i])))); + u_sess->attr.attr_common.backtrace_min_messages = old_backtrace_min_messages; + } + t_thrd.storage_cxt.num_held_lwlocks--; for (; i < t_thrd.storage_cxt.num_held_lwlocks; i++) { t_thrd.storage_cxt.held_lwlocks[i] = t_thrd.storage_cxt.held_lwlocks[i + 1]; + t_thrd.storage_cxt.lwlock_held_times[i] = t_thrd.storage_cxt.lwlock_held_times[i + 1]; } PRINT_LWDEBUG("LWLockRelease", lock, mode); @@ -1980,7 +2006,11 @@ void LWLockOwn(LWLock *lock) ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("lock %s is not held", T_NAME(lock)))); } - t_thrd.storage_cxt.held_lwlocks[t_thrd.storage_cxt.num_held_lwlocks++].lock = lock; + t_thrd.storage_cxt.held_lwlocks[t_thrd.storage_cxt.num_held_lwlocks].lock = lock; + t_thrd.storage_cxt.lwlock_held_times[t_thrd.storage_cxt.num_held_lwlocks] = + t_thrd.storage_cxt.trace_lwlock_time ? GetCurrentTimestamp() : 0; + + t_thrd.storage_cxt.num_held_lwlocks++; HOLD_INTERRUPTS(); } @@ -2000,6 +2030,7 @@ void LWLockDisown(LWLock *lock) { uint64 expected_state; int i; + TimestampTz now = t_thrd.storage_cxt.trace_lwlock_time ? GetCurrentTimestamp() : (TimestampTz)0; /* Ensure that lock is held */ expected_state = pg_atomic_read_u64(&lock->state); @@ -2017,9 +2048,22 @@ void LWLockDisown(LWLock *lock) ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("lock %s is not held", T_NAME(lock)))); } + /* if lwlock is held longer than 1min, ereport the detail and backtrace */ + if (t_thrd.storage_cxt.trace_lwlock_time && + TimestampDifferenceExceeds(t_thrd.storage_cxt.lwlock_held_times[i], now, MSECS_PER_MIN)) { + force_backtrace_messages = true; + int old_backtrace_min_messages = u_sess->attr.attr_common.backtrace_min_messages; + u_sess->attr.attr_common.backtrace_min_messages = LOG; + ereport(LOG, (errmodule(MOD_LWLOCK), (errmsg("lwlock %s mode %d is held " + "for %ld ms longer than 1 min", T_NAME(lock), (int)(t_thrd.storage_cxt.held_lwlocks[i].mode), + now - t_thrd.storage_cxt.lwlock_held_times[i])))); + u_sess->attr.attr_common.backtrace_min_messages = old_backtrace_min_messages; + } + t_thrd.storage_cxt.num_held_lwlocks--; for (; i < t_thrd.storage_cxt.num_held_lwlocks; i++) { t_thrd.storage_cxt.held_lwlocks[i] = t_thrd.storage_cxt.held_lwlocks[i + 1]; + t_thrd.storage_cxt.lwlock_held_times[i] = t_thrd.storage_cxt.lwlock_held_times[i + 1]; } RESUME_INTERRUPTS(); @@ -2043,6 +2087,12 @@ void *get_held_lwlocks(void) return (void *)t_thrd.storage_cxt.held_lwlocks; } +/* get lwlock held times */ +void *get_lwlock_held_times(void) +{ + return (void *)t_thrd.storage_cxt.lwlock_held_times; +} + #define COPY_LWLOCK_HANDLE(src, dst) do { \ (dst)->lock_addr.lock = (src)->lock; \ (dst)->lock_sx = (src)->mode; \ @@ -2216,3 +2266,261 @@ void CheckLWLockPartNumRange(void) } } +const int GS_LWLOCK_STATUS_COL_NUM = 9; +typedef struct LWLockStatInfo { + lwlock_id_mode lwlock; + TimestampTz start_time; + bool granted; +} LWLockStatInfo; + +typedef struct LWLockInstanceData { + int lwlocks_num; /* number of locks held */ + LWLockStatInfo* lwlocks; /* lwlocks */ + ThreadId pid; /* pid of this PGPROC */ + uint64 sessionid; /* session id of this PGPROC */ + GlobalSessionId globalSessionId; /* global session id */ +} LWLockInstanceData; + +typedef struct LWLockData { + int nelements; /* The length of the array */ + LWLockInstanceData* lwlocks; +} LWLockData; + +typedef struct GsLWLockStatus { + LWLockData *lwLockData; + int currInstanceIdx; + int currLockInfoIdx; + TableDistributionInfo *remoteStatus; +} GsLWLockStatus; + +/* Get the head row */ +static TupleDesc GetGsLWLockStatusFuncTupleDesc() +{ + TupleDesc tupdesc = NULL; + tupdesc = CreateTemplateTupleDesc(GS_LWLOCK_STATUS_COL_NUM, false); + AttrNumber attrIdx = 1; + TupleDescInitEntry(tupdesc, attrIdx, "node_name", TEXTOID, -1, 0); + attrIdx++; + TupleDescInitEntry(tupdesc, attrIdx, "lock_name", TEXTOID, -1, 0); + attrIdx++; + TupleDescInitEntry(tupdesc, attrIdx, "lock_unique_id", INT8OID, -1, 0); + attrIdx++; + TupleDescInitEntry(tupdesc, attrIdx, "pid", INT8OID, -1, 0); + attrIdx++; + TupleDescInitEntry(tupdesc, attrIdx, "sessionid", INT8OID, -1, 0); + attrIdx++; + TupleDescInitEntry(tupdesc, attrIdx, "global_sessionid", TEXTOID, -1, 0); + attrIdx++; + TupleDescInitEntry(tupdesc, attrIdx, "mode", TEXTOID, -1, 0); + attrIdx++; + TupleDescInitEntry(tupdesc, attrIdx, "granted", BOOLOID, -1, 0); + attrIdx++; + TupleDescInitEntry(tupdesc, attrIdx, "start_time", TIMESTAMPTZOID, -1, 0); + return BlessTupleDesc(tupdesc); +} + +static void copy_lwlock_infos(void *held_locks, void *held_times, LWLockStatInfo *dst, int num_locks) +{ + LWLockHandle *src_locks = (LWLockHandle *)held_locks; + TimestampTz *src_times = (TimestampTz *)held_times; + for (int i = 0; i < num_locks; i++) { + dst[i].lwlock.lock_addr.lock = src_locks[i].lock; + dst[i].lwlock.lock_sx = src_locks[i].mode; + dst[i].start_time = src_times[i]; + dst[i].granted = true; + } +} + +static bool IsVaildBeentry(volatile PgBackendStatus *beentry) +{ + return (beentry->st_procpid > 0 || beentry->st_sessionid > 0); +} + +static void GetBeentryLWLockInfo(LWLockInstanceData *localEntry, volatile PgBackendStatus *beentry) +{ + for (;;) { + localEntry->lwlocks_num = 0; + localEntry->pid = 0; + localEntry->sessionid = 0; + int beforeChangeCount; + int afterChangeCount; + pgstat_save_changecount_before(beentry, beforeChangeCount); + /* the only Prerequisites is that thread is valid. */ + if (IsVaildBeentry(beentry)) { + int *lw_held_num = beentry->lw_held_num; + void *lw_held_locks = beentry->lw_held_locks; + void *lw_held_times = beentry->lw_held_times; + LWLock *lw_want_lock = beentry->lw_want_lock; + LWLockMode lw_want_mode = beentry->lw_want_mode; + TimestampTz lw_want_start_time = beentry->lw_want_start_time; + if (lw_held_num != NULL && lw_held_locks != NULL && lw_held_times != NULL) { + localEntry->lwlocks_num = *lw_held_num; + if ((uint32)localEntry->lwlocks_num > get_held_lwlocks_maxnum()) { + localEntry->lwlocks_num = 0; + break; + } + copy_lwlock_infos(lw_held_locks, lw_held_times, localEntry->lwlocks, localEntry->lwlocks_num); + } + if (lw_want_lock != NULL) { + localEntry->lwlocks[localEntry->lwlocks_num].lwlock.lock_addr.lock = lw_want_lock; + localEntry->lwlocks[localEntry->lwlocks_num].lwlock.lock_sx = lw_want_mode; + localEntry->lwlocks[localEntry->lwlocks_num].start_time = lw_want_start_time; + localEntry->lwlocks[localEntry->lwlocks_num].granted = false; + localEntry->lwlocks_num++; + } + localEntry->pid = beentry->st_procpid; + localEntry->sessionid = beentry->st_sessionid; + localEntry->globalSessionId.sessionId = beentry->globalSessionId.sessionId; + localEntry->globalSessionId.nodeId = beentry->globalSessionId.nodeId; + localEntry->globalSessionId.seq = beentry->globalSessionId.seq; + } + pgstat_save_changecount_after(beentry, afterChangeCount); + if (beforeChangeCount == afterChangeCount && (beforeChangeCount & 1) == 0) { + break; + } + /* Make sure we can break out of loop if stuck... */ + CHECK_FOR_INTERRUPTS(); + } +} + +static LWLockData* GetLWLockStatusData(void) +{ + volatile PgBackendStatus *beentry = t_thrd.shemem_ptr_cxt.BackendStatusArray + BackendStatusArray_size - 1; + LWLockData *data = (LWLockData *)palloc0(sizeof(LWLockData)); + if (!u_sess->attr.attr_common.pgstat_track_activities) { + ereport(INFO, (errmsg("The collection of information is disabled because track_activities is off."))); + data->nelements = 0; + return data; + } + LWLockInstanceData *localEntry = (LWLockInstanceData *)palloc0(sizeof(LWLockInstanceData)); + localEntry->lwlocks = (LWLockStatInfo *)palloc0((get_held_lwlocks_maxnum() + 1) * sizeof(LWLockStatInfo)); + Size totalLockInfoSize = sizeof(LWLockInstanceData) * BackendStatusArray_size; + data->lwlocks = (LWLockInstanceData *)palloc0(totalLockInfoSize); + for (int i = 1; i <= BackendStatusArray_size; ++i) { + GetBeentryLWLockInfo(localEntry, beentry); + /* Only valid entries get included into the local array */ + if (localEntry->lwlocks_num > 0 && (localEntry->pid > 0 || localEntry->sessionid > 0)) { + data->lwlocks[data->nelements].lwlocks_num = localEntry->lwlocks_num; + Size lockSize = localEntry->lwlocks_num * sizeof(LWLockStatInfo); + data->lwlocks[data->nelements].lwlocks = (LWLockStatInfo *)palloc(lockSize); + errno_t errorno = memcpy_s(data->lwlocks[data->nelements].lwlocks, lockSize, localEntry->lwlocks, lockSize); + securec_check(errorno, "", ""); + data->lwlocks[data->nelements].pid = localEntry->pid; + data->lwlocks[data->nelements].sessionid= localEntry->sessionid; + data->lwlocks[data->nelements].globalSessionId = localEntry->globalSessionId; + data->nelements++; + } + beentry--; + } + pfree(localEntry->lwlocks); + pfree(localEntry); + return data; +} + +static const char* GetLWLockModeType(LWLockMode mode) +{ + if (mode == LW_EXCLUSIVE) { + return "Exclusive"; + } else if (mode == LW_SHARED) { + return "Shared"; + } else if (mode == LW_WAIT_UNTIL_FREE) { + return "Wait until free"; + } else { + return "Unknown"; + } +} + +static uint64 GetLockIndex(LWLock* lockAddr) +{ + return (uint64)((char*)lockAddr - (char*)t_thrd.shemem_ptr_cxt.mainLWLockArray)/sizeof(LWLockPadded); +} + +Datum gs_lwlock_status(PG_FUNCTION_ARGS) +{ + FuncCallContext* funcctx = NULL; + GsLWLockStatus* mystatus = NULL; + LWLockData* lwLockData = NULL; + LWLockInstanceData* instance = NULL; + HeapTuple tuple = NULL; + Datum result; + Datum values[GS_LWLOCK_STATUS_COL_NUM]; + bool nulls[GS_LWLOCK_STATUS_COL_NUM]; + errno_t rc; + int i = 0; + + rc = memset_s(values, sizeof(values), 0, sizeof(values)); + securec_check(rc, "\0", "\0"); + rc = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); + securec_check(rc, "\0", "\0"); + + if (SRF_IS_FIRSTCALL()) { + MemoryContext oldcontext; + /* create a function context for cross-call persistence */ + funcctx = SRF_FIRSTCALL_INIT(); + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + funcctx->tuple_desc = GetGsLWLockStatusFuncTupleDesc(); + mystatus = (GsLWLockStatus*)palloc0(sizeof(GsLWLockStatus)); + funcctx->user_fctx = (void*)mystatus; + mystatus->lwLockData = GetLWLockStatusData(); + (void)MemoryContextSwitchTo(oldcontext); + } + funcctx = SRF_PERCALL_SETUP(); + mystatus = (GsLWLockStatus*)funcctx->user_fctx; + lwLockData = mystatus->lwLockData; + + while (mystatus->currInstanceIdx < lwLockData->nelements) { + instance = &lwLockData->lwlocks[mystatus->currInstanceIdx]; + Assert(instance->lwlocks_num > 0); + int curIdx = mystatus->currLockInfoIdx; + int attrIdx = 0; + bool skip = (instance->lwlocks[curIdx].lwlock.lock_addr.lock == NULL); + if (!skip) { + values[attrIdx++] = CStringGetTextDatum(g_instance.attr.attr_common.PGXCNodeName); + values[attrIdx++] = CStringGetTextDatum(T_NAME(instance->lwlocks[curIdx].lwlock.lock_addr.lock)); + values[attrIdx++] = Int64GetDatum(GetLockIndex(instance->lwlocks[curIdx].lwlock.lock_addr.lock)); + values[attrIdx++] = Int64GetDatum(instance->pid); + values[attrIdx++] = Int64GetDatum(instance->sessionid); + char* gId = GetGlobalSessionStr(instance->globalSessionId); + values[attrIdx++] = CStringGetTextDatum(gId); + pfree(gId); + values[attrIdx++] = CStringGetTextDatum(GetLWLockModeType(instance->lwlocks[curIdx].lwlock.lock_sx)); + values[attrIdx++] = BoolGetDatum(instance->lwlocks[curIdx].granted); + values[attrIdx] = TimestampTzGetDatum(instance->lwlocks[curIdx].start_time); + nulls[attrIdx] = (values[attrIdx] == 0); + } + mystatus->currLockInfoIdx++; + /* till the end, continue next instance */ + if (mystatus->currLockInfoIdx == instance->lwlocks_num) { + mystatus->currLockInfoIdx = 0; + mystatus->currInstanceIdx++; + pfree_ext(instance->lwlocks); + } + if (skip) { + continue; + } + tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); + result = HeapTupleGetDatum(tuple); + SRF_RETURN_NEXT(funcctx, result); + } + + if (IS_PGXC_COORDINATOR && !IsConnFromCoord() && mystatus->remoteStatus != NULL) { + Tuplestorestate *tupstore = (mystatus->remoteStatus)->state->tupstore; + TupleTableSlot *slot = (mystatus->remoteStatus)->slot; + + if (!tuplestore_gettupleslot(tupstore, true, false, slot)) { + FreeParallelFunctionState((mystatus->remoteStatus)->state); + ExecDropSingleTupleTableSlot(slot); + pfree_ext(mystatus->remoteStatus); + SRF_RETURN_DONE(funcctx); + } + for (i = 0; i < GS_LWLOCK_STATUS_COL_NUM; i++) { + values[i] = tableam_tslot_getattr(slot, (i + 1), &nulls[i]); + } + tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); + (void)ExecClearTuple(slot); + + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + } + SRF_RETURN_DONE(funcctx); +} + diff --git a/src/gausskernel/storage/lmgr/lwlock_be.cpp b/src/gausskernel/storage/lmgr/lwlock_be.cpp index c7a61315c4cef2687e45bf326e46dd4fcaf867d5..d8017c1dd0df7b17a1909f0a8e82cbe66a414c75 100644 --- a/src/gausskernel/storage/lmgr/lwlock_be.cpp +++ b/src/gausskernel/storage/lmgr/lwlock_be.cpp @@ -28,7 +28,7 @@ * remember lwlock to require before entering to lwlock * waiting loop. */ -void remember_lwlock_acquire(LWLock *lock) +void remember_lwlock_acquire(LWLock *lock, LWLockMode mode) { if (t_thrd.shemem_ptr_cxt.MyBEEntry) { volatile PgBackendStatus *beentry = t_thrd.shemem_ptr_cxt.MyBEEntry; @@ -38,6 +38,8 @@ void remember_lwlock_acquire(LWLock *lock) * because this function maybe called before pgstat_bestart() function. */ beentry->lw_want_lock = lock; + beentry->lw_want_mode = mode; + beentry->lw_want_start_time = t_thrd.storage_cxt.trace_lwlock_time ? GetCurrentTimestamp() : (TimestampTz)0; } } @@ -55,5 +57,6 @@ void forget_lwlock_acquire(void) * because this function may be called before pgstat_bestart() function. */ beentry->lw_want_lock = NULL; + beentry->lw_want_start_time = (TimestampTz)0; } } diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_864.sql b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_864.sql new file mode 100644 index 0000000000000000000000000000000000000000..5133a1b20fe69e4f81eb1b7cbe621af8c3ecdc03 --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_864.sql @@ -0,0 +1 @@ +DROP FUNCTION IF EXISTS pg_catalog.gs_lwlock_status() CASCADE; \ No newline at end of file diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_92_864.sql b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_92_864.sql new file mode 100644 index 0000000000000000000000000000000000000000..5133a1b20fe69e4f81eb1b7cbe621af8c3ecdc03 --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_92_864.sql @@ -0,0 +1 @@ +DROP FUNCTION IF EXISTS pg_catalog.gs_lwlock_status() CASCADE; \ No newline at end of file diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_92_864.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_92_864.sql new file mode 100644 index 0000000000000000000000000000000000000000..fee1ac28e1666c392d4c239d6884e648ff2649d0 --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_92_864.sql @@ -0,0 +1,15 @@ +DROP FUNCTION IF EXISTS pg_catalog.gs_lwlock_status() CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 8888; +CREATE FUNCTION pg_catalog.gs_lwlock_status +( + OUT node_name pg_catalog.text, + OUT lock_name pg_catalog.text, + OUT lock_unique_id pg_catalog.int8, + OUT pid pg_catalog.int8, + OUT sessionid pg_catalog.int8, + OUT global_sessionid pg_catalog.text, + OUT mode pg_catalog.text, + OUT granted pg_catalog.bool, + OUT start_time pg_catalog.timestamptz +) RETURNS SETOF record LANGUAGE INTERNAL STABLE as 'gs_lwlock_status'; +comment on function pg_catalog.gs_lwlock_status() is 'View system lwlock information'; diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_92_864.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_92_864.sql new file mode 100644 index 0000000000000000000000000000000000000000..2cdbdb540e23a1b90774677bc32576fd889447bc --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_92_864.sql @@ -0,0 +1,15 @@ +DROP FUNCTION IF EXISTS pg_catalog.gs_lwlock_status() CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 8888; +CREATE FUNCTION pg_catalog.gs_lwlock_status +( + OUT node_name pg_catalog.text, + OUT lock_name pg_catalog.text, + OUT lock_unique_id pg_catalog.int8, + OUT pid pg_catalog.int8, + OUT sessionid pg_catalog.int8, + OUT global_sessionid pg_catalog.text, + OUT mode pg_catalog.text, + OUT granted pg_catalog.bool, + OUT start_time pg_catalog.timestamptz +) RETURNS SETOF record LANGUAGE INTERNAL STABLE as 'gs_lwlock_status'; +comment on function pg_catalog.gs_lwlock_status() is 'View system lwlock information'; \ No newline at end of file diff --git a/src/include/knl/knl_thread.h b/src/include/knl/knl_thread.h index c772e10d178f7c096dc51db007d45f9630212417..13a7e8c657b48abdf75ae1deee89133a15191220 100755 --- a/src/include/knl/knl_thread.h +++ b/src/include/knl/knl_thread.h @@ -2763,6 +2763,9 @@ typedef struct knl_t_storage_context { bool isSwitchoverLockHolder; int num_held_lwlocks; struct LWLockHandle* held_lwlocks; + TimestampTz* lwlock_held_times; + bool trace_lwlock_time; + int lock_addin_request; bool lock_addin_request_allowed; int counts_for_pid; diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 4eb62d40accf2e706735e46c8d949fa4fb0f4849..84da7103b1074c600390e6e2f9b6e8e9f0e1d972 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -1645,10 +1645,14 @@ typedef struct PgBackendStatus { int lw_count; /* lwlock object now requiring */ LWLock* lw_want_lock; + LWLockMode lw_want_mode; + TimestampTz lw_want_start_time; /* all lwlocks held by this thread */ int* lw_held_num; /* point to num_held_lwlocks */ void* lw_held_locks; /* point to held_lwlocks[] */ + void* lw_held_times; /* point to lwlock_held_times[] */ + volatile bool st_lw_access_flag; /* valid flag */ volatile bool st_lw_is_cleanning_flag; /* is cleanning lw ptr */ diff --git a/src/include/storage/lock/lwlock.h b/src/include/storage/lock/lwlock.h index 86dcf187a87614fcbe946304f4b19b9816f0169d..650d213be57e22994c78fd85ad10d597bc4a3d48 100644 --- a/src/include/storage/lock/lwlock.h +++ b/src/include/storage/lock/lwlock.h @@ -431,6 +431,7 @@ extern void wakeup_victim(LWLock *lock, ThreadId victim_tid); extern int *get_held_lwlocks_num(void); extern uint32 get_held_lwlocks_maxnum(void); extern void* get_held_lwlocks(void); +extern void* get_lwlock_held_times(void); extern void copy_held_lwlocks(void* heldlocks, lwlock_id_mode* dst, int num_heldlocks); extern const char* GetLWLockIdentifier(uint32 classId, uint16 eventId); extern LWLockMode GetHeldLWLockMode(LWLock* lock); diff --git a/src/include/storage/lock/lwlock_be.h b/src/include/storage/lock/lwlock_be.h index 31b18e9b207ddf530b1f415c5fda0cc5c0b6877a..80e4bcb7fa44de19721399dfb1518d35bc2e419c 100644 --- a/src/include/storage/lock/lwlock_be.h +++ b/src/include/storage/lock/lwlock_be.h @@ -29,7 +29,7 @@ #include "knl/knl_variable.h" #include "storage/lock/lwlock.h" -extern void remember_lwlock_acquire(LWLock* lockid); +extern void remember_lwlock_acquire(LWLock* lockid, LWLockMode mode); extern void forget_lwlock_acquire(void); #endif // SRC_INCLUDE_STORAGE_LWLOCK_BE_H \ No newline at end of file diff --git a/src/include/utils/be_module.h b/src/include/utils/be_module.h index a2a0f3fee891c38e3ced91b5e8134e6833306cbd..5465533d2577bef7c6560652b387bf20edb9e371 100755 --- a/src/include/utils/be_module.h +++ b/src/include/utils/be_module.h @@ -149,6 +149,7 @@ enum ModuleId { MOD_GPI, /* debug info for global partition index */ MOD_PARTITION, MOD_SRF, /* debug info for SRF */ + MOD_LWLOCK, /* debug info for lwlock held longer than a threshold*/ /* * Add your module id above. diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 7eb7d52c3c3b835b563c668e9bdc2d9ce5886b17..abd24e030daa72ebda5f147eded6031a4c7f39e3 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -1480,6 +1480,7 @@ extern Datum pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS); extern Datum pg_advisory_unlock_int4(PG_FUNCTION_ARGS); extern Datum pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS); extern Datum pg_advisory_unlock_all(PG_FUNCTION_ARGS); +extern Datum gs_lwlock_status(PG_FUNCTION_ARGS); /* pgstatfuncs.cpp */ extern Datum gs_stack(PG_FUNCTION_ARGS);