feat(auth): coordinate canonical projection publication
This commit is contained in:
@@ -3,12 +3,14 @@
|
||||
package authprojection
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
@@ -71,14 +73,24 @@ func Inspect(spec Spec) (Status, error) {
|
||||
}
|
||||
|
||||
func Begin(spec Spec, before *Snapshot, requireReadyMatch bool) (*Transaction, error) {
|
||||
return BeginContext(context.Background(), spec, before, requireReadyMatch)
|
||||
}
|
||||
|
||||
func BeginContext(ctx context.Context, spec Spec, before *Snapshot, requireReadyMatch bool) (*Transaction, error) {
|
||||
if ctx == nil {
|
||||
return nil, ErrIntegrity
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
root, err := openRoot(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rendezvousBeforeFlock(root)
|
||||
if unix.Flock(root, unix.LOCK_EX) != nil {
|
||||
if err := flockContext(ctx, root); err != nil {
|
||||
unix.Close(root)
|
||||
return nil, ErrIntegrity
|
||||
return nil, err
|
||||
}
|
||||
transaction := &Transaction{spec: spec, before: before, rootFD: root, lockFD: root}
|
||||
selector, selectorErr := readSelector(root, spec)
|
||||
@@ -132,6 +144,30 @@ func Begin(spec Spec, before *Snapshot, requireReadyMatch bool) (*Transaction, e
|
||||
return transaction, nil
|
||||
}
|
||||
|
||||
func flockContext(ctx context.Context, descriptor int) error {
|
||||
for {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
err := unix.Flock(descriptor, unix.LOCK_EX|unix.LOCK_NB)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if !errors.Is(err, unix.EWOULDBLOCK) {
|
||||
return ErrIntegrity
|
||||
}
|
||||
timer := time.NewTimer(10 * time.Millisecond)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if !timer.Stop() {
|
||||
<-timer.C
|
||||
}
|
||||
return ctx.Err()
|
||||
case <-timer.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (transaction *Transaction) Commit(after Snapshot) (Status, error) {
|
||||
if transaction == nil || transaction.closed || !transaction.blocked || validateSnapshot(after) != nil {
|
||||
return Status{}, ErrIntegrity
|
||||
|
||||
Reference in New Issue
Block a user