MCPcopy Create free account
hub / github.com/devaccuracy/ledgerforge / executeWithLock

Method executeWithLock

transaction.go:1156–1186  ·  view source on GitHub ↗

executeWithLock executes a function with distributed locks to ensure exclusive access to both source and destination balances. It resolves balance IDs first (handling @world indicators), then acquires locks in deterministic order to prevent deadlocks. Parameters: - ctx context.Context: The context

(ctx context.Context, transaction *model.Transaction, fn func(context.Context) (*model.Transaction, error))

Source from the content-addressed store, hash-verified

1154// - *model.Transaction: A pointer to the Transaction model returned by the function.
1155// - error: An error if the locks could not be acquired or if the function execution fails.
1156func (l *LedgerForge) executeWithLock(ctx context.Context, transaction *model.Transaction, fn func(context.Context) (*model.Transaction, error)) (*model.Transaction, error) {
1157 ctx, span := tracer.Start(ctx, "ExecuteWithLock")
1158 defer span.End()
1159
1160 // First resolve balance IDs (handle @ indicators) BEFORE acquiring locks
1161 // This ensures we lock on the correct balance IDs
1162 sourceID, destID, err := l.resolveBalanceIDs(ctx, transaction)
1163 if err != nil {
1164 span.RecordError(err)
1165 return nil, fmt.Errorf("failed to resolve balance IDs: %w", err)
1166 }
1167
1168 // Update transaction with resolved IDs
1169 transaction.Source = sourceID
1170 transaction.Destination = destID
1171
1172 // Acquire distributed locks for both source and destination balances
1173 // MultiLocker handles deduplication (if source == destination) and sorts keys lexicographically
1174 locker, err := l.acquireLock(ctx, sourceID, destID)
1175 if err != nil {
1176 hotpairs.RecordContention(ctx, l.hotPairs, sourceID, destID, transaction.Currency, err)
1177 metrics.HotpairsContentionTotal.Add(ctx, 1)
1178 span.RecordError(err)
1179 return nil, fmt.Errorf("failed to acquire lock: %w", err)
1180 }
1181 defer l.releaseLock(ctx, locker)
1182
1183 // Execute the provided function with the locks held
1184 // The function will re-fetch balances to get fresh state after lock acquisition
1185 return fn(ctx)
1186}
1187
1188// validateAndPrepareTransaction validates the transaction and prepares it by retrieving the source and destination balances.
1189// It starts a tracing span, validates the transaction, retrieves the balances, and updates the transaction with the balance IDs.

Callers 1

Calls 5

resolveBalanceIDsMethod · 0.95
acquireLockMethod · 0.95
releaseLockMethod · 0.95
RecordContentionFunction · 0.92
StartMethod · 0.45

Tested by

no test coverage detected