mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 14:15:49 -06:00
Added collection of waiting events.
В окне "Status server" при получении информации о процессах добавлен сбор событий ожидания. Должно быть установлено расширение pg_wait_sampling. И правильно настроены параметры. Для примера минимальный размер буфера: при частоте опроса 1 сек (1000мс), количестве процессов 100 (num_p), pg_wait_sampling.history_period=10 Значение pg_wait_sampling.history_size = 1000 /10 * 100 = 10000 для 3-х кратного запаса можно взять 30000. Ожидание ClientRead немного изменено и означает, ожидание данных от клиента в НАЧАТОЙ ТРАНЗАКЦИИ. События ожидания можно сохранить в текстовый файл. В настройках pgadmin3opt.json можно выбрать цвета для отдельных событий или отключить сбор.
This commit is contained in:
parent
1e121c1fa0
commit
450c00ea90
8 changed files with 5281 additions and 712 deletions
195
include/utils/WaitSample.h
Normal file
195
include/utils/WaitSample.h
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
struct Sample
|
||||
{
|
||||
int btime;
|
||||
int etime;
|
||||
int wait_id;
|
||||
int pid;
|
||||
int btype; // backend_type = 0 Client backend
|
||||
long long qid;
|
||||
int samples;
|
||||
};
|
||||
enum iswhat {
|
||||
WAIT_FULL,
|
||||
WAIT_GRP,
|
||||
WAIT_NAME
|
||||
} ;
|
||||
/// <summary>
|
||||
/// qid,wait_id,pid
|
||||
/// </summary>
|
||||
struct key3 {
|
||||
long long qid;
|
||||
int w, pid;
|
||||
int sum;
|
||||
|
||||
bool const operator==(const key3& o) const {
|
||||
return qid == o.qid && w == o.w && pid==o.pid;
|
||||
}
|
||||
bool const cmp2field(const key3& o) const {
|
||||
return qid == o.qid && w == o.w;
|
||||
}
|
||||
|
||||
bool const operator<(const key3& o) const {
|
||||
return qid < o.qid || (qid == o.qid && w < o.w)|| (qid == o.qid && w == o.w && pid<o.pid);
|
||||
}
|
||||
};
|
||||
/// <summary>
|
||||
/// compare pid,wait,qid
|
||||
/// </summary>
|
||||
struct key3p {
|
||||
long long qid;
|
||||
int w, pid;
|
||||
int sum;
|
||||
|
||||
bool const operator==(const key3p& o) const {
|
||||
return qid == o.qid && w == o.w && pid == o.pid;
|
||||
}
|
||||
bool const cmp2field(const key3p& o) const {
|
||||
return qid == o.qid && w == o.w;
|
||||
}
|
||||
|
||||
bool const operator<(const key3p& o) const {
|
||||
return pid < o.pid || (pid == o.pid && w < o.w) || (pid == o.pid && w == o.w && qid < o.qid);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<int> vec_int;
|
||||
class WaitSample
|
||||
{
|
||||
private:
|
||||
int periodms = 10;
|
||||
int history_size;
|
||||
wxJSONValue opt;
|
||||
std::map<int, int> pids;
|
||||
std::map<int, int> chkpids;
|
||||
//
|
||||
std::vector<wxString> btype = { "client backend","background writer","checkpointer"
|
||||
,"walreceiver","walsender","walwriter","autovacuum launcher","autovacuum worker"
|
||||
,"logical replication launcher","logical replication worker","parallel worker"
|
||||
,"archiver","startup" };
|
||||
std::vector<wxString> btypeshort = { "CL","BGW","CKP"
|
||||
,"walR","walS","walW","avL","avW"
|
||||
,"lrL","lrW","pW"
|
||||
,"ARC","startup" };
|
||||
std::map<long long, wxString> qid_sql;
|
||||
std::map<wxString, long> wait_idx; // mapping wait_name -> color rgb
|
||||
std::map<wxString, int> wait_disable;
|
||||
std::map<wxString, int> wait_id;
|
||||
std::map<int, wxString> wait_id_name; // number wait -> full name wait
|
||||
std::vector<int> colors; // mapping colors[wait_id] -> color rgb
|
||||
std::vector<wxString> group;
|
||||
std::vector<Sample> smp; //
|
||||
std::vector<Sample> tmp_smp; //
|
||||
long long basetime = 0;
|
||||
int timebegiserios = 0, timeendserios = 0;
|
||||
int start_index_serios;
|
||||
/// <summary>
|
||||
/// Получение номера группы по имени группы.
|
||||
/// </summary>
|
||||
/// <param name="wclass"></param>
|
||||
/// <returns></returns>
|
||||
int wait_class(wxString wclass);
|
||||
public:
|
||||
void SaveFileSamples();
|
||||
void LoadFileSamples();
|
||||
bool AddQuery(long long qid, wxString sql);
|
||||
wxString GetQueryByQid(long long qid);
|
||||
/// <summary>
|
||||
/// Получить Id backend_type
|
||||
/// Если неизвестный backend_type то он получит новый ID
|
||||
/// </summary>
|
||||
/// <param name="backend_type"></param>
|
||||
/// <returns></returns>
|
||||
int GetBackendTypeId(wxString backend_type);
|
||||
wxString GetBackendTypeName(int backend_id) {
|
||||
return btype[backend_id];
|
||||
};
|
||||
wxString GetBackendTypeNameShort(int backend_id) {
|
||||
return backend_id>=btypeshort.size() ? GetBackendTypeName(backend_id): btypeshort[backend_id];
|
||||
};
|
||||
/// <summary>
|
||||
/// Получение индекса цвета по полному имени ожидания
|
||||
/// Если для ожидание нет цвета то используется цвет группы
|
||||
/// </summary>
|
||||
/// <param name="wait_name">Полное имя ожидания</param>
|
||||
/// <returns>Индекс в массиве colors</returns>
|
||||
long GetColorByWaitName(wxString wait_name) {
|
||||
auto clr = wait_idx.find(wait_name);
|
||||
if (clr == wait_idx.end()) {
|
||||
wxString grp_name = wait_name.BeforeFirst(':');
|
||||
clr = wait_idx.find(grp_name);
|
||||
}
|
||||
|
||||
return clr->second;
|
||||
};
|
||||
/// <summary>
|
||||
/// Получение Текстового имени ожидания
|
||||
/// </summary>
|
||||
/// <param name="wait_id">Ид ожидания</param>
|
||||
/// <param name="isGrp">WAIT_FULL - полное имя,WAIT_GRP - группа, WAIT_NAME - имя ожидания </param>
|
||||
/// <returns></returns>
|
||||
wxString GetName(int wait_id, iswhat isGrp) {
|
||||
wxString n = wait_id_name[wait_id];
|
||||
if (isGrp == WAIT_FULL) return n;
|
||||
wxString grp_name = n.BeforeFirst(':');
|
||||
if (grp_name.IsEmpty()) return n;
|
||||
if (isGrp==WAIT_GRP) return grp_name;
|
||||
else
|
||||
return n.AfterFirst(':');
|
||||
};
|
||||
int GetCountWaits() { return wait_id.size(); }
|
||||
inline int d_time(long long ms) {
|
||||
return ms - basetime;
|
||||
}
|
||||
std::vector<Sample>* GetSamples();
|
||||
std::vector<int> GetColors();
|
||||
/// <summary>
|
||||
/// Получение начальной границы интервала для переданного времени.
|
||||
/// </summary>
|
||||
/// <param name="timeEnd">-1 текущая левая граница, или время</param>
|
||||
/// <param name="AggrigateInterval"> Агрегирующий интервал</param>
|
||||
/// <returns>Время начала интервала.</returns>
|
||||
int GetHomeInterval(int timeEnd, int AggrigateInterval);
|
||||
int GetInterval(int posStart, int posEnd);
|
||||
wxArrayString GetWaitIdNameArray(bool onlyGroup);
|
||||
int GetGroupingData(int timeEnd, // -1 для правой границы
|
||||
int needCountGroup, // сколько интервалов получить
|
||||
int groupInterval, // 1 min, 5 min, 10 min, 20 min, 30 min, 1 hour
|
||||
wxString groupRule, // как проводить групировку
|
||||
wxArrayString& nameGroup, // эаполняет именами ожиданий или групп ожиданий
|
||||
std::vector<wxDateTime>& xAxisValue,// границы интервалов
|
||||
std::vector<wxTimeSpan>& yAxisValue,
|
||||
std::vector<vec_int>& Values,
|
||||
std::vector<long>& clr
|
||||
);
|
||||
/// <summary>
|
||||
/// Получение позиции в массиве по указанному времени
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
/// <returns></returns>
|
||||
int getPositionByTime(int time);
|
||||
inline int getPeriod() { return periodms; }
|
||||
void SetConfig(long periodmills, long history_size) {
|
||||
periodms = periodmills;
|
||||
this->history_size = history_size;
|
||||
};
|
||||
void Init();
|
||||
|
||||
WaitSample() {
|
||||
//c2.FromString("#3644ff");
|
||||
Init();
|
||||
};
|
||||
void BeginSeriosSample(long long timeserios) {
|
||||
chkpids.clear();
|
||||
if (basetime == 0) basetime = timeserios;
|
||||
timebegiserios = timeendserios;
|
||||
timeendserios = d_time(timeserios);
|
||||
start_index_serios = smp.size();
|
||||
|
||||
}
|
||||
void EndSeriosSample();
|
||||
void AddSample(int pid, bool isXidTransation, wxString& active, const wxString& sample);
|
||||
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue