summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Majewsky <majewsky@gmx.net>2026-07-21 14:18:35 +0200
committerStefan Majewsky <majewsky@gmx.net>2026-07-21 14:18:35 +0200
commitdc7bd11d855f0b3266612a18606801f4e09ecc09 (patch)
tree6d3d483601abc00402f7be06d4d630238128ea2b
parent8b2ace1c7cb82e1af923b8fc5fa7ffba820b9238 (diff)
downloadgo-schwift-dc7bd11d855f0b3266612a18606801f4e09ecc09.tar.gz
make Account.Headers and Container.Headers thread-safe
For type Object, it is a good tradeoff to not carry a mutex in every instance, since Objects are likely only used in the scope of a particular operation (and thus within an individual goroutine). But Account and Container instances are much more likely to be initialized once on startup and then shared across goroutines, so making them safer to use at the expense of a slight increase in resource usage looks like a good choice.
-rw-r--r--CHANGELOG.md6
-rw-r--r--account.go19
-rw-r--r--container.go14
3 files changed, 22 insertions, 17 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2bd8c5d..14589b5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+# v2.2.1 (TBD)
+
+Changes:
+
+- `Account.Headers` and `Container.Headers` are now thread-safe.
+
# v2.2.0 (2026-07-17)
Changes:
diff --git a/account.go b/account.go
index 2bc3b2b..d783baf 100644
--- a/account.go
+++ b/account.go
@@ -36,10 +36,11 @@ type Account struct {
baseURL string
name string
// cache
- headers *AccountHeaders
- caps *Capabilities
- modifyCaps func(*Capabilities)
- capsMutex sync.Mutex
+ headers *AccountHeaders
+ headersMutex sync.Mutex
+ caps *Capabilities
+ modifyCaps func(*Capabilities)
+ capsMutex sync.Mutex
}
// IsEqualTo returns true if both Account instances refer to the same account.
@@ -96,10 +97,9 @@ func (a *Account) Backend() Backend {
// has not been cached yet, a HEAD request is issued on the account.
//
// This operation fails with http.StatusNotFound if the account does not exist.
-//
-// WARNING: This method is not thread-safe. Calling it concurrently on the same
-// object results in undefined behavior.
func (a *Account) Headers(ctx context.Context) (AccountHeaders, error) {
+ a.headersMutex.Lock()
+ defer a.headersMutex.Unlock()
if a.headers != nil {
return *a.headers, nil
}
@@ -124,10 +124,9 @@ func (a *Account) Headers(ctx context.Context) (AccountHeaders, error) {
// Invalidate clears the internal cache of this Account instance. The next call
// to Headers() on this instance will issue a HEAD request on the account.
-//
-// WARNING: This method is not thread-safe. Calling it concurrently on the same
-// object results in undefined behavior.
func (a *Account) Invalidate() {
+ a.headersMutex.Lock()
+ defer a.headersMutex.Unlock()
a.headers = nil
}
diff --git a/container.go b/container.go
index 7ddd415..5d03000 100644
--- a/container.go
+++ b/container.go
@@ -21,6 +21,7 @@ package schwift
import (
"context"
"net/http"
+ "sync"
)
// Container represents a Swift container. Instances are usually obtained by
@@ -30,7 +31,8 @@ type Container struct {
a *Account
name string
// cache
- headers *ContainerHeaders
+ headers *ContainerHeaders
+ headersMutex sync.Mutex
}
// IsEqualTo returns true if both Container instances refer to the same container.
@@ -75,10 +77,9 @@ func (c *Container) Exists(ctx context.Context) (bool, error) {
// has not been cached yet, a HEAD request is issued on the container.
//
// This operation fails with http.StatusNotFound if the container does not exist.
-//
-// WARNING: This method is not thread-safe. Calling it concurrently on the same
-// object results in undefined behavior.
func (c *Container) Headers(ctx context.Context) (ContainerHeaders, error) {
+ c.headersMutex.Lock()
+ defer c.headersMutex.Unlock()
if c.headers != nil {
return *c.headers, nil
}
@@ -167,10 +168,9 @@ func (c *Container) Delete(ctx context.Context, opts *RequestOptions) error {
// Invalidate clears the internal cache of this Container instance. The next call
// to Headers() on this instance will issue a HEAD request on the container.
-//
-// WARNING: This method is not thread-safe. Calling it concurrently on the same
-// object results in undefined behavior.
func (c *Container) Invalidate() {
+ c.headersMutex.Lock()
+ defer c.headersMutex.Unlock()
c.headers = nil
}