You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gitea/modules
Jason Song bc0977f1c9
Refactor globallock (#31933)
Follow #31908. The main refactor is that it has removed the returned
context of `Lock`.

The returned context of `Lock` in old code is to provide a way to let
callers know that they have lost the lock. But in most cases, callers
shouldn't cancel what they are doing even it has lost the lock. And the
design would confuse developers and make them use it incorrectly.

See the discussion history:
https://github.com/go-gitea/gitea/pull/31813#discussion_r1732041513 and
https://github.com/go-gitea/gitea/pull/31813#discussion_r1734078998

It's a breaking change, but since the new module hasn't been used yet, I
think it's OK to not add the `pr/breaking` label.

## Design principles

It's almost copied from #31908, but with some changes.

### Use spinlock even in memory implementation (unchanged)

In actual use cases, users may cancel requests. `sync.Mutex` will block
the goroutine until the lock is acquired even if the request is
canceled. And the spinlock is more suitable for this scenario since it's
possible to give up the lock acquisition.

Although the spinlock consumes more CPU resources, I think it's
acceptable in most cases.

### Do not expose the mutex to callers (unchanged)

If we expose the mutex to callers, it's possible for callers to reuse
the mutex, which causes more complexity.

For example:
```go
lock := GetLocker(key)
lock.Lock()
// ...
// even if the lock is unlocked, we cannot GC the lock,
// since the caller may still use it again.
lock.Unlock()
lock.Lock()
// ...
lock.Unlock()

// callers have to GC the lock manually.
RemoveLocker(key)
```

That's why
https://github.com/go-gitea/gitea/pull/31813#discussion_r1721200549

In this PR, we only expose `ReleaseFunc` to callers. So callers just
need to call `ReleaseFunc` to release the lock, and do not need to care
about the lock's lifecycle.
```go
release, err := locker.Lock(ctx, key)
if err != nil {
    return err
}
// ...
release()

// if callers want to lock again, they have to re-acquire the lock.
release, err := locker.Lock(ctx, key)
// ...
```

In this way, it's also much easier for redis implementation to extend
the mutex automatically, so that callers do not need to care about the
lock's lifecycle. See also
https://github.com/go-gitea/gitea/pull/31813#discussion_r1722659743

### Use "release" instead of "unlock" (unchanged)

For "unlock", it has the meaning of "unlock an acquired lock". So it's
not acceptable to call "unlock" when failed to acquire the lock, or call
"unlock" multiple times. It causes more complexity for callers to decide
whether to call "unlock" or not.

So we use "release" instead of "unlock" to make it clear. Whether the
lock is acquired or not, callers can always call "release", and it's
also safe to call "release" multiple times.

But the code DO NOT expect callers to not call "release" after acquiring
the lock. If callers forget to call "release", it will cause resource
leak. That's why it's always safe to call "release" without extra
checks: to avoid callers to forget to call it.

### Acquired locks could be lost, but the callers shouldn't stop

Unlike `sync.Mutex` which will be locked forever once acquired until
calling `Unlock`, for distributed lock, the acquired lock could be lost.

For example, the caller has acquired the lock, and it holds the lock for
a long time since auto-extending is working for redis. However, it lost
the connection to the redis server, and it's impossible to extend the
lock anymore.

In #31908, it will cancel the context to make the operation stop, but
it's not safe. Many operations are not revert-able. If they have been
interrupted, then the instance goes corrupted. So `Lock` won't return
`ctx` anymore in this PR.

### Multiple ways to use the lock

1. Regular way

```go
release, err := Lock(ctx, key)
if err != nil {
    return err
}
defer release()
// ...
```

2. Early release

```go
release, err := Lock(ctx, key)
if err != nil {
    return err
}
defer release()
// ...
// release the lock earlier
release()
// continue to do something else
// ...
```

3. Functional way

```go
if err := LockAndDo(ctx, key, func(ctx context.Context) error {
    // ...
    return nil
}); err != nil {
    return err
}
```
5 months ago
..
actions Support compression for Actions logs (#31761) 6 months ago
activitypub Upgrade to golangci-lint@v1.55.0 (#27756) 1 year ago
analyze Rename code_langauge.go to code_language.go (#26377) 2 years ago
assetfs Use `Set[Type]` instead of `map[Type]bool/struct{}`. (#26804) 1 year ago
auth Add Passkey login support (#31504) 7 months ago
avatar Use `crypto/sha256` (#29386) 11 months ago
badge Implement actions badge svgs (#28102) 11 months ago
base fix OIDC introspection authentication (#31632) 6 months ago
cache Add cache test for admins (#31265) 8 months ago
charset Render embedded code preview by permlink in markdown (#30234) 10 months ago
container Allow disabling authentication related user features (#31535) 7 months ago
csv Render embedded code preview by permlink in markdown (#30234) 10 months ago
dump Refactor "dump" sub-command (#30240) 10 months ago
emoji Update emoji set to Unicode 15 (#25595) 2 years ago
eventsource Final round of `db.DefaultContext` refactor (#27587) 1 year ago
generate Refactor JWT secret generating & decoding code (#29172) 12 months ago
git Refactor the usage of batch catfile (#31754) 5 months ago
gitgraph More `db.DefaultContext` refactor (#27265) 1 year ago
gitrepo Use repo as of renderctx's member rather than a repoPath on metas (#29222) 8 months ago
globallock Refactor globallock (#31933) 5 months ago
graceful Remove unused error in graceful manager (#29871) 11 months ago
hcaptcha Consume hcaptcha and pwn deps (#22610) 2 years ago
highlight Add option to disable ambiguous unicode characters detection (#28454) 1 year ago
hostmatcher Support allowed hosts for webhook to work with proxy (#27655) 1 year ago
html Refactor backend SVG package and add tests (#26335) 2 years ago
httpcache Also match weakly validated ETags (#28957) 1 year ago
httplib Fix duplicate sub-path for avatars (#31365) 8 months ago
indexer Refactor the usage of batch catfile (#31754) 5 months ago
issue/template Support issue template assignees (#31083) 6 months ago
json Replace `interface{}` with `any` (#25686) 2 years ago
label Make label templates have consistent behavior and priority (#23749) 2 years ago
lfs Distinguish LFS object errors to ignore missing objects during migration (#31702) 6 months ago
log Add some tests to clarify the "must-change-password" behavior (#30693) 9 months ago
markup Fix raw wiki links (#31825) 6 months ago
mcaptcha Implement FSFE REUSE for golang files (#21840) 2 years ago
metrics Rename project board -> column to make the UI less confusing (#30170) 8 months ago
migration Use correct function name (#31887) 5 months ago
nosql Update tool dependencies, lock govulncheck and actionlint (#25655) 2 years ago
optional Resolve lint for unused parameter and unnecessary type arguments (#30750) 9 months ago
options Use a general approach to access custom/static/builtin assets (#24022) 2 years ago
packages Support compression for Actions logs (#31761) 6 months ago
paginator Use more specific test methods (#24265) 2 years ago
pprof Implement FSFE REUSE for golang files (#21840) 2 years ago
private Move database operations of merging a pull request to post receive hook and add a transaction (#30805) 9 months ago
process Update misspell to 0.5.1 and add `misspellings.csv` (#30573) 9 months ago
proxy Use proxy for pull mirror (#22771) 2 years ago
proxyprotocol Implement FSFE REUSE for golang files (#21840) 2 years ago
public Refactor CORS handler (#28587) 1 year ago
queue Fix queue test (#30646) 9 months ago
recaptcha Implement FSFE REUSE for golang files (#21840) 2 years ago
references Refactor to use UnsafeStringToBytes (#31358) 8 months ago
regexplru Upgrade go dependencies (#25819) 2 years ago
repository Distinguish LFS object errors to ignore missing objects during migration (#31702) 6 months ago
secret Use `crypto/sha256` (#29386) 11 months ago
session Improve oauth2 client "preferred username field" logic and the error handling (#30622) 9 months ago
setting Support compression for Actions logs (#31761) 6 months ago
sitemap Fix sitemap (#22272) 2 years ago
ssh Remove SSH workaround (#27893) 1 year ago
storage Enable `unparam` linter (#31277) 8 months ago
structs Actions support workflow dispatch event (#28163) 6 months ago
svg Refactor markdown attention render (#29984) 11 months ago
sync Implement FSFE REUSE for golang files (#21840) 2 years ago
system Refactor to use UnsafeStringToBytes (#31358) 8 months ago
templates Refactor names (#31405) 8 months ago
test Remove sub-path from container registry realm (#31293) 8 months ago
testlogger Replace `interface{}` with `any` (#25686) 2 years ago
timeutil Refactor "dump" sub-command (#30240) 10 months ago
translation Render embedded code preview by permlink in markdown (#30234) 10 months ago
turnstile Add new captcha: cloudflare turnstile (#22369) 2 years ago
typesniffer Detect ogg mime-type as audio or video (#26494) 1 year ago
updatechecker Replace more db.DefaultContext (#27628) 1 year ago
uri Implement FSFE REUSE for golang files (#21840) 2 years ago
user Implement FSFE REUSE for golang files (#21840) 2 years ago
util Refactor to use UnsafeStringToBytes (#31358) 8 months ago
validation Check blocklist for emails when adding them to account (#26812) 1 year ago
web Refactor names (#31405) 8 months ago
webhook Fix schedule tasks bugs (#28691) 1 year ago
zstd Support compression for Actions logs (#31761) 6 months ago