diff --git a/internal/storage/ledger/transactions.go b/internal/storage/ledger/transactions.go index 4600a9642..17f787705 100644 --- a/internal/storage/ledger/transactions.go +++ b/internal/storage/ledger/transactions.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/formancehq/go-libs/v2/collectionutils" "github.com/formancehq/ledger/pkg/features" "math/big" "regexp" @@ -254,15 +255,15 @@ func (s *Store) CommitTransaction(ctx context.Context, tx *ledger.Transaction) e return fmt.Errorf("failed to insert transaction: %w", err) } - for _, address := range tx.InvolvedAccounts() { - err := s.UpsertAccounts(ctx, &ledger.Account{ + err = s.UpsertAccounts(ctx, collectionutils.Map(tx.InvolvedAccounts(), func(address string) *ledger.Account { + return &ledger.Account{ Address: address, FirstUsage: tx.Timestamp, Metadata: make(metadata.Metadata), - }) - if err != nil { - return fmt.Errorf("upserting account: %w", err) } + })...) + if err != nil { + return fmt.Errorf("upserting accounts: %w", err) } if s.ledger.HasFeature(features.FeatureMovesHistory, "ON") { @@ -302,7 +303,6 @@ func (s *Store) CommitTransaction(ctx context.Context, tx *ledger.Transaction) e } if s.ledger.HasFeature(features.FeatureMovesHistoryPostCommitEffectiveVolumes, "SYNC") { - // todo: tx is inserted earlier! tx.PostCommitEffectiveVolumes = moves.ComputePostCommitEffectiveVolumes() } } diff --git a/pkg/generate/generator.go b/pkg/generate/generator.go index a71fd7bec..45adb6ea5 100644 --- a/pkg/generate/generator.go +++ b/pkg/generate/generator.go @@ -14,6 +14,8 @@ import ( "github.com/formancehq/ledger/pkg/client/models/operations" "github.com/google/uuid" "math/big" + "os" + "path/filepath" "time" ) @@ -185,12 +187,24 @@ func (r Action) Apply(ctx context.Context, client *client.V2, l string) (*Result return &Result{response.V2BulkResponse.Data[0]}, nil } +type NextOptions struct { + Globals map[string]any +} + +type NextOption func(options *NextOptions) + +func WithNextGlobals(globals map[string]any) NextOption { + return func(options *NextOptions) { + options.Globals = globals + } +} + type Generator struct { - next func(int) (*Action, error) + next func(int, ...NextOption) (*Action, error) } -func (g *Generator) Next(iteration int) (*Action, error) { - return g.next(iteration) +func (g *Generator) Next(iteration int, options ...NextOption) (*Action, error) { + return g.next(iteration, options...) } func NewGenerator(script string, opts ...Option) (*Generator, error) { @@ -221,6 +235,19 @@ func NewGenerator(script string, opts ...Option) (*Generator, error) { return nil, err } + err = runtime.Set("read_file", func(path string) string { + fmt.Println("read file", path) + f, err := os.ReadFile(filepath.Join(cfg.rootPath, path)) + if err != nil { + panic(err) + } + + return string(f) + }) + if err != nil { + return nil, err + } + var next func(int) map[string]any err = runtime.ExportTo(runtime.Get("next"), &next) if err != nil { @@ -228,7 +255,21 @@ func NewGenerator(script string, opts ...Option) (*Generator, error) { } return &Generator{ - next: func(i int) (*Action, error) { + next: func(i int, options ...NextOption) (*Action, error) { + + nextOptions := NextOptions{} + for _, option := range options { + option(&nextOptions) + } + + if nextOptions.Globals != nil { + for k, v := range nextOptions.Globals { + if err := runtime.Set(k, v); err != nil { + return nil, fmt.Errorf("failed to set global variable %s: %w", k, err) + } + } + } + ret := next(i) var ( @@ -281,7 +322,8 @@ func NewGenerator(script string, opts ...Option) (*Generator, error) { } type config struct { - globals map[string]any + globals map[string]any + rootPath string } type Option func(*config) @@ -291,3 +333,9 @@ func WithGlobals(globals map[string]any) Option { c.globals = globals } } + +func WithRootPath(path string) Option { + return func(c *config) { + c.rootPath = path + } +} diff --git a/test/performance/benchmark_test.go b/test/performance/benchmark_test.go index 8f3f6c5d4..55df38f2c 100644 --- a/test/performance/benchmark_test.go +++ b/test/performance/benchmark_test.go @@ -18,12 +18,12 @@ import ( ) type ActionProvider interface { - Get(iteration int) (*generate.Action, error) + Get(globalIteration, iteration int) (*generate.Action, error) } -type ActionProviderFn func(iteration int) (*generate.Action, error) +type ActionProviderFn func(globalIteration, iteration int) (*generate.Action, error) -func (fn ActionProviderFn) Get(iteration int) (*generate.Action, error) { - return fn(iteration) +func (fn ActionProviderFn) Get(globalIteration, iteration int) (*generate.Action, error) { + return fn(globalIteration, iteration) } type ActionProviderFactory interface { @@ -36,15 +36,17 @@ func (fn ActionProviderFactoryFn) Create() (ActionProvider, error) { return fn() } -func NewJSActionProviderFactory(script string) ActionProviderFactoryFn { +func NewJSActionProviderFactory(rootPath, script string) ActionProviderFactoryFn { return func() (ActionProvider, error) { - generator, err := generate.NewGenerator(script) + generator, err := generate.NewGenerator(script, generate.WithRootPath(rootPath)) if err != nil { return nil, err } - return ActionProviderFn(func(iteration int) (*generate.Action, error) { - return generator.Next(iteration) + return ActionProviderFn(func(globalIteration, iteration int) (*generate.Action, error) { + return generator.Next(iteration, generate.WithNextGlobals(map[string]any{ + "iteration": globalIteration, + })) }), nil } } @@ -82,7 +84,7 @@ func (benchmark *Benchmark) Run(ctx context.Context) map[string][]Result { Name: uuid.NewString()[:8], } - cpt := atomic.Int64{} + globalIteration := atomic.Int64{} env := envFactory.Create(ctx, b, l) b.Logf("ledger: %s/%s", l.Bucket, l.Name) @@ -94,11 +96,13 @@ func (benchmark *Benchmark) Run(ctx context.Context) map[string][]Result { actionProvider, err := benchmark.Scenarios[scenario].Create() require.NoError(b, err) + iteration := atomic.Int64{} for pb.Next() { - iteration := int(cpt.Add(1)) + globalIteration := int(globalIteration.Add(1)) + iteration := int(iteration.Add(1)) - action, err := actionProvider.Get(iteration) + action, err := actionProvider.Get(globalIteration, iteration) require.NoError(b, err) now := time.Now() diff --git a/test/performance/write_test.go b/test/performance/write_test.go index a52c03621..d8a200254 100644 --- a/test/performance/write_test.go +++ b/test/performance/write_test.go @@ -104,13 +104,19 @@ func BenchmarkWrite(b *testing.B) { script, err := scriptsDir.ReadFile(filepath.Join("scripts", entry.Name())) require.NoError(b, err) - scripts[strings.TrimSuffix(entry.Name(), ".js")] = NewJSActionProviderFactory(string(script)) + rootPath, err := filepath.Abs("scripts") + require.NoError(b, err) + + scripts[strings.TrimSuffix(entry.Name(), ".js")] = NewJSActionProviderFactory(rootPath, string(script)) } } else { file, err := os.ReadFile(scriptFlag) require.NoError(b, err, "reading file "+scriptFlag) - scripts["provided"] = NewJSActionProviderFactory(string(file)) + rootPath, err := filepath.Abs(filepath.Dir(scriptFlag)) + require.NoError(b, err) + + scripts["provided"] = NewJSActionProviderFactory(rootPath, string(file)) } if envFactory == nil {