diff --git a/web/pgadmin/dashboard/static/js/Graphs.jsx b/web/pgadmin/dashboard/static/js/Graphs.jsx index 7f2eae22825..30175820c30 100644 --- a/web/pgadmin/dashboard/static/js/Graphs.jsx +++ b/web/pgadmin/dashboard/static/js/Graphs.jsx @@ -64,16 +64,27 @@ export function statsReducer(state, action) { action.counterData = action.incoming; } + /* When the counter represents a rate (e.g. transactions per second), + * the raw delta between two polls must be normalised by the number of + * seconds elapsed between them, otherwise it only reads correctly when + * the refresh interval happens to be 1 second. + */ + let rate = action.rate || 1; + let newState = {}; Object.keys(action.incoming).forEach(label => { + let value = action.incoming[label]; + if(action.counter) { + value = (action.incoming[label] - action.counterData[label]) / rate; + } if(state[label]) { newState[label] = [ - action.counter ? action.incoming[label] - action.counterData[label] : action.incoming[label], + value, ...state[label].slice(0, X_AXIS_LENGTH-1), ]; } else { newState[label] = [ - action.counter ? action.incoming[label] - action.counterData[label] : action.incoming[label], + value, ]; } }); @@ -114,6 +125,14 @@ export default function Graphs({preferences, sid, did, pageVisible, enablePoll=t } if(prevPrefernces['tps_stats_refresh'] != preferences['tps_stats_refresh']) { tpsStatsReduce({reset:chartsDefault['tps_stats']}); + /* The rate divisor is changing, so the previous counter baseline + * can no longer be used to compute the next delta. + */ + setCounterData((prevCounterData)=>{ + const nextCounterData = {...prevCounterData}; + delete nextCounterData['tps_stats']; + return nextCounterData; + }); calcPollDelay = true; } if(prevPrefernces['ti_stats_refresh'] != preferences['ti_stats_refresh']) { @@ -169,7 +188,7 @@ export default function Graphs({preferences, sid, did, pageVisible, enablePoll=t let data = resp.data; setErrorMsg(null); sessionStatsReduce({incoming: data['session_stats']}); - tpsStatsReduce({incoming: data['tps_stats'], counter: true, counterData: counterData['tps_stats']}); + tpsStatsReduce({incoming: data['tps_stats'], counter: true, counterData: counterData['tps_stats'], rate: preferences['tps_stats_refresh']}); tiStatsReduce({incoming: data['ti_stats'], counter: true, counterData: counterData['ti_stats']}); toStatsReduce({incoming: data['to_stats'], counter: true, counterData: counterData['to_stats']}); bioStatsReduce({incoming: data['bio_stats'], counter: true, counterData: counterData['bio_stats']}); diff --git a/web/regression/javascript/dashboard/graphs_spec.js b/web/regression/javascript/dashboard/graphs_spec.js index d02cd3488fa..6e2aa4a5b0d 100644 --- a/web/regression/javascript/dashboard/graphs_spec.js +++ b/web/regression/javascript/dashboard/graphs_spec.js @@ -72,6 +72,25 @@ describe('Graphs.js', ()=>{ expect(state).toEqual(newState); }); + it('with incoming with counter and rate', ()=>{ + let state = { + 'Label1': [1], 'Label2': [2], + }; + let action = { + incoming: { + 'Label1': 11, 'Label2': 23, + }, + counter: true, + counterData: {'Label1': 1, 'Label2': 3}, + rate: 5, + }; + let newState = { + 'Label1': [2, 1], 'Label2': [4, 2], + }; + state = statsReducer(state, action); + expect(state).toEqual(newState); + }); + it('with reset', ()=>{ let state = { 'Label1': [0, 1], 'Label2': [1, 2],