mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05: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
1699
ctl/wxTopActivity.cpp
Normal file
1699
ctl/wxTopActivity.cpp
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
583
include/ctl/wxTopActivity.h
Normal file
583
include/ctl/wxTopActivity.h
Normal file
|
|
@ -0,0 +1,583 @@
|
|||
#pragma once
|
||||
#include <wx/wx.h>
|
||||
#include "utils/WaitSample.h"
|
||||
#include "wx/popupwin.h"
|
||||
#include "wx/dataview.h"
|
||||
#include "wx/headerctrl.h"
|
||||
#include <wx/tokenzr.h>
|
||||
#include <vector>
|
||||
//#include "utils/misc.h"
|
||||
// ----------------------------------------------------------------------------
|
||||
// MyCustomRendererText
|
||||
// ----------------------------------------------------------------------------
|
||||
extern std::vector<int> sort_vec_map(const std::vector<int>& src, int& sum);
|
||||
#define sepListWait ";"
|
||||
extern int s_pid_HIGHLIGH;
|
||||
class MyCustomRendererGraph : public wxDataViewCustomRenderer
|
||||
{
|
||||
public:
|
||||
// This renderer can be either activatable or editable, for demonstration
|
||||
// purposes. In real programs, you should select whether the user should be
|
||||
// able to activate or edit the cell and it doesn't make sense to switch
|
||||
// between the two -- but this is just an example, so it doesn't stop us.
|
||||
explicit MyCustomRendererGraph(wxDataViewCellMode mode, int column)
|
||||
: wxDataViewCustomRenderer("string", mode, wxALIGN_LEFT)
|
||||
{
|
||||
EnableEllipsize(wxELLIPSIZE_END);
|
||||
col = column;
|
||||
}
|
||||
|
||||
virtual bool Render(wxRect rect, wxDC* dc, int state) wxOVERRIDE
|
||||
{
|
||||
wxString l;
|
||||
wxRect orig = rect;
|
||||
if (col < 2) {
|
||||
l = m_value;
|
||||
if (m_value == "ffffffffffffffff" || m_value == "-1") {
|
||||
l = "SUM";
|
||||
RenderText(l, 0, rect, dc, state);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (col == 0) {
|
||||
if (m_value[0] == '*') {
|
||||
l = m_value.AfterFirst('*');
|
||||
|
||||
// wxFont fn = dc->GetFont().Italic();
|
||||
// wxDCFontChanger nfont(*dc, fn);
|
||||
dc->SetBrush(*wxLIGHT_GREY_BRUSH);
|
||||
dc->SetPen(*wxTRANSPARENT_PEN);
|
||||
rect.Deflate(1);
|
||||
dc->DrawRoundedRectangle(rect, 3);
|
||||
RenderText(l, 0, rect, dc, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
l = m_value;
|
||||
RenderText(l, 0, rect, dc, state);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
if (col == 1) {
|
||||
RenderText(l, 0, rect, dc, state);
|
||||
return true;
|
||||
}
|
||||
//dc->SetBrush( *wxLIGHT_GREY_BRUSH );
|
||||
dc->SetBrush(*wxYELLOW_BRUSH);
|
||||
//dc->SetPen(*wxTRANSPARENT_PEN);
|
||||
dc->SetPen(*wxBLACK_PEN);
|
||||
rect.Deflate(1);
|
||||
//WaitSample*ws= static_cast<topDataViewCtrl*>(GetView())->GetSample();
|
||||
//dc->DrawRoundedRectangle( rect, 3 );
|
||||
wxFont fn = dc->GetFont();
|
||||
fn.SetPointSize(fn.GetPointSize() - 1);
|
||||
wxDCFontChanger nfont(*dc, fn);
|
||||
|
||||
wxString s = m_value, t;
|
||||
wxStringTokenizer tk(s, sepListWait, wxTOKEN_DEFAULT);
|
||||
|
||||
bool isDis = true;
|
||||
bool isGrp = true;
|
||||
int f = 0;
|
||||
float itog = 0;
|
||||
int widt = orig.width - 20;
|
||||
wxPoint p(orig.x, orig.y);
|
||||
while (tk.HasMoreTokens())
|
||||
{
|
||||
l = tk.GetNextToken();
|
||||
if (f == 0) {
|
||||
float tmp;
|
||||
l = l.AfterLast(' ');
|
||||
wxSscanf(l, "%f", &tmp);
|
||||
itog = tmp;
|
||||
float sek = itog / 1000;
|
||||
wxString tt = wxString::Format("%.1f", sek); // time sec
|
||||
wxSize sz = GetTextExtent(tt);
|
||||
wxRect drw(orig.x + orig.width - sz.x - 2, orig.y, sz.x + 2, orig.GetHeight());
|
||||
wxRect npos(0, 0, sz.x, sz.y);
|
||||
npos = npos.CentreIn(drw);
|
||||
dc->DrawText(tt, npos.x, npos.y);
|
||||
widt = orig.width - sz.x - 2;
|
||||
}
|
||||
if (f > 0) {
|
||||
float tmp;
|
||||
wxString w;
|
||||
long cl;
|
||||
l = l.AfterFirst(' ');
|
||||
wxSscanf(l, "%ld %f", &cl, &tmp);
|
||||
|
||||
wxColour c(cl);
|
||||
//c.Set(cl);
|
||||
dc->SetBrush(c);
|
||||
|
||||
|
||||
int ww = widt * tmp;
|
||||
wxRect drw(p.x, p.y, ww, rect.GetHeight());
|
||||
float sek = itog * tmp / 1000;
|
||||
wxString tt = wxString::Format("%.1f", sek); // time sec
|
||||
wxSize sz = GetTextExtent(tt);
|
||||
wxRect npos(0, 0, sz.x, sz.y);
|
||||
npos = npos.CentreIn(drw);
|
||||
dc->DrawRectangle(drw);
|
||||
{
|
||||
wxColour fg(ContrastColorBlackOrWhite(c));
|
||||
wxDCTextColourChanger setfg(*dc, fg);
|
||||
if (sz.GetWidth() < drw.GetWidth()) dc->DrawText(tt, npos.x, npos.y);
|
||||
}
|
||||
p.x = p.x + ww;
|
||||
|
||||
}
|
||||
f++;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool ActivateCell(const wxRect& WXUNUSED(cell),
|
||||
wxDataViewModel* WXUNUSED(model),
|
||||
const wxDataViewItem& WXUNUSED(item),
|
||||
unsigned int WXUNUSED(col),
|
||||
const wxMouseEvent* mouseEvent) wxOVERRIDE
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual wxSize GetSize() const wxOVERRIDE
|
||||
{
|
||||
wxSize txtSize = GetTextExtent(m_value);
|
||||
int lines = m_value.Freq('\n') + 1;
|
||||
if (lines > 1) {
|
||||
// wxLogMessage("MyCustomRendererText GetSize() %s", position);
|
||||
txtSize.SetHeight(txtSize.GetHeight() * lines + 1 * lines);
|
||||
}
|
||||
else {
|
||||
#ifdef __WXGTK__
|
||||
txtSize.SetHeight(txtSize.GetHeight() + 3);
|
||||
#else
|
||||
txtSize.SetHeight(-1);
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
if (col == 2) txtSize.SetWidth(-1);
|
||||
else
|
||||
{
|
||||
//maxw = txtSize.GetWidth();
|
||||
//maxw=wxMax(txtSize.GetWidth(), maxw);
|
||||
txtSize.SetWidth(txtSize.GetWidth() + 1);
|
||||
}
|
||||
return txtSize;
|
||||
|
||||
//return GetView()->FromDIP(wxSize(60, 20));
|
||||
}
|
||||
|
||||
virtual bool SetValue(const wxVariant& value) wxOVERRIDE
|
||||
{
|
||||
m_value = value.GetString();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool GetValue(wxVariant& WXUNUSED(value)) const wxOVERRIDE { return true; }
|
||||
|
||||
#if wxUSE_ACCESSIBILITY
|
||||
virtual wxString GetAccessibleDescription() const wxOVERRIDE
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
#endif // wxUSE_ACCESSIBILITY
|
||||
|
||||
virtual bool HasEditorCtrl() const wxOVERRIDE { return false; }
|
||||
private:
|
||||
wxString m_value;
|
||||
int col;
|
||||
int maxw = -1;
|
||||
};
|
||||
|
||||
class MyIndexListModel : public wxDataViewIndexListModel
|
||||
{
|
||||
public:
|
||||
MyIndexListModel(WaitSample* w) { ws = w; }
|
||||
|
||||
void SetAllRows(const std::vector<key3>& keys, const std::map<key3, vec_int>& wait, bool isfp) {
|
||||
k = keys;
|
||||
w = wait;
|
||||
//IsFirstPid = isfp;
|
||||
|
||||
Reset(keys.size());
|
||||
|
||||
}
|
||||
key3 GetRowValue(long row) {
|
||||
key3 r{};
|
||||
if (row >= 0 && row < k.size()) {
|
||||
r = k[row];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
// Implement base class pure virtual methods.
|
||||
unsigned GetCount() const wxOVERRIDE { return k.size(); }
|
||||
void GetValueByRow(wxVariant& val, unsigned row, unsigned col) const wxOVERRIDE
|
||||
{
|
||||
//val=wxString::Format("r:%d,c:%d",row,col);
|
||||
//val = m_strings[row];
|
||||
//if (row + 1 < m_strings.Count() && col == 1 ) val = m_strings[row + 1];
|
||||
bool ishint = false;
|
||||
int r = row;
|
||||
if (!val.IsNull()) {
|
||||
//r = r * -1;
|
||||
ishint = true;
|
||||
}
|
||||
if (k.size() > 0) {
|
||||
key3 kk = k.at(r);
|
||||
if ((col == 0)) {
|
||||
long ttmp = kk.pid;
|
||||
if (kk.sum > 0) val = wxString::Format("*%ld", ttmp); // backend
|
||||
else
|
||||
val = wxString::Format("%ld", ttmp);
|
||||
|
||||
}
|
||||
else
|
||||
val = wxString::Format("%llx", kk.qid);
|
||||
if (col == 2) {
|
||||
vec_int v = w.at(kk);
|
||||
int sz = v.size();
|
||||
val = wxString::Format("count w=%d", sz);
|
||||
int itog = 0;
|
||||
std::vector<int> map_sum_all = sort_vec_map(v, itog);
|
||||
int period = ws->getPeriod();
|
||||
int total = itog;
|
||||
wxString h;
|
||||
if (total != 0) {
|
||||
wxString x = wxString::Format("all %ld", (long)itog * period);
|
||||
for (int i = 0; i < map_sum_all.size(); i++) {
|
||||
int wait_index = map_sum_all[i];
|
||||
if (v[wait_index] == 0) continue;
|
||||
float w_sum = (v[wait_index] / (float)total);
|
||||
float sek = ((period * v[wait_index]) / 1000.0);
|
||||
wxString w_name = ws->GetName(wait_index, WAIT_NAME);
|
||||
wxString w_grp = ws->GetName(wait_index, WAIT_GRP);
|
||||
wxString full = ws->GetName(wait_index, WAIT_FULL);
|
||||
long clr = ws->GetColorByWaitName(full);
|
||||
wxString pr = wxString::Format("%s %ld %.3f", w_name, clr, w_sum);
|
||||
if (ishint) {
|
||||
if (!h.IsEmpty()) h += "\n";
|
||||
h.Append(wxString::Format("%-8.1f%-15s", sek, w_name));
|
||||
}
|
||||
else {
|
||||
if (!x.IsEmpty()) x += sepListWait;
|
||||
x += pr;
|
||||
}
|
||||
}
|
||||
if (ishint) val = h;
|
||||
else
|
||||
val = x;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
bool SetValueByRow(const wxVariant&, unsigned, unsigned) wxOVERRIDE
|
||||
{
|
||||
return false;
|
||||
}
|
||||
unsigned GetRow(const wxDataViewItem& item) const wxOVERRIDE { return (unsigned long)item.GetID()-1; } // 0 row = header
|
||||
unsigned int GetColumnCount() const wxOVERRIDE { return 0; }
|
||||
wxString GetColumnType(unsigned int) const wxOVERRIDE { return ""; }
|
||||
|
||||
|
||||
private:
|
||||
bool IsFirstPid = true;
|
||||
std::vector<key3> k;
|
||||
std::map<key3, vec_int> w;
|
||||
WaitSample* ws = NULL;
|
||||
wxDECLARE_NO_COPY_CLASS(MyIndexListModel);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// SimpleTransientPopup
|
||||
//----------------------------------------------------------------------------
|
||||
class wxTopActivity;
|
||||
class topDataViewCtrl;
|
||||
|
||||
class SimpleTransientPopup : public wxFrame
|
||||
{
|
||||
public:
|
||||
friend class wxTopActivity;
|
||||
friend class topDataViewCtrl;
|
||||
SimpleTransientPopup(wxWindow* parent, bool scrolled, wxTopActivity* small_ctl, wxPoint p,wxString title);
|
||||
virtual ~SimpleTransientPopup();
|
||||
|
||||
// wxPopupTransientWindow virtual methods are all overridden to log them
|
||||
|
||||
private:
|
||||
wxScrolledWindow* m_panel;
|
||||
wxTopActivity* top;
|
||||
topDataViewCtrl* dvc;
|
||||
wxObjectDataPtr<MyIndexListModel> m_index_list_model;
|
||||
wxPoint mouseDownPos_;
|
||||
bool dragg = false;
|
||||
wxTimer m_taskTimer;
|
||||
private:
|
||||
void OnMouse(wxMouseEvent& event);
|
||||
void OnSize(wxSizeEvent& event);
|
||||
void OnSetFocus(wxFocusEvent& event);
|
||||
void OnKillFocus(wxFocusEvent& event);
|
||||
void OnTimerEvent(wxTimerEvent& pEvent);
|
||||
void OnClose(wxCommandEvent& event);
|
||||
|
||||
private:
|
||||
wxDECLARE_ABSTRACT_CLASS(SimpleTransientPopup);
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
||||
struct title_info {
|
||||
bool iner = false;
|
||||
bool remove;
|
||||
bool down_line;
|
||||
int total;
|
||||
wxString title;
|
||||
|
||||
};
|
||||
/// <summary>
|
||||
/// Графический элемент отображающий данные WaitSample
|
||||
/// Может использоваться в двух режимах.
|
||||
/// </summary>
|
||||
class wxTopActivity : public wxControl
|
||||
{
|
||||
WaitSample* ws;
|
||||
wxString m_title;
|
||||
wxSize setsize;
|
||||
wxArrayString seriosName;
|
||||
std::vector<wxDateTime> xAxis;
|
||||
std::vector<wxTimeSpan> yAxis;
|
||||
std::vector<vec_int> val;
|
||||
std::vector<long> colors;
|
||||
std::vector<title_info> m_title_i;
|
||||
std::map<wxString, int> m_collapse;
|
||||
std::map<wxString, int> m_sumtotal;
|
||||
wxPoint mouse, mouseS;
|
||||
wxRect m_area;
|
||||
int m_click = 0;
|
||||
int m_fix_detail_idx = -1;
|
||||
// fix sel Range
|
||||
wxDateTime fix_pos_L;
|
||||
wxDateTime fix_pos_R;
|
||||
|
||||
wxPoint m_fix_pos; // context win
|
||||
wxString m_filter_detail;
|
||||
long long m_qid_filter = -1;
|
||||
bool m_regroup = false;
|
||||
int m_lastInterval = 0;
|
||||
int m_RightTime = -1;
|
||||
wxString m_filter;
|
||||
int m_agg_int = 5000;
|
||||
int m_count_wait;
|
||||
int m_inter[9] = {
|
||||
5000 ,
|
||||
10000 ,
|
||||
30000 ,//30 s
|
||||
60000 ,//1 min
|
||||
5 * 60000 ,//5 min
|
||||
10 * 60000,//10 min
|
||||
15 * 60000,//10 min
|
||||
30 * 60000,//30 min
|
||||
60 * 60000 //60 min
|
||||
};
|
||||
SimpleTransientPopup* m_simplePopup;
|
||||
void paintSelRange(wxDC& dc, int width_sample);
|
||||
public:
|
||||
wxTopActivity(wxWindow* parent, WaitSample* WS, wxSize sz);
|
||||
wxSize DoGetBestClientSize();
|
||||
void setViewRange(int m_aggregate_interval, int RightTime);
|
||||
WaitSample* getViewRange(int& m_aggregate_interval, int& RightTime);
|
||||
void paintEvent(wxPaintEvent& evt);
|
||||
void OnEraseBackground(wxEraseEvent& event);
|
||||
void paintNow();
|
||||
void SetFilter(long long qid);
|
||||
/// <summary>
|
||||
/// Возвращает время указаной границы
|
||||
/// </summary>
|
||||
/// <param name="isLeftRange">true для левой границы, инаце правая</param>
|
||||
///
|
||||
int getTimeSelRange(bool isLeftRange);
|
||||
void render(wxDC& dc);
|
||||
|
||||
// some useful events
|
||||
void mouseMoved(wxMouseEvent& event);
|
||||
void mouseDown(wxMouseEvent& event);
|
||||
void mouseWheelMoved(wxMouseEvent& event);
|
||||
void mouseReleased(wxMouseEvent& event);
|
||||
void rightClick(wxMouseEvent& event);
|
||||
void mouseLeftWindow(wxMouseEvent& event);
|
||||
void keyPressed(wxKeyEvent& event);
|
||||
void keyReleased(wxKeyEvent& event);
|
||||
void resize(wxSizeEvent& event);
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
class topDataViewCtrl :
|
||||
public wxDataViewCtrl
|
||||
{
|
||||
public:
|
||||
topDataViewCtrl(wxWindow* parent, wxWindowID id,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize, long style = 0,
|
||||
wxTopActivity* topactive = NULL,
|
||||
const wxValidator& validator = wxDefaultValidator,
|
||||
const wxString& name = wxASCII_STR(wxDataViewCtrlNameStr)
|
||||
) : wxDataViewCtrl(parent, id, pos, size, style, validator, name)
|
||||
{
|
||||
//SetMinSize(wxSize(300,200));
|
||||
top = topactive;
|
||||
w = NULL;
|
||||
w = top->getViewRange(agg, right_g);
|
||||
Bind(wxEVT_DATAVIEW_COLUMN_HEADER_CLICK, [&](wxDataViewEvent& event) {
|
||||
int col = event.GetColumn();
|
||||
if (GetColumn(col)->GetTitle() == "PID") {
|
||||
ignoreBG = !ignoreBG;
|
||||
CalcRowsDataView(true, ispidfirst);
|
||||
Refresh();
|
||||
|
||||
}
|
||||
});
|
||||
Bind(wxEVT_DATAVIEW_ITEM_ACTIVATED, [&](wxDataViewEvent& event) {
|
||||
int col = event.GetColumn();
|
||||
wxDataViewItem item(event.GetItem());
|
||||
long row = (long)item.GetID();
|
||||
row--;
|
||||
if (col == 1) //qid
|
||||
{
|
||||
MyIndexListModel* m = static_cast<MyIndexListModel*>(GetModel());
|
||||
key3 k = m->GetRowValue(row);
|
||||
if (k.qid != -1) top->SetFilter(k.qid);
|
||||
}
|
||||
if (col == 0) { //pid
|
||||
MyIndexListModel* m = static_cast<MyIndexListModel*>(GetModel());
|
||||
key3 k = m->GetRowValue(row);
|
||||
if (k.pid>0) s_pid_HIGHLIGH = k.pid;
|
||||
// else
|
||||
// s_pid_HIGHLIGH = -1;
|
||||
}
|
||||
});
|
||||
|
||||
Bind(wxEVT_DATAVIEW_COLUMN_REORDERED, [&](wxDataViewEvent& event) {
|
||||
wxDataViewColumn* const col = event.GetDataViewColumn();
|
||||
if (!col)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ispidfirst = col->GetTitle() == "PID" && event.GetColumn() == 0;
|
||||
if (!ispidfirst) ispidfirst = col->GetTitle() == "QID" && event.GetColumn() == 1;
|
||||
CalcRowsDataView(true, ispidfirst);
|
||||
Refresh();
|
||||
});
|
||||
GetMainWindow()->Bind(wxEVT_MOTION, [&](wxMouseEvent& event) {
|
||||
if (event.Dragging())
|
||||
return;
|
||||
|
||||
wxClientDC dc(GetMainWindow());
|
||||
PrepareDC(dc);
|
||||
|
||||
//wxPoint logPos(event.GetLogicalPosition(dc));
|
||||
//wxPoint mc= GetMainWindow()->ScreenToClient(event.GetPosition());
|
||||
wxPoint mc = event.GetPosition();
|
||||
wxString position;
|
||||
//position = wxString::Format("x=%d y=%d", logPos.x, logPos.y);
|
||||
//wxLogMessage("Mouse pos %s", position);
|
||||
int dy = 0;
|
||||
wxSize sz;
|
||||
#ifdef WIN32
|
||||
wxHeaderCtrl* const header = GenericGetHeader();
|
||||
if (header) {
|
||||
sz = header->GetSize();
|
||||
//header->Refresh();
|
||||
dy = sz.GetHeight();
|
||||
}
|
||||
mc.y += dy;
|
||||
#else
|
||||
mc.y += 18; // only linux compile
|
||||
#endif
|
||||
wxDataViewItem item;
|
||||
wxDataViewColumn* column;
|
||||
|
||||
HitTest(mc, item, column);
|
||||
if (item != NULL && column != NULL)
|
||||
{
|
||||
int row = (long)item.GetID() - 1;
|
||||
int ncol = column->GetModelColumn();
|
||||
if (row >= 0) {
|
||||
if (column && column->GetModelColumn() == 2) {
|
||||
wxVariant vr;
|
||||
vr = "gethint";
|
||||
if ((lastcol != ncol) || (lastrow != row)) {
|
||||
MyIndexListModel* m = static_cast<MyIndexListModel*>(GetModel());
|
||||
m->GetValueByRow(vr, row, ncol);
|
||||
GetMainWindow()->SetToolTip(vr.GetString());
|
||||
lastrow = row;
|
||||
lastcol = ncol;
|
||||
}
|
||||
|
||||
}
|
||||
else if (column && column->GetModelColumn() == 0 ) {
|
||||
// PID
|
||||
MyIndexListModel* m = static_cast<MyIndexListModel*>(GetModel());
|
||||
key3 k=m->GetRowValue(row);
|
||||
if (k.sum > 0) {
|
||||
if (((lastcol != ncol) || (lastrow != row))) {
|
||||
wxString s = w->GetBackendTypeName(k.sum);
|
||||
GetMainWindow()->SetToolTip(s);
|
||||
lastrow = row;
|
||||
lastcol = ncol;
|
||||
|
||||
}
|
||||
}
|
||||
else { GetMainWindow()->UnsetToolTip(); lastcol = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GetMainWindow()->UnsetToolTip();
|
||||
lastcol = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GetMainWindow()->UnsetToolTip();
|
||||
lastcol = -1;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
WaitSample* GetSample() { return w; }
|
||||
void BuildColumn(int mode);
|
||||
bool CalcRowsDataView(bool force, bool IsPidFirst);
|
||||
//void AddRow(wxString csvtext);
|
||||
//void OnMouseMove(wxMouseEvent& event);
|
||||
//void OnMouseDown(wxMouseEvent& event);
|
||||
//void OnKEY_DOWN(wxKeyEvent& event);
|
||||
//void OnKEY_UP(wxKeyEvent& event);
|
||||
//void OnEVT_DATAVIEW_COLUMN_HEADER_CLICK(wxDataViewEvent& event);
|
||||
//void OnEVT_DATAVIEW_CONTEXT_MENU(wxCommandEvent& event);
|
||||
//void OnEVT_DATAVIEW_SELECTION_CHANGED(wxDataViewEvent& event);
|
||||
//void OnContextMenu(wxDataViewEvent& event);
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
|
||||
private:
|
||||
int lastrow = -1, lastcol = 1;
|
||||
int agg, right_g, left_g;
|
||||
bool ignoreBG = false;
|
||||
bool ispidfirst = true;
|
||||
wxTopActivity* top;
|
||||
WaitSample* w;
|
||||
};
|
||||
|
||||
#undef sepListWait
|
||||
|
||||
|
|
@ -94,7 +94,7 @@ protected:
|
|||
wxString dlgName;
|
||||
wxString lastFilename, lastDir, lastPath;
|
||||
wxString recentKey;
|
||||
wxMenu *fileMenu, *editMenu, *viewMenu, *recentFileMenu, *helpMenu;
|
||||
wxMenu *fileMenu, *editMenu, *viewMenu, *recentFileMenu, *helpMenu, *waitMenu;
|
||||
wxStatusBar *statusBar;
|
||||
wxMenuBar *menuBar;
|
||||
ctlMenuToolbar *toolBar;
|
||||
|
|
|
|||
|
|
@ -22,57 +22,63 @@
|
|||
// wxAUI
|
||||
#include <wx/aui/aui.h>
|
||||
|
||||
#include <wx/msgqueue.h>
|
||||
#include "dlg/dlgClasses.h"
|
||||
#include "utils/factory.h"
|
||||
#include "ctl/ctlAuiNotebook.h"
|
||||
#include "ctl/ctlNavigatePanel.h"
|
||||
#include "utils/WaitSample.h"
|
||||
#include "ctl/wxTopActivity.h"
|
||||
|
||||
enum
|
||||
{
|
||||
CTL_RATECBO = 250,
|
||||
CTL_REFRESHBTN,
|
||||
CTL_CANCELBTN,
|
||||
CTL_TERMINATEBTN,
|
||||
CTL_COMMITBTN,
|
||||
CTL_ROLLBACKBTN,
|
||||
CTL_LOGCBO,
|
||||
CTL_ROTATEBTN,
|
||||
CTL_STATUSLIST,
|
||||
CTL_LOCKLIST,
|
||||
CTL_XACTLIST,
|
||||
CTL_LOGLIST,
|
||||
CTL_QUERYSTATELIST,
|
||||
MNU_STATUSPAGE,
|
||||
MNU_LOCKPAGE,
|
||||
MNU_XACTPAGE,
|
||||
MNU_LOGPAGE,
|
||||
MNU_QUERYSTATEPAGE,
|
||||
MNU_TERMINATE,
|
||||
MNU_COMMIT,
|
||||
MNU_ROLLBACK,
|
||||
MNU_COPY_QUERY,
|
||||
MNU_CLEAR_FILTER_SERVER_STATUS,
|
||||
MNU_COPY_QUERY_PLAN,
|
||||
MNU_HIGHLIGHTSTATUS,
|
||||
MNU_QUERYSTATEVERBOSE,
|
||||
MNU_QUERYSTATETIME,
|
||||
MNU_QUERYSTATEBUFFER,
|
||||
MNU_QUERYSTATETRIGGER,
|
||||
TIMER_REFRESHUI_ID,
|
||||
TIMER_STATUS_ID,
|
||||
TIMER_LOCKS_ID,
|
||||
TIMER_XACT_ID,
|
||||
TIMER_LOG_ID,
|
||||
TIMER_QUERYSTATE_ID
|
||||
CTL_RATECBO = 250,
|
||||
CTL_REFRESHBTN,
|
||||
CTL_CANCELBTN,
|
||||
CTL_TERMINATEBTN,
|
||||
CTL_COMMITBTN,
|
||||
CTL_ROLLBACKBTN,
|
||||
CTL_LOGCBO,
|
||||
CTL_ROTATEBTN,
|
||||
CTL_STATUSLIST,
|
||||
CTL_LOCKLIST,
|
||||
CTL_XACTLIST,
|
||||
CTL_LOGLIST,
|
||||
CTL_QUERYSTATELIST,
|
||||
MNU_STATUSPAGE,
|
||||
MNU_LOCKPAGE,
|
||||
MNU_XACTPAGE,
|
||||
MNU_LOGPAGE,
|
||||
MNU_QUERYSTATEPAGE,
|
||||
MNU_TERMINATE,
|
||||
MNU_COMMIT,
|
||||
MNU_ROLLBACK,
|
||||
MNU_COPY_QUERY,
|
||||
MNU_CLEAR_FILTER_SERVER_STATUS,
|
||||
MNU_COPY_QUERY_PLAN,
|
||||
MNU_HIGHLIGHTSTATUS,
|
||||
MNU_QUERYSTATEVERBOSE,
|
||||
MNU_QUERYSTATETIME,
|
||||
MNU_QUERYSTATEBUFFER,
|
||||
MNU_QUERYSTATETRIGGER,
|
||||
MNU_WAITENABLE,
|
||||
MNU_WAITSAVE,
|
||||
TIMER_REFRESHUI_ID,
|
||||
TIMER_STATUS_ID,
|
||||
TIMER_LOCKS_ID,
|
||||
TIMER_XACT_ID,
|
||||
TIMER_LOG_ID,
|
||||
TIMER_QUERYSTATE_ID
|
||||
};
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PANE_STATUS = 1,
|
||||
PANE_LOCKS,
|
||||
PANE_XACT,
|
||||
PANE_LOG,
|
||||
PANE_QUERYSTATE
|
||||
PANE_STATUS = 1,
|
||||
PANE_LOCKS,
|
||||
PANE_XACT,
|
||||
PANE_LOG,
|
||||
PANE_QUERYSTATE
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -87,7 +93,7 @@ enum
|
|||
#ifdef __WXGTK__
|
||||
#define FRMSTATUS_DEFAULT_PERSPECTIVE wxT("layout2|name=Activity;caption=Activity;state=6309884;dir=4;layer=0;row=0;pos=0;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=Locks;caption=Locks;state=6293500;dir=4;layer=0;row=0;pos=1;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=Transactions;caption=Prepared Transactions;state=6293500;dir=4;layer=0;row=0;pos=2;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=Querystate;caption=QueryState;state=6293502;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=Logfile;caption=Logfile;state=6293500;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=toolBar;caption=Tool bar;state=2108144;dir=1;layer=10;row=0;pos=0;prop=100000;bestw=690;besth=39;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|dock_size(4,0,0)=800|dock_size(5,0,0)=22|dock_size(1,10,0)=41|")
|
||||
#else
|
||||
#define FRMSTATUS_DEFAULT_PERSPECTIVE wxT("layout2|name=Activity;caption=Activity;state=6293500;dir=4;layer=0;row=1;pos=0;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=174;floaty=216;floatw=578;floath=282|name=Locks;caption=Locks;state=6293500;dir=4;layer=0;row=1;pos=2;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=136;floaty=339;floatw=576;floath=283|name=Transactions;caption=Transactions;state=6293500;dir=4;layer=0;row=1;pos=3;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=133;floaty=645;floatw=577;floath=283|name=Querystate;caption=Query State;state=6309884;dir=4;layer=0;row=1;pos=1;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=154;floaty=255;floatw=1360;floath=751|name=Logfile;caption=Logfile;state=6293500;dir=5;layer=0;row=0;pos=0;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=-1;floaty=-1;floatw=-1;floath=-1|name=toolBar;caption=toolBar;state=2108144;dir=1;layer=10;row=0;pos=0;prop=100000;bestw=766;besth=39;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=586;floaty=525;floatw=483;floath=49|dock_size(1,10,0)=25|dock_size(4,0,1)=1115|dock_size(5,0,0)=22|")
|
||||
#define FRMSTATUS_DEFAULT_PERSPECTIVE wxT("layout2|name=Activity;caption=Activity;state=6293500;dir=4;layer=0;row=1;pos=0;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=174;floaty=216;floatw=578;floath=282|name=Locks;caption=Locks;state=6293500;dir=4;layer=0;row=1;pos=2;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=136;floaty=339;floatw=576;floath=283|name=Transactions;caption=Transactions;state=6293500;dir=4;layer=0;row=1;pos=3;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=133;floaty=645;floatw=577;floath=283|name=Querystate;caption=Query State;state=6309884;dir=4;layer=0;row=1;pos=4;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=154;floaty=255;floatw=800;floath=751|name=Logfile;caption=Logfile;state=6293500;dir=4;layer=0;row=1;pos=5;prop=100000;bestw=20;besth=20;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=150;floaty=90;floatw=400;floath=800|name=toolBar;caption=toolBar;state=2108144;dir=1;layer=10;row=0;pos=0;prop=100000;bestw=766;besth=39;minw=-1;minh=-1;maxw=-1;maxh=-1;floatx=586;floaty=525;floatw=483;floath=49|dock_size(1,10,0)=25|dock_size(4,0,1)=1115|dock_size(5,0,0)=22|")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
@ -96,175 +102,268 @@ static wxCriticalSection gs_critsect;
|
|||
|
||||
|
||||
// Class declarations
|
||||
static wxMutex s_mutexDBLogReading;
|
||||
static wxSemaphore s_goReadLog(0, 1);
|
||||
static wxSemaphore s_ResultOkLog(0, 1);
|
||||
static wxSemaphore s_CloseLog(0, 1);
|
||||
|
||||
class ReadLogThread : public wxThread
|
||||
{
|
||||
public:
|
||||
ReadLogThread(pgConn *conlog, wxWindow* p, wxMessageQueue<wxString> *queue)
|
||||
{
|
||||
|
||||
log_queue = queue;
|
||||
theParent = p;
|
||||
logfileName = wxEmptyString;
|
||||
savedPartialLine=wxEmptyString;
|
||||
logfileLength=0;
|
||||
len=0;
|
||||
conn = conlog;
|
||||
//nextrun = wxDateTime(0);
|
||||
}
|
||||
~ReadLogThread();
|
||||
void DoTerminate();
|
||||
bool IsTerminate() { return m_exit; }
|
||||
void SetParameters(wxString plogfileName, long plenfile, long plogfileLength, wxString psavedPartialLine) {
|
||||
logfileName = plogfileName;
|
||||
len = plenfile;
|
||||
logfileLength = plogfileLength;
|
||||
if (plogfileLength==0) inquote = false;
|
||||
savedPartialLine = psavedPartialLine;
|
||||
}
|
||||
long GetReadByteFile(wxString &part) {
|
||||
part = savedPartialLine;
|
||||
return logfileLength;
|
||||
}
|
||||
bool isReadyRows() {
|
||||
wxMutexError e = s_mutexDBLogReading.TryLock();
|
||||
if (e == wxMUTEX_NO_ERROR) {
|
||||
s_mutexDBLogReading.Unlock();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void BreakRead();
|
||||
bool isBreak() { return m_break; }
|
||||
bool GoReadRows() {
|
||||
m_break = false;
|
||||
wxSemaError e = s_goReadLog.Post();
|
||||
if (e == wxSEMA_NO_ERROR) {
|
||||
return true;
|
||||
}
|
||||
//wxLogError("Semafore return error");
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void* Entry();
|
||||
private:
|
||||
void readLogFile(wxString logfileName, long& lenfile, long& logfileLength, wxString& savedPartialLine);
|
||||
void getFilename();
|
||||
void sendText(wxString s) {
|
||||
wxThreadEvent e(wxEVT_THREAD);
|
||||
e.SetString(s);
|
||||
theParent->GetEventHandler()->AddPendingEvent(e);
|
||||
}
|
||||
wxDateTime nextrun;
|
||||
wxWindow* theParent;
|
||||
bool m_exit = false;
|
||||
bool m_break = false;
|
||||
pgConn *conn;
|
||||
wxMessageQueue<wxString>* log_queue;
|
||||
//
|
||||
wxString logfileName;
|
||||
wxString savedPartialLine;
|
||||
long logfileLength;
|
||||
long len;
|
||||
bool inquote = false;
|
||||
|
||||
};
|
||||
|
||||
class frmStatus : public pgFrame
|
||||
{
|
||||
public:
|
||||
frmStatus(frmMain *form, const wxString &_title, pgConn *conn);
|
||||
~frmStatus();
|
||||
void Go();
|
||||
frmStatus(frmMain *form, const wxString &_title, pgConn *conn);
|
||||
~frmStatus();
|
||||
void Go();
|
||||
|
||||
private:
|
||||
wxAuiManager manager;
|
||||
wxAuiManager manager;
|
||||
|
||||
frmMain *mainForm;
|
||||
pgConn *connection, *locks_connection;
|
||||
frmMain *mainForm;
|
||||
pgConn *connection, *locks_connection, *logconn;
|
||||
|
||||
wxString logFormat;
|
||||
bool logHasTimestamp, logFormatKnown;
|
||||
int logFmtPos;
|
||||
wxString logFormat,logFindString;
|
||||
bool logHasTimestamp, logFormatKnown;
|
||||
int logFmtPos;
|
||||
long logFinditem=-1;
|
||||
ReadLogThread *logThread=NULL;
|
||||
wxMessageQueue<wxString> log_queue;
|
||||
wxDateTime logfileTimestamp, latestTimestamp;
|
||||
wxString logDirectory, logfileName;
|
||||
|
||||
wxDateTime logfileTimestamp, latestTimestamp;
|
||||
wxString logDirectory, logfileName;
|
||||
wxString savedPartialLine;
|
||||
|
||||
wxString savedPartialLine;
|
||||
bool showCurrent, isCurrent;
|
||||
|
||||
bool showCurrent, isCurrent;
|
||||
long backend_pid;
|
||||
int wait_event_type_col;
|
||||
bool isrecovery,track_commit_timestamp, is_read_log;
|
||||
bool wait_sample, wait_enable, wait_save;
|
||||
bool frm_exit = false; // need close form
|
||||
bool logisread = false; // need close form
|
||||
WaitSample WS;
|
||||
wxTopActivity* top_small;
|
||||
wxString first_tt;
|
||||
bool loaded;
|
||||
long logfileLength;
|
||||
wxColour logcol[2];
|
||||
int addodd = 0;
|
||||
int currentPane;
|
||||
|
||||
long backend_pid;
|
||||
int wait_event_type_col;
|
||||
bool isrecovery,track_commit_timestamp;
|
||||
bool loaded;
|
||||
long logfileLength;
|
||||
wxColour bgColor;
|
||||
int statusSortColumn;
|
||||
wxString statusSortOrder;
|
||||
int lockSortColumn;
|
||||
wxString lockSortOrder;
|
||||
int xactSortColumn;
|
||||
wxString xactSortOrder;
|
||||
|
||||
int currentPane;
|
||||
wxComboBox *cbRate;
|
||||
wxComboBox *cbLogfiles;
|
||||
wxButton *btnRotateLog;
|
||||
ctlComboBoxFix *cbDatabase;
|
||||
|
||||
int statusSortColumn;
|
||||
wxString statusSortOrder;
|
||||
int lockSortColumn;
|
||||
wxString lockSortOrder;
|
||||
int xactSortColumn;
|
||||
wxString xactSortOrder;
|
||||
wxTimer *refreshUITimer;
|
||||
wxTimer *statusTimer, *locksTimer, *xactTimer, *logTimer, *querystateTimer;
|
||||
int statusRate, locksRate, xactRate, logRate, querystateRate;
|
||||
|
||||
ctlListView *statusList;
|
||||
ctlListView *lockList;
|
||||
ctlListView *xactList;
|
||||
ctlListView *logList;
|
||||
ctlNavigatePanel* nav;
|
||||
ctlListView *querystateList;
|
||||
|
||||
wxComboBox *cbRate;
|
||||
wxComboBox *cbLogfiles;
|
||||
wxButton *btnRotateLog;
|
||||
ctlComboBoxFix *cbDatabase;
|
||||
wxMenu *actionMenu;
|
||||
wxMenu *statusPopupMenu;
|
||||
wxMenu *lockPopupMenu;
|
||||
wxMenu *xactPopupMenu;
|
||||
wxMenu *querystatePopupMenu;
|
||||
wxString queryplan;
|
||||
wxArrayString queries;
|
||||
wxArrayInt filterColumn;
|
||||
wxArrayString filterValue;
|
||||
|
||||
wxTimer *refreshUITimer;
|
||||
wxTimer *statusTimer, *locksTimer, *xactTimer, *logTimer, *querystateTimer;
|
||||
int statusRate, locksRate, xactRate, logRate, querystateRate;
|
||||
int statusColWidth[12], lockColWidth[10], xactColWidth[5], querystateColWidth[5];
|
||||
|
||||
ctlListView *statusList;
|
||||
ctlListView *lockList;
|
||||
ctlListView *xactList;
|
||||
ctlListView *logList;
|
||||
ctlListView *querystateList;
|
||||
int cboToRate();
|
||||
wxString rateToCboString(int rate);
|
||||
|
||||
wxMenu *actionMenu;
|
||||
wxMenu *statusPopupMenu;
|
||||
wxMenu *lockPopupMenu;
|
||||
wxMenu *xactPopupMenu;
|
||||
wxMenu *querystatePopupMenu;
|
||||
wxString queryplan;
|
||||
wxArrayString queries;
|
||||
wxArrayInt filterColumn;
|
||||
wxArrayString filterValue;
|
||||
|
||||
int statusColWidth[12], lockColWidth[10], xactColWidth[5], querystateColWidth[5];
|
||||
|
||||
int cboToRate();
|
||||
wxString rateToCboString(int rate);
|
||||
|
||||
wxImageList *listimages;
|
||||
long getlongvalue(wxString source,wxString match_str);
|
||||
void AddStatusPane();
|
||||
void AddLockPane();
|
||||
void AddXactPane();
|
||||
void AddLogPane();
|
||||
wxImageList *listimages;
|
||||
long getlongvalue(wxString source,wxString match_str);
|
||||
void AddStatusPane();
|
||||
void AddLockPane();
|
||||
void AddXactPane();
|
||||
void AddLogPane();
|
||||
void AddQuerystatePane();
|
||||
|
||||
void OnHelp(wxCommandEvent &ev);
|
||||
void OnContents(wxCommandEvent &ev);
|
||||
void OnExit(wxCommandEvent &event);
|
||||
void OnHelp(wxCommandEvent &ev);
|
||||
void OnContents(wxCommandEvent &ev);
|
||||
void OnExit(wxCommandEvent &event);
|
||||
|
||||
void OnCopy(wxCommandEvent &ev);
|
||||
void OnCopyQuery(wxCommandEvent &ev);
|
||||
void OnCopy(wxCommandEvent &ev);
|
||||
void OnCopyQuery(wxCommandEvent &ev);
|
||||
|
||||
void OnToggleStatusPane(wxCommandEvent &event);
|
||||
void OnToggleLockPane(wxCommandEvent &event);
|
||||
void OnToggleXactPane(wxCommandEvent &event);
|
||||
void OnToggleLogPane(wxCommandEvent &event);
|
||||
void OnToggleQuerystatePane(wxCommandEvent &event);
|
||||
void OnEmptyAction(wxCommandEvent &event);
|
||||
|
||||
void OnToggleToolBar(wxCommandEvent &event);
|
||||
void OnDefaultView(wxCommandEvent &event);
|
||||
void OnHighlightStatus(wxCommandEvent &event);
|
||||
void OnToggleStatusPane(wxCommandEvent &event);
|
||||
void OnToggleLockPane(wxCommandEvent &event);
|
||||
void OnToggleXactPane(wxCommandEvent &event);
|
||||
void OnToggleLogPane(wxCommandEvent &event);
|
||||
void OnToggleQuerystatePane(wxCommandEvent &event);
|
||||
void OnToggleWaitEnable(wxCommandEvent& event);
|
||||
void OnEmptyAction(wxCommandEvent &event);
|
||||
void OnLogContextMenu(wxCommandEvent& event);
|
||||
|
||||
void OnRefreshUITimer(wxTimerEvent &event);
|
||||
void OnRefreshStatusTimer(wxTimerEvent &event);
|
||||
void OnRefreshLocksTimer(wxTimerEvent &event);
|
||||
void OnRefreshXactTimer(wxTimerEvent &event);
|
||||
void OnRefreshLogTimer(wxTimerEvent &event);
|
||||
void OnRefreshQuerystateTimer(wxTimerEvent &event);
|
||||
void OnToggleToolBar(wxCommandEvent &event);
|
||||
void OnDefaultView(wxCommandEvent &event);
|
||||
void OnHighlightStatus(wxCommandEvent &event);
|
||||
|
||||
void SetColumnImage(ctlListView *list, int col, int image);
|
||||
void OnSortStatusGrid(wxListEvent &event);
|
||||
void OnRightClickStatusItem(wxListEvent& event);
|
||||
void OnSortLockGrid(wxListEvent &event);
|
||||
void OnSortXactGrid(wxListEvent &event);
|
||||
void OnRefreshUITimer(wxTimerEvent &event);
|
||||
void OnRefreshStatusTimer(wxTimerEvent &event);
|
||||
void OnRefreshLocksTimer(wxTimerEvent &event);
|
||||
void OnRefreshXactTimer(wxTimerEvent &event);
|
||||
void OnRefreshLogTimer(wxTimerEvent &event);
|
||||
void OnRefreshQuerystateTimer(wxTimerEvent &event);
|
||||
|
||||
void OnRightClickStatusGrid(wxListEvent &event);
|
||||
void OnRightClickLockGrid(wxListEvent &event);
|
||||
void OnRightClickXactGrid(wxListEvent &event);
|
||||
void OnRightClickQuerystateGrid(wxListEvent &event);
|
||||
void SetColumnImage(ctlListView *list, int col, int image);
|
||||
void OnSortStatusGrid(wxListEvent &event);
|
||||
void OnRightClickStatusItem(wxListEvent& event);
|
||||
void OnSortLockGrid(wxListEvent &event);
|
||||
void OnSortXactGrid(wxListEvent &event);
|
||||
|
||||
void OnStatusMenu(wxCommandEvent &event);
|
||||
void OnLockMenu(wxCommandEvent &event);
|
||||
void OnXactMenu(wxCommandEvent &event);
|
||||
void OnQuerystateMenu(wxCommandEvent &event);
|
||||
void OnRightClickStatusGrid(wxListEvent &event);
|
||||
void OnRightClickLockGrid(wxListEvent &event);
|
||||
void OnRightClickXactGrid(wxListEvent &event);
|
||||
void OnRightClickQuerystateGrid(wxListEvent &event);
|
||||
void OnRightClickLogGrid(wxListEvent& event);
|
||||
|
||||
void OnStatusMenu(wxCommandEvent &event);
|
||||
void OnLockMenu(wxCommandEvent &event);
|
||||
void OnXactMenu(wxCommandEvent &event);
|
||||
void OnQuerystateMenu(wxCommandEvent &event);
|
||||
|
||||
void OnChgColSizeStatusGrid(wxListEvent &event);
|
||||
void OnChgColSizeLockGrid(wxListEvent &event);
|
||||
void OnChgColSizeXactGrid(wxListEvent &event);
|
||||
void OnChgColSizeQuerystateGrid(wxListEvent &event);
|
||||
|
||||
void OnRateChange(wxCommandEvent &event);
|
||||
void OnChgColSizeStatusGrid(wxListEvent &event);
|
||||
void OnChgColSizeLockGrid(wxListEvent &event);
|
||||
void OnChgColSizeXactGrid(wxListEvent &event);
|
||||
void OnChgColSizeQuerystateGrid(wxListEvent &event);
|
||||
|
||||
void OnRateChange(wxCommandEvent &event);
|
||||
|
||||
void OnPaneClose(wxAuiManagerEvent &evt);
|
||||
void OnPaneClose(wxAuiManagerEvent &evt);
|
||||
void OnPaneActivated(wxAuiManagerEvent& evt);
|
||||
|
||||
void OnClose(wxCloseEvent &event);
|
||||
void OnRefresh(wxCommandEvent &event);
|
||||
void OnCancelBtn(wxCommandEvent &event);
|
||||
void OnStatusCancelBtn(wxCommandEvent &event);
|
||||
void OnLocksCancelBtn(wxCommandEvent &event);
|
||||
void OnTerminateBtn(wxCommandEvent &event);
|
||||
void OnStatusTerminateBtn(wxCommandEvent &event);
|
||||
void OnLocksTerminateBtn(wxCommandEvent &event);
|
||||
void OnSelStatusItem(wxListEvent &event);
|
||||
void OnSelLockItem(wxListEvent &event);
|
||||
void OnSelXactItem(wxListEvent &event);
|
||||
void OnSelLogItem(wxListEvent &event);
|
||||
void OnSelQuerystateItem(wxListEvent &event);
|
||||
void OnLoadLogfile(wxCommandEvent &event);
|
||||
void OnRotateLogfile(wxCommandEvent &event);
|
||||
void OnCommit(wxCommandEvent &event);
|
||||
void OnRollback(wxCommandEvent &event);
|
||||
void OnClearFilter(wxCommandEvent& event);
|
||||
void OnClose(wxCloseEvent &event);
|
||||
void OnRefresh(wxCommandEvent &event);
|
||||
void OnCancelBtn(wxCommandEvent &event);
|
||||
void OnStatusCancelBtn(wxCommandEvent &event);
|
||||
void OnLocksCancelBtn(wxCommandEvent &event);
|
||||
void OnTerminateBtn(wxCommandEvent &event);
|
||||
void OnStatusTerminateBtn(wxCommandEvent &event);
|
||||
void OnLocksTerminateBtn(wxCommandEvent &event);
|
||||
void OnSelStatusItem(wxListEvent &event);
|
||||
void OnSelLockItem(wxListEvent &event);
|
||||
void OnSelXactItem(wxListEvent &event);
|
||||
void OnSelLogItem(wxListEvent &event);
|
||||
void OnSelQuerystateItem(wxListEvent &event);
|
||||
void OnLoadLogfile(wxCommandEvent &event);
|
||||
void OnRotateLogfile(wxCommandEvent &event);
|
||||
void OnCommit(wxCommandEvent &event);
|
||||
void OnRollback(wxCommandEvent &event);
|
||||
void OnClearFilter(wxCommandEvent& event);
|
||||
void OnLogKeyUp(wxKeyEvent& event);
|
||||
void OnAddLabelTextThread(wxThreadEvent& event);
|
||||
void ActivatePane(wxString name);
|
||||
|
||||
void OnChangeDatabase(wxCommandEvent &ev);
|
||||
void OnChangeDatabase(wxCommandEvent &ev);
|
||||
|
||||
int fillLogfileCombo();
|
||||
void emptyLogfileCombo();
|
||||
int fillLogfileCombo();
|
||||
void emptyLogfileCombo();
|
||||
|
||||
void addLogFile(wxDateTime *dt, bool skipFirst);
|
||||
void addLogFile(const wxString &filename, const wxDateTime timestamp, long len, long &read, bool skipFirst);
|
||||
void addLogLine(const wxString &str, bool formatted = true, bool csv_log_format = false);
|
||||
void addLogFile(wxDateTime *dt, bool skipFirst);
|
||||
void addLogFile(const wxString &filename, const wxDateTime timestamp, long len, long &read, bool skipFirst);
|
||||
void addLogLine(const wxString &str, bool formatted = true, bool csv_log_format = false);
|
||||
|
||||
void checkConnection();
|
||||
void checkConnection();
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
|
||||
class serverStatusFactory : public actionFactory
|
||||
{
|
||||
public:
|
||||
serverStatusFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar);
|
||||
wxWindow *StartDialog(frmMain *form, pgObject *obj);
|
||||
bool CheckEnable(pgObject *obj);
|
||||
serverStatusFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar);
|
||||
wxWindow *StartDialog(frmMain *form, pgObject *obj);
|
||||
bool CheckEnable(pgObject *obj);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
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);
|
||||
|
||||
};
|
||||
1508
ui/xrcDialogs.cpp
1508
ui/xrcDialogs.cpp
File diff suppressed because it is too large
Load diff
714
utils/WaitSample.cpp
Normal file
714
utils/WaitSample.cpp
Normal file
|
|
@ -0,0 +1,714 @@
|
|||
#include "pgAdmin3.h"
|
||||
#include "utils/WaitSample.h"
|
||||
#include "wx/stdpaths.h"
|
||||
#include "utils/utffile.h"
|
||||
#include "utils/json/jsonval.h"
|
||||
|
||||
void WaitSample::Init() {
|
||||
wxString clr = "h1 { \
|
||||
region: \"IO:DataFileRead\", #3644ff;\n\
|
||||
region: \"IO:DataFileWrite\", #790808;\n\
|
||||
region: \"IO:BufFileRead\", #16658d;\n\
|
||||
region: \"IO:BufFileWrite\", #d30a0a;\n\
|
||||
region: \"IO:DataFileExtend\", #9720ba;\n\
|
||||
region: \"IO:DataFilePrefetch\", #c03ae8;\n\
|
||||
region: \"IO:DataFileFlush\", #b609ea;\n\
|
||||
region: \"IO:DataFileSync\", #b609ea;\n\
|
||||
region: \"IO:ReplicationSlotSync\", #b609ea;\n\
|
||||
region: \"IO:WALSync\", #ff6a00;\n\
|
||||
region: \"IO:WALWrite\", #ff6a00;\n\
|
||||
region: \"IO:WALInitWrite\", #ff6a00;\n\
|
||||
region: \"IO:WALRead\", #ba550e;\n\
|
||||
region: \"IO\", #2132bd;\n\
|
||||
region: \"IPC\", #908b3b;\n\
|
||||
region: \"Lock\", #ff0000;\n\
|
||||
region: \"Client\", #0b6222;\n\
|
||||
region: \"BufferPin\", #a4a3a0;\n\
|
||||
region: \"Client:ClientWrite\", #76bb88;\n\
|
||||
region: \"IPC:ArchiveCommand\", #fff200;\n\
|
||||
region: \"IPC:MessageQueueReceive\", #aaae4f;\n\
|
||||
region: \"IPC:MessageQueueSend\", #aaae4f;\n\
|
||||
region: \"LWLock\", #87f566;\n\
|
||||
region: \"LWLock:WALWrite\", #3bf61e;\n\
|
||||
region: \"LWLock:WALInsert\", #3bf61e;\n\
|
||||
region: \"LWLock:Autovacuum\", #20bb08;\n\
|
||||
region: \"LWLock:BufferContent\", #98db19;\n\
|
||||
region: \"Timeout\", #6ce4c6;\n\
|
||||
region: \"Timeout:VacuumDelay\", #20bb08;\n\
|
||||
}";
|
||||
wxStringTokenizer tk(clr, "\n", wxTOKEN_DEFAULT);
|
||||
wxString cc;
|
||||
wxString cnt;
|
||||
wxString ee;
|
||||
wxString l;
|
||||
wxJSONValue events(wxJSONType::wxJSONTYPE_ARRAY);
|
||||
while (tk.HasMoreTokens())
|
||||
{
|
||||
wxString l = tk.GetNextToken();
|
||||
wxString w = l.AfterFirst('"').BeforeFirst('"');
|
||||
if (w.IsEmpty()) continue;
|
||||
wxString c = l.AfterFirst('#').BeforeFirst(';');
|
||||
unsigned long tmp;
|
||||
wxSscanf(c, "%lx", &tmp);
|
||||
wait_idx.emplace(w, tmp);
|
||||
wxJSONValue e(wxJSONType::wxJSONTYPE_OBJECT);
|
||||
wxColour cc3("#"+c);
|
||||
e["enable"] = true;
|
||||
e["color"] = "#" + c;
|
||||
e["name"] = w;
|
||||
events.Append(e);
|
||||
}
|
||||
wxJSONValue def(wxJSONType::wxJSONTYPE_OBJECT);
|
||||
def["events"] = events;
|
||||
//def["autoloadcache_sql"] = true;
|
||||
group.push_back("BufferPin");
|
||||
group.push_back("Client");
|
||||
group.push_back("IO");
|
||||
group.push_back("IPC");
|
||||
group.push_back("Lock");
|
||||
group.push_back("Activity");
|
||||
group.push_back("LWLock");
|
||||
group.push_back("Timeout");
|
||||
settings->ReloadJsonFileIfNeed();
|
||||
settings->ReadJsonObect("WaitEvents", opt, def);
|
||||
// settings->WriteJsonFile();
|
||||
if (!opt.IsNull()) {
|
||||
wait_idx.clear();
|
||||
wxJSONValue r = opt["events"];
|
||||
for (int j = 0; j < r.Size(); j++) {
|
||||
wxJSONValue e = r[j];
|
||||
bool enable = e["enable"].AsBool();
|
||||
wxString c= e["color"].AsString();
|
||||
unsigned long tmp;
|
||||
wxSscanf(c, "#%lx", &tmp);
|
||||
wxColour cc(tmp);
|
||||
if (!cc.IsOk()) cc = *wxBLACK;
|
||||
//wxSscanf(c, "%lx", &tmp);
|
||||
wxString w = e["name"].AsString();
|
||||
wait_idx.emplace(w, tmp);
|
||||
if (!enable) wait_disable.emplace(w,0);
|
||||
}
|
||||
}
|
||||
else opt = def;
|
||||
wxString tempDir = wxStandardPaths::Get().GetUserConfigDir() + wxFileName::GetPathSeparator() + "postgresql" + wxFileName::GetPathSeparator() + "cache_sql.txt";
|
||||
wxTextFile file(tempDir);
|
||||
if (file.Exists()) file.Open();
|
||||
if (file.IsOpened())
|
||||
{
|
||||
wxString str;
|
||||
wxString sql;
|
||||
long long qid;
|
||||
for (str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine())
|
||||
{
|
||||
if (str.length() == 16) {
|
||||
unsigned long long temp_qid = 0;
|
||||
int cntbits = 0;
|
||||
for (int i = str.length() - 1; i >= 0; i--, cntbits = cntbits + 4)
|
||||
{
|
||||
unsigned char h = str[i];
|
||||
unsigned char n09 = h - '0';
|
||||
unsigned char nAF = (h | 0x20) - 'a';
|
||||
if ((n09 <= (9 - 0)) || (nAF <= (0xf - 0xa))) {
|
||||
// is hex digits
|
||||
}
|
||||
else break;
|
||||
unsigned long long tetra = ((h & 0xf) + (h >> 6) * 9);
|
||||
temp_qid |= tetra << cntbits;
|
||||
}
|
||||
if (cntbits == 64) {
|
||||
//wxString tmp = sql.BeforeLast('\n');
|
||||
//if (tmp.IsEmpty()) tmp=sql;
|
||||
if (sql.length() > 0) AddQuery(qid, sql); // previos sql
|
||||
qid = temp_qid;
|
||||
sql = wxEmptyString;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!sql.IsEmpty()) sql.Append('\n');
|
||||
sql.Append(str);
|
||||
}
|
||||
//file.ReadAll(&str);
|
||||
file.Close();
|
||||
if (sql.length() > 0)
|
||||
{
|
||||
//wxString tmp = sql.BeforeLast('\n');
|
||||
//if (tmp.IsEmpty()) tmp = sql;
|
||||
AddQuery(qid, sql); // previos sql
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
std::vector<Sample>* WaitSample::GetSamples() { return &smp; }
|
||||
std::vector<int> WaitSample::GetColors() { return colors; }
|
||||
|
||||
wxArrayString WaitSample::GetWaitIdNameArray(bool onlyGroup) {
|
||||
typedef std::pair<wxString, int> pair;
|
||||
// sort map by value;
|
||||
std::vector<pair> vec;
|
||||
std::copy(wait_id.begin(),
|
||||
wait_id.end(),
|
||||
std::back_inserter<std::vector<pair>>(vec));
|
||||
std::sort(vec.begin(), vec.end(),
|
||||
[](const pair& l, const pair& r)
|
||||
{
|
||||
if (l.second != r.second) {
|
||||
return l.second < r.second;
|
||||
}
|
||||
|
||||
return l.first < r.first;
|
||||
});
|
||||
wxArrayString a;
|
||||
for (auto const& pair : vec) {
|
||||
//std::cout << '{' << pair.first << "," << pair.second << '}' << std::endl;
|
||||
wxString n = pair.first;
|
||||
if (onlyGroup) {
|
||||
if (!n.BeforeFirst(':').IsEmpty()) n = n.BeforeFirst(':');
|
||||
}
|
||||
a.Add(n);
|
||||
|
||||
}
|
||||
return a;
|
||||
}
|
||||
// return position in smp vector
|
||||
int WaitSample::GetHomeInterval(int timeEnd, int AggrigateInterval) {
|
||||
Sample sa;
|
||||
if (timeEnd == -1) {
|
||||
// end smp
|
||||
sa = smp.back();
|
||||
timeEnd = sa.btime;
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
long long th = ((basetime + timeEnd) / AggrigateInterval) * AggrigateInterval;
|
||||
int home_int = th - basetime;
|
||||
if (th > (basetime + timeEnd)) {
|
||||
//long long te = th - AggrigateInterval;
|
||||
home_int = th - AggrigateInterval - basetime;
|
||||
}
|
||||
return home_int;
|
||||
|
||||
//wxLongLong l(((basetime + timeEnd)/AggrigateInterval)* AggrigateInterval);
|
||||
//wxDateTime t(l);
|
||||
}
|
||||
int WaitSample::getPositionByTime(int time) {
|
||||
|
||||
int max = smp.size() - 1;
|
||||
int min = 0;
|
||||
int i = (max - min) / 2;
|
||||
while (i != -1) {
|
||||
int t = smp[i].btime;
|
||||
if (t < time) {
|
||||
min = i;
|
||||
i = min + (max - min) / 2;
|
||||
}
|
||||
else if (t > time) {
|
||||
max = i;
|
||||
i = min + (max - min) / 2;
|
||||
}
|
||||
else {
|
||||
while (i > 0 && smp[i - 1].btime == t) {
|
||||
i--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (max - min < 2) {
|
||||
i = max;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
int WaitSample::wait_class(wxString wclass) {
|
||||
int i = 0;
|
||||
for (const auto& name : group) {
|
||||
if (name == wclass) return i;
|
||||
i++;
|
||||
}
|
||||
wxFAIL_MSG("Unknown wait class " + wclass);
|
||||
return -1000;
|
||||
}
|
||||
// return count group
|
||||
int WaitSample::GetGroupingData(int timeEnd, int needCountGroup, int groupInterval,
|
||||
wxString groupRule, wxArrayString& nameGroup,
|
||||
std::vector<wxDateTime>& xAxisValue,
|
||||
std::vector<wxTimeSpan>& yAxisValue,
|
||||
std::vector<vec_int>& Values, // ìàññèâ ñòîëáöîâ ñïðàâà íà ëåâî
|
||||
std::vector<long>& clr // öåòà ñëî¸â ðàçìåðíîñòüþ groupRule.Count()
|
||||
)
|
||||
{
|
||||
int idx_grp = wait_id.size();
|
||||
std::vector<int> filter_map(wait_id.size() + group.size());
|
||||
std::vector<int> summary(wait_id.size() + group.size());
|
||||
for (size_t i = 0; i < filter_map.size(); i++) filter_map[i] = -1;
|
||||
nameGroup.Clear();
|
||||
//std::map<int, wxString> wait_id_name;
|
||||
long long qidfilter = -1;
|
||||
for (const auto& kv : wait_id) {
|
||||
//std::cout << kv.first << " has value " << kv.second << std::endl;
|
||||
wxString w_name = kv.first;
|
||||
int w_id = kv.second;
|
||||
//wait_id_name.emplace(w_id, w_name);
|
||||
bool enable = true;
|
||||
wxString grp_name = w_name.BeforeFirst(':');
|
||||
if (grp_name.IsEmpty()) grp_name = w_name;
|
||||
int cl = wait_class(grp_name);
|
||||
bool isF = false;
|
||||
if (!groupRule.IsEmpty()) {
|
||||
wxStringTokenizer tk(groupRule, ";", wxTOKEN_DEFAULT);
|
||||
wxString l;
|
||||
bool isDis = true;
|
||||
bool isGrp = true;
|
||||
|
||||
while (tk.HasMoreTokens())
|
||||
{
|
||||
l = tk.GetNextToken();
|
||||
if (l[0] == '@') {
|
||||
if (qidfilter == -1) {
|
||||
int cntbits = 0;
|
||||
unsigned long long temp_qid = 0;
|
||||
for (int i = l.length() - 1; i > 0; i--, cntbits = cntbits + 4)
|
||||
{
|
||||
unsigned char h = l[i];
|
||||
unsigned char n09 = h - '0';
|
||||
unsigned char nAF = (h | 0x20) - 'a';
|
||||
if ((n09 <= (9 - 0)) || (nAF <= (0xf - 0xa))) {
|
||||
// is hex digits
|
||||
}
|
||||
else break;
|
||||
unsigned long long tetra = ((h & 0xf) + (h >> 6) * 9);
|
||||
temp_qid |= tetra << cntbits;
|
||||
}
|
||||
qidfilter = temp_qid;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
isDis = l[0] == '-';
|
||||
if (isDis) l = l.substr(1);
|
||||
isGrp = l.find(':') == -1;
|
||||
if (w_name == l) {
|
||||
if (isDis) {
|
||||
filter_map[w_id] = w_id; //disable in Grp
|
||||
if (filter_map[idx_grp + cl] < 0) filter_map[idx_grp + cl] = -2;
|
||||
}
|
||||
else {
|
||||
//filter_map[w_id] = w_id;
|
||||
isF = false; //default
|
||||
break;
|
||||
}
|
||||
isF = true;
|
||||
break;
|
||||
}
|
||||
if (isGrp) {
|
||||
|
||||
if (grp_name == l) {
|
||||
if (isDis) {
|
||||
// Groups equal and disable
|
||||
filter_map[w_id] = w_id; // disable w_id Grp ALL disable
|
||||
filter_map[idx_grp + cl] = -2; // disable group
|
||||
isF = true;
|
||||
break;
|
||||
}
|
||||
// default rule
|
||||
break;
|
||||
}
|
||||
continue; // next rule
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isF) {
|
||||
// no found in Rule
|
||||
filter_map[w_id] = idx_grp + cl; // wait_id -> [idx_grp + cl]
|
||||
filter_map[idx_grp + cl] = 999; // visible
|
||||
//filter_map[idx_grp+cl]=
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// nameGroup
|
||||
// begin Group
|
||||
wxString n, g;
|
||||
clr.clear();
|
||||
clr.resize(filter_map.size());
|
||||
for (size_t i = idx_grp; i < filter_map.size(); i++)
|
||||
{
|
||||
int wait_id = filter_map[i];
|
||||
if (wait_id == -1) continue;
|
||||
n = group[i - idx_grp];
|
||||
g = n;
|
||||
clr[i] = GetColorByWaitName(n);
|
||||
if (wait_id == -2) n = '-' + n;
|
||||
nameGroup.Add(n);
|
||||
// individual wait
|
||||
for (size_t j = 0; j < idx_grp; j++)
|
||||
{
|
||||
int wait_id = filter_map[j];
|
||||
n = wait_id_name[j];
|
||||
wxString grp_name = n.BeforeFirst(':');
|
||||
if (grp_name.IsEmpty()) grp_name = n;
|
||||
if (grp_name != g) continue;
|
||||
if (!n.AfterFirst(':').IsEmpty()) n = n.AfterFirst(':');
|
||||
if (wait_id == j) n = "--" + n; else n = " " + n;
|
||||
nameGroup.Add(n);
|
||||
clr[j] = GetColorByWaitName(wait_id_name[j]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
int homeInt = GetHomeInterval(timeEnd, groupInterval);
|
||||
Sample sa;
|
||||
if (timeEnd == -1) {
|
||||
sa = smp.back();
|
||||
timeEnd = sa.btime;
|
||||
}
|
||||
int idx = getPositionByTime(timeEnd);
|
||||
for (size_t i = 0; i < summary.size(); i++) summary[i] = 0;
|
||||
Values.clear();
|
||||
xAxisValue.clear();
|
||||
//for (size_t i = 0; i < maxS.size(); i++) maxS[i] = 0;
|
||||
long long maxsum = 0;
|
||||
int minsum = 0;
|
||||
int nGrp = needCountGroup;
|
||||
while (idx >= 0) {
|
||||
sa = smp[idx--];
|
||||
if (sa.btime >= homeInt && idx >= 0) {
|
||||
}
|
||||
else {
|
||||
// new interval
|
||||
wxLongLong l(basetime + homeInt);
|
||||
wxDateTime t(l);
|
||||
xAxisValue.push_back(t);
|
||||
std::vector<int> itog(summary.size());
|
||||
int ni = idx_grp;
|
||||
int Ymax = 0;
|
||||
for (size_t i = 0; i < itog.size(); i++)
|
||||
{
|
||||
|
||||
int wait_id = filter_map[i];
|
||||
if (wait_id < 0) { itog[i] = wait_id; continue; }
|
||||
int a = summary[i];
|
||||
itog[i] = a;
|
||||
if (i >= idx_grp) Ymax += a;
|
||||
//if (minsum > a) minsum = a;
|
||||
}
|
||||
if (maxsum < Ymax) maxsum = Ymax;
|
||||
Values.push_back(itog);
|
||||
homeInt -= groupInterval;
|
||||
nGrp--;
|
||||
if (nGrp == 0) break;
|
||||
for (size_t i = 0; i < summary.size(); i++) summary[i] = 0;
|
||||
}
|
||||
if (qidfilter != -1 && sa.qid != qidfilter) continue;
|
||||
int w_id = sa.wait_id;
|
||||
if (filter_map[w_id] < 0) continue;
|
||||
int ii = filter_map[w_id];
|
||||
// grp
|
||||
int s = sa.samples * periodms;
|
||||
if (ii != w_id) summary[ii] += s;
|
||||
// details
|
||||
summary[w_id] += s;
|
||||
}
|
||||
yAxisValue.clear();
|
||||
yAxisValue.push_back(wxTimeSpan(0, 0, 0, maxsum));
|
||||
return Values.size();
|
||||
}
|
||||
int WaitSample::GetInterval(int posStart, int posEnd) {
|
||||
Sample sa1, sa2;
|
||||
if (smp.size() == 0) return 0;
|
||||
if (posEnd == -1) {
|
||||
sa2 = smp.back();
|
||||
}
|
||||
else sa2 = smp.at(posEnd);
|
||||
sa1 = smp.at(posStart);
|
||||
return sa2.btime - sa1.btime;
|
||||
}
|
||||
bool WaitSample::AddQuery(long long qid, wxString sql) {
|
||||
if (qid_sql.find(qid) == qid_sql.end()) {
|
||||
qid_sql.emplace(qid, sql);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
wxString WaitSample::GetQueryByQid(long long qid) {
|
||||
if (qid_sql.find(qid) != qid_sql.end()) {
|
||||
wxString sql = qid_sql[qid];
|
||||
return sql;
|
||||
}
|
||||
return wxEmptyString;
|
||||
|
||||
}
|
||||
void WaitSample::LoadFileSamples() {
|
||||
wxString tempDir = wxStandardPaths::Get().GetUserConfigDir() + wxFileName::GetPathSeparator() + "postgresql" + wxFileName::GetPathSeparator() + "sample.dat";
|
||||
wxTextFile file(tempDir);
|
||||
file.Open();
|
||||
if (file.IsOpened())
|
||||
{
|
||||
wxString str;
|
||||
for (str = file.GetFirstLine() + '\n'; !file.Eof(); str += file.GetNextLine() + '\n')
|
||||
{
|
||||
|
||||
}
|
||||
//file.ReadAll(&str);
|
||||
file.Close();
|
||||
|
||||
wxStringTokenizer tk(str, "\n", wxTOKEN_DEFAULT);
|
||||
wxString cc;
|
||||
wxString cnt;
|
||||
wxString ee;
|
||||
wxString l;
|
||||
int nl = 0;
|
||||
while (tk.HasMoreTokens())
|
||||
{
|
||||
wxString l = tk.GetNextToken();
|
||||
if (l.IsEmpty()) continue;
|
||||
if (nl == 0) {
|
||||
long long t;
|
||||
wxSscanf(l, "%lld", &basetime);
|
||||
nl++;
|
||||
continue;
|
||||
}
|
||||
if (nl == 4) {
|
||||
//smp
|
||||
//wxString w_name = tk.GetNextToken();
|
||||
//wxString w_id = tk2.GetNextToken();
|
||||
int tmp = 0;
|
||||
Sample sa;
|
||||
if (wxSscanf(l, "%d %d %d %d %lld %d %d", &sa.btime, &sa.etime, &sa.wait_id, &sa.pid, &sa.qid, &sa.btype, &sa.samples) != 7) {
|
||||
wxLogError("Invalid count parameters '%s'.", l);
|
||||
}
|
||||
/*wxSscanf(tk2.GetNextToken(), "%d", &sa.btime);
|
||||
wxSscanf(tk2.GetNextToken(), "%d", &sa.etime);
|
||||
wxSscanf(tk2.GetNextToken(), "%d", &sa.wait_id);
|
||||
wxSscanf(tk2.GetNextToken(), "%d", &sa.pid);
|
||||
wxSscanf(tk2.GetNextToken(), "%lld", &sa.qid);
|
||||
wxSscanf(tk2.GetNextToken(), "%d", &sa.btype);
|
||||
wxSscanf(tk2.GetNextToken(), "%d", &sa.samples);*/
|
||||
smp.push_back(sa);
|
||||
continue;
|
||||
}
|
||||
|
||||
wxStringTokenizer tk2(l, " ", wxTOKEN_DEFAULT);
|
||||
if (nl == 1) {
|
||||
//btype
|
||||
|
||||
while (tk2.HasMoreTokens())
|
||||
{
|
||||
wxString b_name, b_id;
|
||||
while (b_id.IsEmpty()) {
|
||||
wxString str = tk2.GetNextToken();
|
||||
if (!wxIsdigit(str[0]))
|
||||
b_name += b_name.IsEmpty() ? str : " " + str;
|
||||
else b_id = str;
|
||||
}
|
||||
unsigned long tmp;
|
||||
wxSscanf(b_id, "%ld", &tmp);
|
||||
int i = GetBackendTypeId(b_name);
|
||||
if (i != tmp) {
|
||||
|
||||
}
|
||||
}
|
||||
nl++;
|
||||
continue;
|
||||
}
|
||||
if (nl == 2) {
|
||||
//wait_id
|
||||
while (tk2.HasMoreTokens())
|
||||
{
|
||||
wxString w_name, w_id;
|
||||
while (w_id.IsEmpty()) {
|
||||
wxString str = tk2.GetNextToken();
|
||||
if (!wxIsdigit(str[0]))
|
||||
w_name += w_name.IsEmpty() ? str : " " + str;
|
||||
else w_id = str;
|
||||
}
|
||||
unsigned long tmp;
|
||||
wxSscanf(w_id, "%ld", &tmp);
|
||||
wait_id.emplace(w_name, tmp);
|
||||
wait_id_name.emplace(tmp, w_name);
|
||||
}
|
||||
nl++;
|
||||
continue;
|
||||
}
|
||||
if (nl == 3) {
|
||||
//colors
|
||||
int sz = wait_id.size();
|
||||
colors.resize(sz);
|
||||
int i = 0;
|
||||
while (tk2.HasMoreTokens())
|
||||
{
|
||||
wxString c = tk2.GetNextToken();
|
||||
unsigned long tmp;
|
||||
wxSscanf(c, "%ld", &tmp);
|
||||
colors[i++] = tmp;
|
||||
}
|
||||
nl++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
void WaitSample::SaveFileSamples() {
|
||||
wxString tempDir = wxStandardPaths::Get().GetUserConfigDir() + wxFileName::GetPathSeparator() + "postgresql" + wxFileName::GetPathSeparator() + "sample.dat";
|
||||
wxUtfFile file(tempDir, wxFile::write, wxFONTENCODING_UTF8);
|
||||
if (file.IsOpened())
|
||||
{
|
||||
wxString strnl;
|
||||
strnl = wxString::Format("%lld\n", basetime);
|
||||
file.Write(strnl);
|
||||
strnl.Clear();
|
||||
//btype
|
||||
int i = 0;
|
||||
for (const auto& e : btype) {
|
||||
if (!strnl.IsEmpty()) strnl += ' ';
|
||||
strnl += wxString::Format("%s %d", e, i);
|
||||
i++;
|
||||
}
|
||||
strnl += '\n';
|
||||
file.Write(strnl);
|
||||
// wait_id
|
||||
strnl.Clear();
|
||||
for (const auto& e : wait_id) {
|
||||
if (!strnl.IsEmpty()) strnl += ' ';
|
||||
strnl += wxString::Format("%s %d", e.first, e.second);
|
||||
}
|
||||
strnl += '\n';
|
||||
file.Write(strnl);
|
||||
strnl.Clear();
|
||||
for (const auto& e : colors) {
|
||||
if (!strnl.IsEmpty()) strnl += ' ';
|
||||
strnl += wxString::Format("%d", e);
|
||||
}
|
||||
strnl += '\n';
|
||||
file.Write(strnl);
|
||||
strnl.Clear();
|
||||
for (const auto& e : smp) {
|
||||
strnl.Append(wxString::Format("%d %d %d %d %lld %d %d\n", e.btime, e.etime, e.wait_id, e.pid, e.qid, e.btype, e.samples));
|
||||
}
|
||||
file.Write(strnl);
|
||||
file.Close();
|
||||
}
|
||||
tempDir = wxStandardPaths::Get().GetUserConfigDir() + wxFileName::GetPathSeparator() + "postgresql" + wxFileName::GetPathSeparator() + "cache_sql.txt";
|
||||
wxUtfFile file1(tempDir, wxFile::write, wxFONTENCODING_UTF8);
|
||||
if (file1.IsOpened())
|
||||
{
|
||||
wxString str;
|
||||
|
||||
for (const auto& e : qid_sql) {
|
||||
wxLongLong l(e.first);
|
||||
|
||||
str = wxString::Format("%0x%0x\n%s\n", l.GetHi(), l.GetLo(), e.second);
|
||||
file1.Write(str);
|
||||
}
|
||||
file1.Close();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitSample::AddSample(int pid, bool isXidTransation, wxString& btype, const wxString& sample) {
|
||||
//PidWait pw(pid, basetime);;
|
||||
// ïîèñê
|
||||
int pw;
|
||||
auto iter = pids.find(pid);
|
||||
if (iter != pids.end()) {
|
||||
//std::cout << "Found the key " << iter->first << " with the value " << iter->second << "\n";
|
||||
pw = iter->second;
|
||||
}
|
||||
else {
|
||||
pids.emplace(pid, pw);
|
||||
}
|
||||
++chkpids[pid];
|
||||
int bt = GetBackendTypeId(btype);
|
||||
//pw.AddSample(sample, active, timebegiserios, timeendserios);
|
||||
wxStringTokenizer tk(sample, ";", wxTOKEN_DEFAULT);
|
||||
wxString cnt;
|
||||
wxString w;
|
||||
wxString et;
|
||||
while (tk.HasMoreTokens())
|
||||
{
|
||||
wxString et = tk.GetNextToken();
|
||||
wxString cnt = et.AfterLast(':');
|
||||
et = et.BeforeLast(':');
|
||||
wxString tqid = et.AfterLast(':');
|
||||
wxString w = et.BeforeLast(':');
|
||||
// ignore ClientRead out transaction
|
||||
if (w == "Client:ClientRead" && !isXidTransation)
|
||||
continue;
|
||||
int smp_cnt;
|
||||
long long qid;
|
||||
wxSscanf(cnt, "%d", &smp_cnt);
|
||||
wxSscanf(tqid, "%lld", &qid);
|
||||
auto dis_it = wait_disable.find(w);
|
||||
if (dis_it != wait_disable.end()) {
|
||||
continue;
|
||||
}
|
||||
auto iter = wait_id.find(w);
|
||||
int id;
|
||||
if (iter == wait_id.end()) {
|
||||
id = wait_id.size();
|
||||
wait_id.emplace(w, id);
|
||||
wait_id_name.emplace(id, w);
|
||||
//map color
|
||||
long c = 0;
|
||||
auto it2 = wait_idx.find(w);
|
||||
if (it2 == wait_idx.end()) {
|
||||
it2 = wait_idx.find(w.BeforeFirst(':'));
|
||||
if (it2 != wait_idx.end()) {
|
||||
c = it2->second;
|
||||
}
|
||||
}
|
||||
else c = it2->second;
|
||||
colors.push_back(c);
|
||||
//colors
|
||||
}
|
||||
else id = iter->second;
|
||||
|
||||
Sample sa;
|
||||
sa.btime = timebegiserios;
|
||||
sa.etime = timeendserios;
|
||||
sa.wait_id = id;
|
||||
sa.samples = smp_cnt;
|
||||
sa.pid = pid;
|
||||
sa.qid = qid;
|
||||
sa.btype = bt;
|
||||
smp.push_back(sa);
|
||||
//pw.AddSample();
|
||||
}
|
||||
|
||||
}
|
||||
int WaitSample::GetBackendTypeId(wxString backend_type) {
|
||||
int idx = 0;
|
||||
auto it = std::find_if(btype.begin(), btype.end(), [&](const wxString& s) {
|
||||
idx++;
|
||||
return s == backend_type;
|
||||
}
|
||||
);
|
||||
if (it != btype.end()) return idx - 1;
|
||||
btype.push_back(backend_type);
|
||||
return idx;
|
||||
}
|
||||
std::vector<int> tmp_idx_colors;
|
||||
bool compareBySample(const Sample& a, const Sample& b)
|
||||
{
|
||||
if (tmp_idx_colors[a.wait_id] < tmp_idx_colors[b.wait_id])
|
||||
return true;
|
||||
if (tmp_idx_colors[b.wait_id] < tmp_idx_colors[a.wait_id])
|
||||
return false;
|
||||
return a.samples < b.samples;
|
||||
}
|
||||
|
||||
void WaitSample::EndSeriosSample() {
|
||||
int end_index = smp.size();
|
||||
if ((end_index - start_index_serios) < 2) return;
|
||||
// sort
|
||||
//(std::list<int>::iterator it = C.begin(), end = C.end(); it != end; ++it)
|
||||
std::vector<Sample>::iterator it = smp.end();
|
||||
it = it - (end_index - start_index_serios);
|
||||
tmp_idx_colors = colors;
|
||||
std::sort(it, smp.end(), compareBySample);
|
||||
return;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue