diff options
Diffstat (limited to 'src/include/pgstat.h')
| -rw-r--r-- | src/include/pgstat.h | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 08925336d18..7285f3ee167 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -16,6 +16,7 @@ #include "libpq/pqcomm.h" #include "portability/instr_time.h" #include "postmaster/pgarch.h" +#include "storage/barrier.h" #include "utils/hsearch.h" #include "utils/relcache.h" @@ -714,6 +715,12 @@ typedef struct PgBackendStatus * st_changecount again. If the value hasn't changed, and if it's even, * the copy is valid; otherwise start over. This makes updates cheap * while reads are potentially expensive, but that's the tradeoff we want. + * + * The above protocol needs the memory barriers to ensure that + * the apparent order of execution is as it desires. Otherwise, + * for example, the CPU might rearrange the code so that st_changecount + * is incremented twice before the modification on a machine with + * weak memory ordering. This surprising result can lead to bugs. */ int st_changecount; @@ -745,6 +752,43 @@ typedef struct PgBackendStatus char *st_activity; } PgBackendStatus; +/* + * Macros to load and store st_changecount with the memory barriers. + * + * pgstat_increment_changecount_before() and + * pgstat_increment_changecount_after() need to be called before and after + * PgBackendStatus entries are modified, respectively. This makes sure that + * st_changecount is incremented around the modification. + * + * Also pgstat_save_changecount_before() and pgstat_save_changecount_after() + * need to be called before and after PgBackendStatus entries are copied into + * private memory, respectively. + */ +#define pgstat_increment_changecount_before(beentry) \ + do { \ + beentry->st_changecount++; \ + pg_write_barrier(); \ + } while (0) + +#define pgstat_increment_changecount_after(beentry) \ + do { \ + pg_write_barrier(); \ + beentry->st_changecount++; \ + Assert((beentry->st_changecount & 1) == 0); \ + } while (0) + +#define pgstat_save_changecount_before(beentry, save_changecount) \ + do { \ + save_changecount = beentry->st_changecount; \ + pg_read_barrier(); \ + } while (0) + +#define pgstat_save_changecount_after(beentry, save_changecount) \ + do { \ + pg_read_barrier(); \ + save_changecount = beentry->st_changecount; \ + } while (0) + /* ---------- * LocalPgBackendStatus * |
