Skip to content

Commit

Permalink
Fixes average stats bug (#436)
Browse files Browse the repository at this point in the history
* Add test

* Fix test

* Add fix
  • Loading branch information
zainkabani authored May 12, 2023
1 parent 5056cbe commit 7326069
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 14 deletions.
15 changes: 13 additions & 2 deletions src/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,19 @@ impl Collector {
loop {
interval.tick().await;

for stats in SERVER_STATS.read().values() {
stats.address_stats().update_averages();
// Hold read lock for duration of update to retain all server stats
let server_stats = SERVER_STATS.read();

for stats in server_stats.values() {
if !stats.check_address_stat_average_is_updated_status() {
stats.address_stats().update_averages();
stats.set_address_stat_average_is_updated_status(true);
}
}

// Reset to false for next update
for stats in server_stats.values() {
stats.set_address_stat_average_is_updated_status(false);
}
}
});
Expand Down
14 changes: 8 additions & 6 deletions src/stats/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ pub struct AddressStats {
pub avg_xact_time: Arc<AtomicU64>,
pub avg_xact_count: Arc<AtomicU64>,
pub avg_wait_time: Arc<AtomicU64>,

// Determines if the averages have been updated since the last time they were reported
pub averages_updated: Arc<AtomicBool>,
}

impl IntoIterator for AddressStats {
Expand Down Expand Up @@ -114,15 +117,14 @@ impl AddressStats {

pub fn update_averages(&self) {
let (totals, averages, old_totals) = self.fields_iterators();
for data in itertools::izip!(totals, averages, old_totals) {
let (total, average, old_total) = data;
let total = total.load(Ordering::Relaxed);
let old = old_total.load(Ordering::Relaxed);
for (total, average, old_total) in itertools::izip!(totals, averages, old_totals) {
let total_value = total.load(Ordering::Relaxed);
let old_total_value = old_total.load(Ordering::Relaxed);
average.store(
(total - old) / (crate::stats::STAT_PERIOD / 1_000),
(total_value - old_total_value) / (crate::stats::STAT_PERIOD / 1_000),
Ordering::Relaxed,
); // Avg / second
old_total.store(total, Ordering::Relaxed);
old_total.store(total_value, Ordering::Relaxed);
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/stats/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,17 @@ impl ServerStats {
self.address.stats.clone()
}

pub fn check_address_stat_average_is_updated_status(&self) -> bool {
self.address.stats.averages_updated.load(Ordering::Relaxed)
}

pub fn set_address_stat_average_is_updated_status(&self, is_checked: bool) {
self.address
.stats
.averages_updated
.store(is_checked, Ordering::Relaxed);
}

// Helper methods for show_servers
pub fn pool_name(&self) -> String {
self.pool_stats.database()
Expand Down
13 changes: 7 additions & 6 deletions tests/ruby/admin_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,20 @@
describe "SHOW STATS" do
context "clients connect and make one query" do
it "updates *_query_time and *_wait_time" do
connection = PG::connect("#{pgcat_conn_str}?application_name=one_query")
connection.async_exec("SELECT pg_sleep(0.25)")
connection.async_exec("SELECT pg_sleep(0.25)")
connection.async_exec("SELECT pg_sleep(0.25)")
connection.close
connections = Array.new(3) { PG::connect("#{pgcat_conn_str}?application_name=one_query") }
connections.each do |c|
Thread.new { c.async_exec("SELECT pg_sleep(0.25)") }
end
sleep(1)
connections.map(&:close)

# wait for averages to be calculated, we shouldn't do this too often
sleep(15.5)
admin_conn = PG::connect(processes.pgcat.admin_connection_string)
results = admin_conn.async_exec("SHOW STATS")[0]
admin_conn.close
expect(results["total_query_time"].to_i).to be_within(200).of(750)
expect(results["avg_query_time"].to_i).to_not eq(0)
expect(results["avg_query_time"].to_i).to be_within(20).of(50)

expect(results["total_wait_time"].to_i).to_not eq(0)
expect(results["avg_wait_time"].to_i).to_not eq(0)
Expand Down

0 comments on commit 7326069

Please sign in to comment.