Skip to content

Commit

Permalink
Random test failures because of work item creation error (fabric8-ser…
Browse files Browse the repository at this point in the history
…vices#1676)

Make sure that a sequence number initialized at `0` is created
when the space itself is created, in order to allow for locking
of the row in the `work_item_sequence_numbers` table.

Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
  • Loading branch information
xcoulon committed Oct 2, 2017
1 parent 27d530d commit 736cdbe
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 14 deletions.
6 changes: 6 additions & 0 deletions space/space.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/fabric8-services/fabric8-wit/errors"
"github.com/fabric8-services/fabric8-wit/gormsupport"
"github.com/fabric8-services/fabric8-wit/log"
workitemnumber "github.com/fabric8-services/fabric8-wit/workitem/number"

"github.com/goadesign/goa"
"github.com/jinzhu/gorm"
Expand Down Expand Up @@ -225,6 +226,11 @@ func (r *GormRepository) Create(ctx context.Context, space *Space) (*Space, erro
}
return nil, errors.NewInternalError(ctx, err)
}
// also, initialize the work_item_number_sequence table for this space
numberSequence := workitemnumber.WorkItemNumberSequence{CurrentVal: 0, SpaceID: space.ID}
if err := r.db.Save(&numberSequence).Error; err != nil {
return nil, errs.Wrapf(err, "failed to create work item with sequence number: `%s`", numberSequence.String())
}

log.Info(ctx, map[string]interface{}{
"space_id": space.ID,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package workitem
package number

import (
"fmt"

uuid "github.com/satori/go.uuid"
)

Expand All @@ -18,3 +20,7 @@ const (
func (w WorkItemNumberSequence) TableName() string {
return workitemNumberTableName
}

func (w *WorkItemNumberSequence) String() string {
return fmt.Sprintf("SpaceId=%s Number=%d", w.SpaceID.String(), w.CurrentVal)
}
44 changes: 44 additions & 0 deletions workitem/number/workitem_number_repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package number

import (
"context"

"github.com/jinzhu/gorm"
errs "github.com/pkg/errors"
uuid "github.com/satori/go.uuid"
)

// WorkItemNumberSequenceRepository the interface for the work item number sequence repository
type WorkItemNumberSequenceRepository interface {
NextVal(ctx context.Context, spaceID uuid.UUID) (*WorkItemNumberSequence, error)
}

// NewWorkItemSequenceNumberRepository creates a GormWorkItemNumberSequenceRepository
func NewWorkItemSequenceNumberRepository(db *gorm.DB) *GormWorkItemNumberSequenceRepository {
repository := &GormWorkItemNumberSequenceRepository{db}
return repository
}

// GormWorkItemNumberSequenceRepository implements WorkItemNumberSequenceRepository using gorm
type GormWorkItemNumberSequenceRepository struct {
db *gorm.DB
}

// NextVal returns the next work item sequence number for the given space ID. Creates an entry in the DB if none was found before
func (r *GormWorkItemNumberSequenceRepository) NextVal(ctx context.Context, spaceID uuid.UUID) (*WorkItemNumberSequence, error) {
// retrieve the current issue number in the given space
r.db.LogMode(true)
defer r.db.LogMode(false)
numberSequence := WorkItemNumberSequence{}
tx := r.db.Model(&WorkItemNumberSequence{}).Set("gorm:query_option", "FOR UPDATE").Where("space_id = ?", spaceID).First(&numberSequence)
if tx.RecordNotFound() {
numberSequence.SpaceID = spaceID
numberSequence.CurrentVal = 1
} else {
numberSequence.CurrentVal++
}
if err := r.db.Save(&numberSequence).Error; err != nil {
return nil, errs.Wrapf(err, "failed to create work item with sequence number: `%s`", numberSequence.String())
}
return &numberSequence, nil
}
25 changes: 12 additions & 13 deletions workitem/workitem_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/fabric8-services/fabric8-wit/log"
"github.com/fabric8-services/fabric8-wit/rendering"
"github.com/fabric8-services/fabric8-wit/space"
workitemnumber "github.com/fabric8-services/fabric8-wit/workitem/number"

"github.com/goadesign/goa"
"github.com/jinzhu/gorm"
Expand Down Expand Up @@ -53,13 +54,19 @@ type WorkItemRepository interface {

// NewWorkItemRepository creates a GormWorkItemRepository
func NewWorkItemRepository(db *gorm.DB) *GormWorkItemRepository {
repository := &GormWorkItemRepository{db, &GormWorkItemTypeRepository{db}, &GormRevisionRepository{db}}
repository := &GormWorkItemRepository{
db,
workitemnumber.NewWorkItemSequenceNumberRepository(db),
&GormWorkItemTypeRepository{db},
&GormRevisionRepository{db},
}
return repository
}

// GormWorkItemRepository implements WorkItemRepository using gorm
type GormWorkItemRepository struct {
db *gorm.DB
winr *workitemnumber.GormWorkItemNumberSequenceRepository
witr *GormWorkItemTypeRepository
wirr *GormRevisionRepository
}
Expand Down Expand Up @@ -551,25 +558,17 @@ func (r *GormWorkItemRepository) Create(ctx context.Context, spaceID uuid.UUID,
if err != nil {
return nil, errors.NewBadParameterError("typeID", typeID)
}
// retrieve the current issue number in the given space
numberSequence := WorkItemNumberSequence{}
tx := r.db.Model(&WorkItemNumberSequence{}).Set("gorm:query_option", "FOR UPDATE").Where("space_id = ?", spaceID).First(&numberSequence)
if tx.RecordNotFound() {
numberSequence.SpaceID = spaceID
numberSequence.CurrentVal = 1
} else {
numberSequence.CurrentVal++
}
if err = r.db.Save(&numberSequence).Error; err != nil {
return nil, errs.Wrapf(err, "failed to create work item")
}

// The order of workitems are spaced by a factor of 1000.
pos, err := r.LoadHighestOrder(ctx, spaceID)
if err != nil {
return nil, errors.NewInternalError(ctx, err)
}
pos = pos + orderValue
numberSequence, err := r.winr.NextVal(ctx, spaceID)
if err != nil {
return nil, errors.NewInternalError(ctx, err)
}
wi := WorkItemStorage{
Type: typeID,
Fields: Fields{},
Expand Down

0 comments on commit 736cdbe

Please sign in to comment.