Skip to content

Commit 3d8c945

Browse files
[CLD-361]: fix(operations): use map for operation registry (#187)
- Use map instead of slice for faster lookup in the operation registry - reduce duplicate logging JIRA: https://smartcontract-it.atlassian.net/browse/CLD-361
1 parent 8920e23 commit 3d8c945

File tree

3 files changed

+38
-16
lines changed

3 files changed

+38
-16
lines changed

.changeset/tidy-fans-wink.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"chainlink-deployments-framework": patch
3+
---
4+
5+
fix(operations): optimization on dynamic execution

operations/operation.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,7 @@ func (o *Operation[IN, OUT, DEP]) execute(b Bundle, deps DEP, input IN) (output
104104
// Warning: The input and output types will be converted to `any`, so type safety is lost.
105105
func (o *Operation[IN, OUT, DEP]) AsUntyped() *Operation[any, any, any] {
106106
return &Operation[any, any, any]{
107-
def: Definition{
108-
ID: o.def.ID,
109-
Version: o.def.Version,
110-
Description: o.def.Description,
111-
},
107+
def: o.def,
112108
handler: func(b Bundle, deps any, input any) (any, error) {
113109
var typedInput IN
114110
if input != nil {
@@ -126,7 +122,7 @@ func (o *Operation[IN, OUT, DEP]) AsUntyped() *Operation[any, any, any] {
126122
}
127123
}
128124

129-
return o.execute(b, typedDeps, typedInput)
125+
return o.handler(b, typedDeps, typedInput)
130126
},
131127
}
132128
}

operations/registry.go

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,58 @@
11
package operations
22

3-
import "errors"
3+
import (
4+
"errors"
5+
"fmt"
6+
)
7+
8+
var ErrOperationNotFound = errors.New("operation not found in registry")
49

510
// OperationRegistry is a store for operations that allows retrieval based on their definitions.
611
type OperationRegistry struct {
7-
ops []*Operation[any, any, any]
12+
ops map[string]*Operation[any, any, any]
813
}
914

1015
// NewOperationRegistry creates a new OperationRegistry with the provided untyped operations.
1116
func NewOperationRegistry(ops ...*Operation[any, any, any]) *OperationRegistry {
12-
return &OperationRegistry{
13-
ops: ops,
17+
reg := &OperationRegistry{
18+
ops: make(map[string]*Operation[any, any, any]),
19+
}
20+
for _, op := range ops {
21+
key := generateRegistryKey(op.Def())
22+
reg.ops[key] = op
1423
}
24+
25+
return reg
1526
}
1627

1728
// Retrieve retrieves an operation from the store based on its definition.
1829
// It returns an error if the operation is not found.
1930
// The definition must match the operation's ID and version.
31+
// Description of the definition is not used for retrieval, only ID and Version.
32+
// This allows for simplicity in retrieving operations with the same ID and version only without having to provide the description.
33+
// This is useful when definition has to be provided via manual input.
2034
func (s OperationRegistry) Retrieve(def Definition) (*Operation[any, any, any], error) {
21-
for _, op := range s.ops {
22-
if op.ID() == def.ID && op.Version() == def.Version.String() {
23-
return op, nil
24-
}
35+
key := generateRegistryKey(def)
36+
if op, ok := s.ops[key]; ok {
37+
return op, nil
2538
}
2639

27-
return nil, errors.New("operation not found in registry")
40+
return nil, ErrOperationNotFound
2841
}
2942

3043
// RegisterOperation registers new operations in the registry.
3144
// To register operations with different input, output, and dependency types,
3245
// call RegisterOperation multiple times with different type parameters.
46+
// If the same operation is registered multiple times, it will overwrite the previous one.
3347
func RegisterOperation[D, I, O any](r *OperationRegistry, op ...*Operation[D, I, O]) {
3448
for _, o := range op {
35-
r.ops = append(r.ops, o.AsUntyped())
49+
key := generateRegistryKey(o.Def())
50+
r.ops[key] = o.AsUntyped()
3651
}
3752
}
53+
54+
// generateRegistryKey creates a unique key for the operation registry based on the operation's ID and version.
55+
// This key is used to store and retrieve operations in the registry.
56+
func generateRegistryKey(def Definition) string {
57+
return fmt.Sprintf("%s:%s", def.ID, def.Version)
58+
}

0 commit comments

Comments
 (0)