Skip to content
This repository was archived by the owner on Jul 6, 2021. It is now read-only.

Commit 70df898

Browse files
committed
Merge branch 'dmius-f00x-conclusions-recommedations' into 'master'
F002,F004 conclusions and recommendations implemented See merge request postgres-ai/postgres-checkup!317
2 parents 05167b7 + 38b5615 commit 70df898

File tree

12 files changed

+730
-4
lines changed

12 files changed

+730
-4
lines changed

pghrep/src/checkup/a008/a008.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func A008PreprocessReportData(data map[string]interface{}) {
117117
var report A008Report
118118
err := json.Unmarshal(jsonRaw, &report)
119119
if err != nil {
120-
log.Err("Can't load json report to process")
120+
log.Err("Cannot load json report to process")
121121
return
122122
}
123123
result := A008Process(report)

pghrep/src/checkup/a008/a008_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func printReccomendations(result checkup.ReportOutcome) {
1919
}
2020
}
2121

22-
func TestA008Sucess(t *testing.T) {
22+
func TestA008Success(t *testing.T) {
2323
fmt.Println(t.Name())
2424
var report A008Report
2525
var hostResult A008ReportHostResult
@@ -36,7 +36,7 @@ func TestA008Sucess(t *testing.T) {
3636
report.Results = A008ReportHostsResults{"test-host": hostResult}
3737
result := A008Process(report)
3838
if result.P1 || result.P2 || result.P3 {
39-
t.Fatal("TestSucess failed")
39+
t.Fatal("TestA008Success failed")
4040
}
4141
printConclusions(result)
4242
printReccomendations(result)

pghrep/src/checkup/checkuputil.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func SaveJsonConclusionsRecommendations(data map[string]interface{}, conclusions
9494
}
9595
}
9696

97-
func SaveConclusionsRecommendations(data map[string]interface{},
97+
func SaveConclusionsRecommendations(data map[string]interface{},
9898
result ReportOutcome) map[string]interface{} {
9999
data["conclusions"] = result.Conclusions
100100
data["recommendations"] = result.Recommendations
@@ -104,3 +104,15 @@ func SaveConclusionsRecommendations(data map[string]interface{},
104104
SaveJsonConclusionsRecommendations(data, result.Conclusions, result.Recommendations, result.P1, result.P2, result.P3)
105105
return data
106106
}
107+
108+
func PrintConclusions(result ReportOutcome) {
109+
for _, conclusion := range result.Conclusions {
110+
fmt.Println("C: ", conclusion)
111+
}
112+
}
113+
114+
func PrintReccomendations(result ReportOutcome) {
115+
for _, recommendation := range result.Recommendations {
116+
fmt.Println("R: ", recommendation)
117+
}
118+
}

pghrep/src/checkup/f002/f002.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package f002
2+
3+
import (
4+
"encoding/json"
5+
"strings"
6+
7+
"../../log"
8+
"../../pyraconv"
9+
10+
checkup ".."
11+
)
12+
13+
const CRITICAL_CAPACITY_USAGE float32 = 50.0
14+
15+
// Generate conclusions and recommendatons
16+
func F002Process(report F002Report) checkup.ReportOutcome {
17+
var result checkup.ReportOutcome
18+
var databases, tables []string
19+
for _, hostData := range report.Results {
20+
for db, dbData := range hostData.Data.Databases {
21+
if dbData.CapacityUsed > CRITICAL_CAPACITY_USAGE {
22+
databases = append(databases, "- database `"+db+"` \n")
23+
result.P1 = true
24+
}
25+
}
26+
for table, tableData := range hostData.Data.Tables {
27+
if tableData.CapacityUsed > CRITICAL_CAPACITY_USAGE {
28+
tables = append(tables, "- table `"+table+"` \n")
29+
result.P1 = true
30+
}
31+
}
32+
}
33+
items := strings.Join(databases, "") + strings.Join(tables, "")
34+
if len(databases) > 0 || len(tables) > 0 {
35+
result.AppendConclusion(MSG_RISKS_ARE_HIGH_CONCLUSION, items)
36+
result.AppendRecommendation(MSG_RISKS_ARE_HIGH_RECOMMENDATION)
37+
}
38+
return result
39+
}
40+
41+
func F002PreprocessReportData(data map[string]interface{}) {
42+
filePath := pyraconv.ToString(data["source_path_full"])
43+
jsonRaw := checkup.LoadRawJsonReport(filePath)
44+
var report F002Report
45+
err := json.Unmarshal(jsonRaw, &report)
46+
if err != nil {
47+
log.Err("Cannot load json report to process")
48+
return
49+
}
50+
result := F002Process(report)
51+
if len(result.Recommendations) == 0 {
52+
result.AppendRecommendation(MSG_NO_RECOMMENDATIONS)
53+
}
54+
checkup.SaveConclusionsRecommendations(data, result)
55+
}
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package f002
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
checkup ".."
8+
)
9+
10+
func TestF002Success(t *testing.T) {
11+
fmt.Println(t.Name())
12+
var report F002Report
13+
var hostResult F002ReportHostResult
14+
hostResult.Data.Databases = map[string]F002Database{
15+
"database_1": F002Database{
16+
Num: 1,
17+
DatabaseName: "database_1",
18+
Age: 1,
19+
CapacityUsed: 34,
20+
Datfrozenxid: "",
21+
Warning: 0,
22+
},
23+
"database_2": F002Database{
24+
Num: 2,
25+
DatabaseName: "database_2",
26+
Age: 1,
27+
CapacityUsed: 37,
28+
Datfrozenxid: "",
29+
Warning: 0,
30+
},
31+
}
32+
33+
report.Results = F002ReportHostsResults{"test-host": hostResult}
34+
result := F002Process(report)
35+
if result.P1 || result.P2 || result.P3 {
36+
t.Fatal("TestF002Success failed")
37+
}
38+
checkup.PrintConclusions(result)
39+
checkup.PrintReccomendations(result)
40+
}
41+
42+
func TestF002ChecDatabases(t *testing.T) {
43+
fmt.Println(t.Name())
44+
var report F002Report
45+
var hostResult F002ReportHostResult
46+
hostResult.Data.Databases = map[string]F002Database{
47+
"database_1": F002Database{
48+
Num: 1,
49+
DatabaseName: "database_1",
50+
Age: 1,
51+
CapacityUsed: 76,
52+
Datfrozenxid: "",
53+
Warning: 0,
54+
},
55+
"database_2": F002Database{
56+
Num: 2,
57+
DatabaseName: "database_2",
58+
Age: 1,
59+
CapacityUsed: 37,
60+
Datfrozenxid: "",
61+
Warning: 0,
62+
},
63+
}
64+
65+
report.Results = F002ReportHostsResults{"test-host": hostResult}
66+
result := F002Process(report)
67+
if !result.P1 {
68+
t.Fatal("TestF002Sucess failed")
69+
}
70+
checkup.PrintConclusions(result)
71+
checkup.PrintReccomendations(result)
72+
}
73+
74+
func TestF002ChecTables(t *testing.T) {
75+
fmt.Println(t.Name())
76+
var report F002Report
77+
var hostResult F002ReportHostResult
78+
hostResult.Data.Databases = map[string]F002Database{
79+
"database_1": F002Database{
80+
Num: 1,
81+
DatabaseName: "database_1",
82+
Age: 1,
83+
CapacityUsed: 36,
84+
Datfrozenxid: "",
85+
Warning: 0,
86+
},
87+
"database_2": F002Database{
88+
Num: 2,
89+
DatabaseName: "database_2",
90+
Age: 1,
91+
CapacityUsed: 37,
92+
Datfrozenxid: "",
93+
Warning: 0,
94+
},
95+
}
96+
hostResult.Data.Tables = map[string]F002Table{
97+
"table_1": F002Table{
98+
Num: 1,
99+
Relation: "table_1",
100+
Age: 0,
101+
CapacityUsed: 43,
102+
RelRelfrozenxid: "",
103+
ToastRelfrozenxid: "",
104+
Warning: 0,
105+
OverridedSettings: false,
106+
},
107+
"table_2": F002Table{
108+
Num: 1,
109+
Relation: "table_2",
110+
Age: 0,
111+
CapacityUsed: 76,
112+
RelRelfrozenxid: "",
113+
ToastRelfrozenxid: "",
114+
Warning: 0,
115+
OverridedSettings: false,
116+
},
117+
}
118+
119+
report.Results = F002ReportHostsResults{"test-host": hostResult}
120+
result := F002Process(report)
121+
if !result.P1 {
122+
t.Fatal("TestF002Sucess failed")
123+
}
124+
checkup.PrintConclusions(result)
125+
checkup.PrintReccomendations(result)
126+
}
127+
128+
func TestF002ChecDatabaseTables(t *testing.T) {
129+
fmt.Println(t.Name())
130+
var report F002Report
131+
var hostResult F002ReportHostResult
132+
hostResult.Data.Databases = map[string]F002Database{
133+
"database_1": F002Database{
134+
Num: 1,
135+
DatabaseName: "database_1",
136+
Age: 1,
137+
CapacityUsed: 56,
138+
Datfrozenxid: "",
139+
Warning: 0,
140+
},
141+
"database_2": F002Database{
142+
Num: 2,
143+
DatabaseName: "database_2",
144+
Age: 1,
145+
CapacityUsed: 37,
146+
Datfrozenxid: "",
147+
Warning: 0,
148+
},
149+
}
150+
hostResult.Data.Tables = map[string]F002Table{
151+
"table_1": F002Table{
152+
Num: 1,
153+
Relation: "table_1",
154+
Age: 0,
155+
CapacityUsed: 43,
156+
RelRelfrozenxid: "",
157+
ToastRelfrozenxid: "",
158+
Warning: 0,
159+
OverridedSettings: false,
160+
},
161+
"table_2": F002Table{
162+
Num: 1,
163+
Relation: "table_2",
164+
Age: 0,
165+
CapacityUsed: 76,
166+
RelRelfrozenxid: "",
167+
ToastRelfrozenxid: "",
168+
Warning: 0,
169+
OverridedSettings: false,
170+
},
171+
}
172+
173+
report.Results = F002ReportHostsResults{"test-host": hostResult}
174+
result := F002Process(report)
175+
if !result.P1 {
176+
t.Fatal("TestF002Sucess failed")
177+
}
178+
checkup.PrintConclusions(result)
179+
checkup.PrintReccomendations(result)
180+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package f002
2+
3+
const MSG_RISKS_ARE_HIGH_CONCLUSION string = "[P1] Risks of transaction ID wraparound are high for: \n" +
4+
"%s \n" +
5+
"Approaching 100%% leads to downtime: the system will shut down and refuse to start any new transactions. \n" +
6+
"More on this topic: \n" +
7+
"- [PostgreSQL Documentation. 24.1.5. Preventing Transaction ID Wraparound Failures](https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND) \n" +
8+
"- [The Internals of PostgreSQL. Chapter 5. Concurrency Control. 5.10.1. FREEZE Processing](http://www.interdb.jp/pg/pgsql05.html#_5.10.1.) \n" +
9+
"- [Transaction ID Wraparound in Postgres](https://blog.sentry.io/2015/07/23/transaction-id-wraparound-in-postgres) (2015, Sentry blog) \n" +
10+
"- [Autovacuum wraparound protection in PostgreSQL](https://www.cybertec-postgresql.com/en/autovacuum-wraparound-protection-in-postgresql/) (2017, Cybertec blog) \n" +
11+
"- [What We Learned from the Recent Mandrill Outage](https://mailchimp.com/what-we-learned-from-the-recent-mandrill-outage/) (2019, Mailchimp blog) \n" +
12+
"- [Managing Transaction ID Exhaustion (Wraparound) in PostgreSQL](https://info.crunchydata.com/blog/managing-transaction-id-wraparound-in-postgresql) (2019, Crunchy Data blog) \n"
13+
14+
const MSG_RISKS_ARE_HIGH_RECOMMENDATION string = "[P1] To minimize risks of transaction ID wraparound do the following: \n" +
15+
"1. Run `VACUUM FREEZE` for mentioned tables. \n" +
16+
"2. Perform autovacuum tuning to ensure that autovacuum has enough resources and runs often enough to minimize risks of transaction ID wraparound. Read articles provided in the \"Conclusions\" section for more details. "
17+
18+
const MSG_NO_RECOMMENDATIONS string = "No recommendations."
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package f002
2+
3+
import checkup ".."
4+
5+
// Instace databases list
6+
type F002Database struct {
7+
Num int `json:"num"`
8+
DatabaseName string `json:"datname"`
9+
Age int `json:"age"`
10+
CapacityUsed float32 `json:"capacity_used"`
11+
Datfrozenxid string `json:"datfrozenxid"`
12+
Warning int `json:"warning"`
13+
}
14+
15+
// Current database tables list
16+
type F002Table struct {
17+
Num int `json:"num"`
18+
Relation string `json:"relation"`
19+
Age int `json:"age"`
20+
CapacityUsed float32 `json:"capacity_used"`
21+
RelRelfrozenxid string `json:"rel_relfrozenxid"`
22+
ToastRelfrozenxid string `json:"toast_relfrozenxid"`
23+
Warning int `json:"warning"`
24+
OverridedSettings bool `json:"overrided_settings"`
25+
}
26+
27+
type F002ReportHostResultData struct {
28+
Databases map[string]F002Database `json:"per_instance"`
29+
Tables map[string]F002Table `json:"per_database"`
30+
}
31+
32+
type F002ReportHostResult struct {
33+
Data F002ReportHostResultData `json:"data"`
34+
NodesJson checkup.ReportLastNodes `json:"nodes.json"`
35+
}
36+
37+
type F002ReportHostsResults map[string]F002ReportHostResult
38+
39+
type F002Report struct {
40+
Project string `json:"project"`
41+
Name string `json:"name"`
42+
CheckId string `json:"checkId"`
43+
Timestamptz string `json:"timestamptz"`
44+
Database string `json:"database"`
45+
Dependencies map[string]interface{} `json:"dependencies"`
46+
LastNodesJson checkup.ReportLastNodes `json:"last_nodes_json"`
47+
Results F002ReportHostsResults `json:"results"`
48+
}

0 commit comments

Comments
 (0)