diff --git a/pkg/model/annotation.go b/pkg/model/annotation.go index ed0ceffa90..a7dfc820ea 100644 --- a/pkg/model/annotation.go +++ b/pkg/model/annotation.go @@ -16,8 +16,8 @@ var ( ) type Annotation struct { - AppName string `gorm:"not null;default:null"` - Timestamp time.Time `form:"not null;default:null"` + AppName string `gorm:"index:idx_appname_timestamp,unique;not null;default:null"` + Timestamp time.Time `gorm:"index:idx_appname_timestamp,unique;not null;default:null"` Content string `gorm:"not null;default:null"` CreatedAt time.Time UpdatedAt time.Time diff --git a/pkg/service/annotation.go b/pkg/service/annotation.go index 476461e7e8..d7316f5b6d 100644 --- a/pkg/service/annotation.go +++ b/pkg/service/annotation.go @@ -6,6 +6,7 @@ import ( "github.com/pyroscope-io/pyroscope/pkg/model" "gorm.io/gorm" + "gorm.io/gorm/clause" ) type AnnotationsService struct{ db *gorm.DB } @@ -30,11 +31,17 @@ func (svc AnnotationsService) CreateAnnotation(ctx context.Context, params model tx := svc.db.WithContext(ctx) // Upsert - if tx.Where(model.CreateAnnotation{ - AppName: params.AppName, - Timestamp: params.Timestamp, - }).Updates(&u).RowsAffected == 0 { - return &u, tx.Create(&u).Error + if err := tx.Clauses(clause.OnConflict{ + Columns: []clause.Column{ + {Name: "app_name"}, + {Name: "timestamp"}, + }, + // Update fields we care about + DoUpdates: clause.AssignmentColumns([]string{"app_name", "timestamp", "content"}), + // Update updateAt fields + UpdateAll: true, + }).Create(&u).Error; err != nil { + return nil, err } return &u, nil diff --git a/pkg/service/annotation_test.go b/pkg/service/annotation_test.go index 55c1efe905..faa0f1e3d9 100644 --- a/pkg/service/annotation_test.go +++ b/pkg/service/annotation_test.go @@ -34,7 +34,7 @@ var _ = Describe("AnnotationsService", func() { Expect(annotation).ToNot(BeNil()) Expect(annotation.AppName).To(Equal("myapp")) Expect(annotation.Content).To(Equal("mycontent")) - Expect(annotation.Timestamp).To(Equal(now)) + Expect(annotation.Timestamp.Unix()).To(Equal(now.Unix())) Expect(annotation.CreatedAt).ToNot(BeZero()) Expect(annotation.UpdatedAt).ToNot(BeZero()) diff --git a/pkg/sqlstore/migrations/migrations.go b/pkg/sqlstore/migrations/migrations.go index 02b77a1273..b867a7f20b 100644 --- a/pkg/sqlstore/migrations/migrations.go +++ b/pkg/sqlstore/migrations/migrations.go @@ -49,6 +49,7 @@ func Migrate(db *gorm.DB, c *config.Server) error { createUserTableMigration(c.Auth.Internal.AdminUser), createAPIKeyTableMigration(), createAnnotationsTableMigration(), + addIndexesUniqueTableMigration(), }).Migrate() } @@ -132,3 +133,20 @@ func createAnnotationsTableMigration() *gormigrate.Migration { }, } } + +func addIndexesUniqueTableMigration() *gormigrate.Migration { + type annotation struct { + AppName string `gorm:"index:idx_appname_timestamp,unique;not null;default:null"` + Timestamp time.Time `gorm:"index:idx_appname_timestamp,unique;not null;default:null"` + } + + return &gormigrate.Migration{ + ID: "1663269650", + Migrate: func(tx *gorm.DB) error { + return tx.AutoMigrate(&annotation{}) + }, + Rollback: func(tx *gorm.DB) error { + return tx.Migrator().DropIndex(&annotation{}, "idx_appname_timestamp") + }, + } +}