Skip to content

Commit

Permalink
Batch fetching details for visibility notifications (#370)
Browse files Browse the repository at this point in the history
  • Loading branch information
dotchev authored and NickyMateev committed Dec 16, 2019
1 parent 16f6c62 commit 8598d3c
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 44 deletions.
21 changes: 21 additions & 0 deletions pkg/types/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,24 @@ type ObjectPage struct {
ItemsCount int `json:"num_items"`
Items []Object `json:"items"`
}

// ObjectArray is an ObjectList backed by a slice of Object's
type ObjectArray struct {
Objects []Object
}

func NewObjectArray(objects ...Object) *ObjectArray {
return &ObjectArray{objects}
}

func (a *ObjectArray) Add(object Object) {
a.Objects = append(a.Objects, object)
}

func (a *ObjectArray) ItemAt(index int) Object {
return a.Objects[index]
}

func (a *ObjectArray) Len() int {
return len(a.Objects)
}
17 changes: 9 additions & 8 deletions storage/interceptors/broker_notifications_interceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"context"
"fmt"

"github.com/Peripli/service-manager/pkg/util"

"github.com/Peripli/service-manager/pkg/types"
"github.com/Peripli/service-manager/storage"
)
Expand All @@ -15,12 +13,15 @@ func NewBrokerNotificationsInterceptor() *NotificationsInterceptor {
PlatformIdProviderFunc: func(ctx context.Context, obj types.Object) string {
return ""
},
AdditionalDetailsFunc: func(ctx context.Context, obj types.Object, repository storage.Repository) (util.InputValidator, error) {
broker := obj.(*types.ServiceBroker)

return &BrokerAdditional{
Services: broker.Services,
}, nil
AdditionalDetailsFunc: func(ctx context.Context, objects types.ObjectList, repository storage.Repository) (objectDetails, error) {
details := make(objectDetails, objects.Len())
for i := 0; i < objects.Len(); i++ {
broker := objects.ItemAt(i).(*types.ServiceBroker)
details[broker.ID] = &BrokerAdditional{
Services: broker.Services,
}
}
return details, nil
},
}
}
Expand Down
26 changes: 11 additions & 15 deletions storage/interceptors/notifications_interceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ type ObjectPayload struct {
Additional util.InputValidator `json:"additional,omitempty"`
}

type objectDetails map[string]util.InputValidator

type NotificationsInterceptor struct {
PlatformIdProviderFunc func(ctx context.Context, object types.Object) string
AdditionalDetailsFunc func(ctx context.Context, object types.Object, repository storage.Repository) (util.InputValidator, error)
AdditionalDetailsFunc func(ctx context.Context, objects types.ObjectList, repository storage.Repository) (objectDetails, error)
}

func (ni *NotificationsInterceptor) OnTxCreate(h storage.InterceptCreateOnTxFunc) storage.InterceptCreateOnTxFunc {
Expand All @@ -40,7 +42,7 @@ func (ni *NotificationsInterceptor) OnTxCreate(h storage.InterceptCreateOnTxFunc
return nil, err
}

additionalDetails, err := ni.AdditionalDetailsFunc(ctx, obj, repository)
additionalDetails, err := ni.AdditionalDetailsFunc(ctx, types.NewObjectArray(obj), repository)
if err != nil {
return nil, err
}
Expand All @@ -50,7 +52,7 @@ func (ni *NotificationsInterceptor) OnTxCreate(h storage.InterceptCreateOnTxFunc
return newObj, CreateNotification(ctx, repository, types.CREATED, newObj.GetType(), platformID, &Payload{
New: &ObjectPayload{
Resource: newObj,
Additional: additionalDetails,
Additional: additionalDetails[obj.GetID()],
},
})
}
Expand All @@ -63,10 +65,11 @@ func (ni *NotificationsInterceptor) OnTxUpdate(h storage.InterceptUpdateOnTxFunc
return nil, err
}

additionalDetails, err := ni.AdditionalDetailsFunc(ctx, updatedObject, repository)
detailsMap, err := ni.AdditionalDetailsFunc(ctx, types.NewObjectArray(updatedObject), repository)
if err != nil {
return nil, err
}
additionalDetails := detailsMap[updatedObject.GetID()]

oldPlatformID := ni.PlatformIdProviderFunc(ctx, oldObject)
newPlatformID := ni.PlatformIdProviderFunc(ctx, newObject)
Expand Down Expand Up @@ -113,16 +116,9 @@ func (ni *NotificationsInterceptor) OnTxUpdate(h storage.InterceptUpdateOnTxFunc

func (ni *NotificationsInterceptor) OnTxDelete(h storage.InterceptDeleteOnTxFunc) storage.InterceptDeleteOnTxFunc {
return func(ctx context.Context, repository storage.Repository, objects types.ObjectList, deletionCriteria ...query.Criterion) error {
additionalDetailsMap := make(map[string]util.InputValidator)

for i := 0; i < objects.Len(); i++ {
object := objects.ItemAt(i)
additionalDetails, err := ni.AdditionalDetailsFunc(ctx, object, repository)
if err != nil {
return err
}

additionalDetailsMap[object.GetID()] = additionalDetails
additionalDetails, err := ni.AdditionalDetailsFunc(ctx, objects, repository)
if err != nil {
return err
}

if err := h(ctx, repository, objects, deletionCriteria...); err != nil {
Expand All @@ -137,7 +133,7 @@ func (ni *NotificationsInterceptor) OnTxDelete(h storage.InterceptDeleteOnTxFunc
if err := CreateNotification(ctx, repository, types.DELETED, oldObject.GetType(), platformID, &Payload{
Old: &ObjectPayload{
Resource: oldObject,
Additional: additionalDetailsMap[oldObject.GetID()],
Additional: additionalDetails[oldObject.GetID()],
},
}); err != nil {
return err
Expand Down
122 changes: 101 additions & 21 deletions storage/interceptors/visibility_notifications_interceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (

"github.com/Peripli/service-manager/pkg/query"

"github.com/Peripli/service-manager/pkg/util"

"github.com/Peripli/service-manager/pkg/types"
"github.com/Peripli/service-manager/storage"
)
Expand All @@ -17,40 +15,122 @@ func NewVisibilityNotificationsInterceptor() *NotificationsInterceptor {
PlatformIdProviderFunc: func(ctx context.Context, obj types.Object) string {
return obj.(*types.Visibility).PlatformID
},
AdditionalDetailsFunc: func(ctx context.Context, obj types.Object, repository storage.Repository) (util.InputValidator, error) {
visibility := obj.(*types.Visibility)
AdditionalDetailsFunc: func(ctx context.Context, objects types.ObjectList, repository storage.Repository) (objectDetails, error) {
var visibilities []*types.Visibility
switch t := objects.(type) {
case *types.Visibilities:
visibilities = t.Visibilities
default:
visibilities = make([]*types.Visibility, objects.Len())
for i := 0; i < objects.Len(); i++ {
visibilities[i] = objects.ItemAt(i).(*types.Visibility)
}
}
if len(visibilities) == 0 {
return objectDetails{}, nil
}

byPlanID := query.ByField(query.EqualsOperator, "id", visibility.ServicePlanID)
plan, err := repository.Get(ctx, types.ServicePlanType, byPlanID)
plans, err := fetchVisibilityPlans(ctx, repository, visibilities)
if err != nil {
return nil, err
}
servicePlan := plan.(*types.ServicePlan)

byServiceID := query.ByField(query.EqualsOperator, "id", servicePlan.ServiceOfferingID)
service, err := repository.Get(ctx, types.ServiceOfferingType, byServiceID)
offerings, err := fetchPlanOfferings(ctx, repository, plans)
if err != nil {
return nil, err
}
serviceOffering := service.(*types.ServiceOffering)

byBrokerID := query.ByField(query.EqualsOperator, "id", serviceOffering.BrokerID)
broker, err := repository.Get(ctx, types.ServiceBrokerType, byBrokerID)
brokers, err := fetchOfferingBrokers(ctx, repository, offerings)
if err != nil {
return nil, err
}

serviceBroker := broker.(*types.ServiceBroker)

return &VisibilityAdditional{
BrokerID: serviceBroker.ID,
BrokerName: serviceBroker.Name,
ServicePlan: plan.(*types.ServicePlan),
}, nil
details := make(objectDetails, len(visibilities))
for _, vis := range visibilities {
plan := plans[vis.ServicePlanID]
offering := offerings[plan.ServiceOfferingID]
broker := brokers[offering.BrokerID]
details[vis.ID] = &VisibilityAdditional{
BrokerID: broker.ID,
BrokerName: broker.Name,
ServicePlan: plan,
}
}
return details, nil
},
}
}

func fetchVisibilityPlans(ctx context.Context, repository storage.Repository, visibilities []*types.Visibility) (map[string]*types.ServicePlan, error) {
planSet := make(map[string]bool, len(visibilities))
for _, vis := range visibilities {
planSet[vis.ServicePlanID] = true
}
planIDs := make([]string, len(planSet))
i := 0
for id := range planSet {
planIDs[i] = id
i++
}
list, err := repository.List(ctx, types.ServicePlanType,
query.ByField(query.InOperator, "id", planIDs...))
if err != nil {
return nil, err
}
plans := list.(*types.ServicePlans).ServicePlans
planMap := make(map[string]*types.ServicePlan, len(plans))
for _, plan := range plans {
planMap[plan.ID] = plan
}
return planMap, nil
}

func fetchPlanOfferings(ctx context.Context, repository storage.Repository, plans map[string]*types.ServicePlan) (map[string]*types.ServiceOffering, error) {
offeringSet := make(map[string]bool, len(plans))
for _, plan := range plans {
offeringSet[plan.ServiceOfferingID] = true
}
offeringIDs := make([]string, len(offeringSet))
i := 0
for id := range offeringSet {
offeringIDs[i] = id
i++
}
list, err := repository.List(ctx, types.ServiceOfferingType,
query.ByField(query.InOperator, "id", offeringIDs...))
if err != nil {
return nil, err
}
offerings := list.(*types.ServiceOfferings).ServiceOfferings
offeringMap := make(map[string]*types.ServiceOffering, len(offerings))
for _, offering := range offerings {
offeringMap[offering.ID] = offering
}
return offeringMap, nil
}

func fetchOfferingBrokers(ctx context.Context, repository storage.Repository, offerings map[string]*types.ServiceOffering) (map[string]*types.ServiceBroker, error) {
brokerSet := make(map[string]bool, len(offerings))
for _, offering := range offerings {
brokerSet[offering.BrokerID] = true
}
brokerIDs := make([]string, len(brokerSet))
i := 0
for id := range brokerSet {
brokerIDs[i] = id
i++
}
list, err := repository.List(ctx, types.ServiceBrokerType,
query.ByField(query.InOperator, "id", brokerIDs...))
if err != nil {
return nil, err
}
brokers := list.(*types.ServiceBrokers).ServiceBrokers
brokerMap := make(map[string]*types.ServiceBroker, len(brokers))
for _, broker := range brokers {
brokerMap[broker.ID] = broker
}
return brokerMap, nil
}

type VisibilityAdditional struct {
BrokerID string `json:"broker_id"`
BrokerName string `json:"broker_name"`
Expand Down

0 comments on commit 8598d3c

Please sign in to comment.