88 lines
2.2 KiB
Go
88 lines
2.2 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
"github.com/go-mysql-org/go-mysql/mysql"
|
|
|
|
"dashboard-cdc-worker/internal/config"
|
|
)
|
|
|
|
const serviceName = "dashboard-cdc-worker"
|
|
|
|
type MySQLRepository struct {
|
|
db *sql.DB
|
|
cfg config.Config
|
|
}
|
|
|
|
func NewMySQLRepository(db *sql.DB, cfg config.Config) *MySQLRepository {
|
|
return &MySQLRepository{db: db, cfg: cfg}
|
|
}
|
|
|
|
func (r *MySQLRepository) WithTx(ctx context.Context, fn func(*sql.Tx) error) error {
|
|
tx, err := r.db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelReadCommitted})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := fn(tx); err != nil {
|
|
_ = tx.Rollback()
|
|
return err
|
|
}
|
|
return tx.Commit()
|
|
}
|
|
|
|
func (r *MySQLRepository) LoadCheckpoint(ctx context.Context) (mysql.Position, bool, error) {
|
|
var file string
|
|
var pos uint32
|
|
err := r.db.QueryRowContext(ctx, `
|
|
SELECT binlog_file, binlog_pos
|
|
FROM dashboard_cdc_checkpoint
|
|
WHERE service_name = ?
|
|
`, serviceName).Scan(&file, &pos)
|
|
if err == sql.ErrNoRows {
|
|
return mysql.Position{}, false, nil
|
|
}
|
|
if err != nil {
|
|
return mysql.Position{}, false, err
|
|
}
|
|
return mysql.Position{Name: file, Pos: pos}, true, nil
|
|
}
|
|
|
|
func (r *MySQLRepository) SaveCheckpoint(ctx context.Context, pos mysql.Position) error {
|
|
_, err := r.db.ExecContext(ctx, `
|
|
INSERT INTO dashboard_cdc_checkpoint (service_name, binlog_file, binlog_pos, updated_at)
|
|
VALUES (?, ?, ?, NOW())
|
|
ON DUPLICATE KEY UPDATE
|
|
binlog_file = VALUES(binlog_file),
|
|
binlog_pos = VALUES(binlog_pos),
|
|
updated_at = NOW()
|
|
`, serviceName, pos.Name, pos.Pos)
|
|
return err
|
|
}
|
|
|
|
func (r *MySQLRepository) MarkEventApplied(ctx context.Context, tx *sql.Tx, eventKey string, source string) (bool, error) {
|
|
result, err := tx.ExecContext(ctx, `
|
|
INSERT IGNORE INTO dashboard_cdc_event_dedup (event_key, source, created_at)
|
|
VALUES (?, ?, NOW())
|
|
`, eventKey, source)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return affected > 0, nil
|
|
}
|
|
|
|
func execAll(ctx context.Context, db *sql.DB, statements []string) error {
|
|
for _, stmt := range statements {
|
|
if _, err := db.ExecContext(ctx, stmt); err != nil {
|
|
return fmt.Errorf("exec schema failed: %w; sql=%s", err, stmt)
|
|
}
|
|
}
|
|
return nil
|
|
}
|