mirror of
https://github.com/versity/versitygw.git
synced 2026-09-23 16:34:18 +00:00
Fail closed on unexpected advisory-lock errors instead of silently reducing cross-process exclusion to a local mutex. Make local publish-slot waits honor request cancellation. Move version snapshots under the publish lock so concurrent versioned PUTs preserve publication order. Add regression coverage for canceled lock waiters. Also add an option to disable flock files and only rely on in process locking.
57 lines
1.6 KiB
Go
57 lines
1.6 KiB
Go
// Copyright 2026 Versity Software
|
|
// This file is licensed under the Apache License, Version 2.0
|
|
// (the "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
//go:build !windows
|
|
|
|
package posix
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"time"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// lockFileExclusive takes an exclusive advisory flock on f, polling with
|
|
// backoff so that context cancellation is honored while waiting. The lock is
|
|
// released by closing f or on process exit, so no cleanup beyond Close is
|
|
// required on any failure path.
|
|
func lockFileExclusive(ctx context.Context, f *os.File) error {
|
|
backoff := objLockInitialBackoff
|
|
for {
|
|
err := unix.Flock(int(f.Fd()), unix.LOCK_EX|unix.LOCK_NB)
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
if !errors.Is(err, unix.EWOULDBLOCK) && !errors.Is(err, unix.EAGAIN) &&
|
|
!errors.Is(err, unix.EINTR) {
|
|
return err
|
|
}
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-time.After(backoff):
|
|
}
|
|
backoff = min(backoff*2, objLockMaxBackoff)
|
|
}
|
|
}
|
|
|
|
func isAdvisoryLockUnsupported(err error) bool {
|
|
return errors.Is(err, unix.ENOTSUP) || errors.Is(err, unix.EOPNOTSUPP) ||
|
|
errors.Is(err, unix.ENOSYS)
|
|
}
|