carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package rootparticipation
2
3import (
4 "context"
5 "sync/atomic"
6)
7
8type transactionKey struct{}
9type heldTransaction struct {
10 ledger Ledger
11 active atomic.Bool
12}
13
14func TransactionLedger(ctx context.Context) (Ledger, bool, error) {
15 held, ok := ctx.Value(transactionKey{}).(*heldTransaction)
16 if !ok {
17 return Ledger{}, false, nil
18 }
19 if !held.active.Load() {
20 return Ledger{}, true, ErrUnavailable
21 }
22 if err := ctx.Err(); err != nil {
23 return Ledger{}, true, err
24 }
25 return held.ledger, true, nil
26}
27
28func (l Ledger) lockTransaction(ctx context.Context) (func(), error) {
29 held, ok, err := TransactionLedger(ctx)
30 if err != nil {
31 return nil, err
32 }
33 if ok {
34 if held.State != l.State {
35 return nil, ErrUnavailable
36 }
37 return func() {}, nil
38 }
39 return l.State.Lock(ctx, "transaction.lock")
40}
41
42func (l Ledger) WithTransaction(ctx context.Context, fn func(context.Context) error) error {
43 if l.State == nil || fn == nil {
44 return ErrUnavailable
45 }
46 unlock, err := l.lockTransaction(ctx)
47 if err != nil {
48 return err
49 }
50 defer unlock()
51 held := &heldTransaction{ledger: l}
52 held.active.Store(true)
53 defer held.active.Store(false)
54 return fn(context.WithValue(ctx, transactionKey{}, held))
55}
56