Add vacuums
This commit is contained in:
@@ -10,6 +10,11 @@ database:
|
||||
name: "himewiki"
|
||||
sslmode: "disable"
|
||||
|
||||
vacuum:
|
||||
check-every: 250
|
||||
threshold: 68719476736
|
||||
image-threshold: 68719476736
|
||||
|
||||
site:
|
||||
base: "https://wiki.example.org/"
|
||||
name: "HimeWiki"
|
||||
|
||||
@@ -80,7 +80,7 @@ func Edit(cfg *config.Config, w http.ResponseWriter, r *http.Request, params *Pa
|
||||
title, normalized, _, rendered := format.Apply(cfg, params.DbName, filtered)
|
||||
|
||||
if previewed && save != "" {
|
||||
if err := data.Save(params.DbName, normalized, revisionID); err != nil {
|
||||
if err := data.Save(cfg, params.DbName, normalized, revisionID); err != nil {
|
||||
http.Error(w, "Failed to save", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func Upload(cfg *config.Config, w http.ResponseWriter, r *http.Request, params *
|
||||
return
|
||||
}
|
||||
|
||||
if err := data.SaveImage(name, filtered); err != nil {
|
||||
if err := data.SaveImage(cfg, name, filtered); err != nil {
|
||||
http.Error(w, "Failed to save", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -22,6 +22,12 @@ type Config struct {
|
||||
SSLMode string `yaml:"sslmode"`
|
||||
} `yaml:"database"`
|
||||
|
||||
Vacuum struct {
|
||||
CheckEvery int `yaml:"check-every"`
|
||||
Threshold int64 `yaml:"threshold"`
|
||||
ImageThreshold int64 `yaml:"image-threshold"`
|
||||
} `yaml:"vacuum"`
|
||||
|
||||
Site struct {
|
||||
Base string `yaml:"base"`
|
||||
Name string `yaml:"name"`
|
||||
|
||||
@@ -199,7 +199,7 @@ func diff(oldText, newText string) string {
|
||||
return text
|
||||
}
|
||||
|
||||
func Save(name, content string, baseRevID int) error {
|
||||
func Save(cfg *config.Config, name, content string, baseRevID int) error {
|
||||
ctx := context.Background()
|
||||
tx, err := db.Begin(ctx)
|
||||
if err != nil {
|
||||
@@ -240,16 +240,68 @@ func Save(name, content string, baseRevID int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx,
|
||||
`UPDATE state
|
||||
SET page_counter = page_counter + 1
|
||||
WHERE id = 1`,
|
||||
)
|
||||
var pageCount int64
|
||||
err = tx.QueryRow(ctx, `
|
||||
UPDATE state
|
||||
SET page_counter = page_counter + 1
|
||||
WHERE id = 1
|
||||
RETURNING page_counter
|
||||
`).Scan(&pageCount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit(ctx)
|
||||
err = tx.Commit(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if pageCount % int64(cfg.Vacuum.CheckEvery) == 0 {
|
||||
var sizeBytes int64
|
||||
err = db.QueryRow(ctx, `
|
||||
SELECT pg_total_relation_size('pages') +
|
||||
pg_total_relation_size('revisions')
|
||||
`).Scan(&sizeBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sizeBytes >= cfg.Vacuum.Threshold {
|
||||
_, err = db.Exec(ctx, "VACUUM FULL pages")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec(ctx, `
|
||||
WITH cutoff AS (
|
||||
SELECT COUNT(*) / 2 AS limit_count
|
||||
FROM revisions
|
||||
GROUP BY name
|
||||
ORDER BY COUNT(*) DESC
|
||||
LIMIT 1
|
||||
)
|
||||
DELETE FROM revisions r
|
||||
USING cutoff
|
||||
WHERE r.id IN (
|
||||
SELECT id
|
||||
FROM revisions r2, cutoff
|
||||
WHERE r2.name = r.name
|
||||
ORDER BY r2.created_at ASC
|
||||
OFFSET cutoff.limit_count
|
||||
)
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec(ctx, "VACUUM FULL revisions")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoadAll(page int, perPage int) ([]string, error) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/akikareha/himewiki/internal/config"
|
||||
)
|
||||
|
||||
func LoadImage(name string) (int, []byte, error) {
|
||||
@@ -17,7 +19,7 @@ func LoadImage(name string) (int, []byte, error) {
|
||||
return id, content, nil
|
||||
}
|
||||
|
||||
func SaveImage(name string, content []byte) error {
|
||||
func SaveImage(cfg *config.Config, name string, content []byte) error {
|
||||
ctx := context.Background()
|
||||
tx, err := db.Begin(ctx)
|
||||
if err != nil {
|
||||
@@ -47,14 +49,66 @@ func SaveImage(name string, content []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx,
|
||||
`UPDATE state
|
||||
SET image_counter = image_counter + 1
|
||||
WHERE id = 1`,
|
||||
)
|
||||
var imageCount int64
|
||||
err = tx.QueryRow(ctx, `
|
||||
UPDATE state
|
||||
SET image_counter = image_counter + 1
|
||||
WHERE id = 1
|
||||
RETURNING image_counter
|
||||
`).Scan(&imageCount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit(ctx)
|
||||
err = tx.Commit(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if imageCount % int64(cfg.Vacuum.CheckEvery) == 0 {
|
||||
var sizeBytes int64
|
||||
err = db.QueryRow(ctx, `
|
||||
SELECT pg_total_relation_size('images') +
|
||||
pg_total_relation_size('image_revisions')
|
||||
`).Scan(&sizeBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sizeBytes >= cfg.Vacuum.ImageThreshold {
|
||||
_, err = db.Exec(ctx, "VACUUM FULL images")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec(ctx, `
|
||||
WITH cutoff AS (
|
||||
SELECT COUNT(*) / 2 AS limit_count
|
||||
FROM image_revisions
|
||||
GROUP BY name
|
||||
ORDER BY COUNT(*) DESC
|
||||
LIMIT 1
|
||||
)
|
||||
DELETE FROM image_revisions r
|
||||
USING cutoff
|
||||
WHERE r.id IN (
|
||||
SELECT id
|
||||
FROM image_revisions r2, cutoff
|
||||
WHERE r2.name = r.name
|
||||
ORDER BY r2.created_at ASC
|
||||
OFFSET cutoff.limit_count
|
||||
)
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec(ctx, "VACUUM FULL image_revisions")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user