lib: consistently use atomic.* types instead of atomic.* functions

See ea9e2b19a5
This commit is contained in:
Aliaksandr Valialkin 2024-02-24 02:07:51 +02:00
parent d5ca67e667
commit 7e1dd8ab9d
No known key found for this signature in database
GPG key ID: 52C003EE2BCDB9EB
39 changed files with 183 additions and 189 deletions

View file

@ -8,7 +8,6 @@ import (
"net/http" "net/http"
"os" "os"
"strings" "strings"
"sync/atomic"
"time" "time"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmagent/csvimport" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmagent/csvimport"
@ -459,7 +458,7 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
return true return true
case "/ready": case "/ready":
if rdy := atomic.LoadInt32(&promscrape.PendingScrapeConfigs); rdy > 0 { if rdy := promscrape.PendingScrapeConfigs.Load(); rdy > 0 {
errMsg := fmt.Sprintf("waiting for scrapes to init, left: %d", rdy) errMsg := fmt.Sprintf("waiting for scrapes to init, left: %d", rdy)
http.Error(w, errMsg, http.StatusTooEarly) http.Error(w, errMsg, http.StatusTooEarly)
} else { } else {

View file

@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
"sync/atomic"
"time" "time"
"github.com/VictoriaMetrics/metrics" "github.com/VictoriaMetrics/metrics"
@ -354,7 +353,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
return true return true
case "/ready": case "/ready":
if rdy := atomic.LoadInt32(&promscrape.PendingScrapeConfigs); rdy > 0 { if rdy := promscrape.PendingScrapeConfigs.Load(); rdy > 0 {
errMsg := fmt.Sprintf("waiting for scrape config to init targets, configs left: %d", rdy) errMsg := fmt.Sprintf("waiting for scrape config to init targets, configs left: %d", rdy)
http.Error(w, errMsg, http.StatusTooEarly) http.Error(w, errMsg, http.StatusTooEarly)
} else { } else {

2
go.mod
View file

@ -8,7 +8,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.0 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.0
github.com/VictoriaMetrics/easyproto v0.1.4 github.com/VictoriaMetrics/easyproto v0.1.4
github.com/VictoriaMetrics/fastcache v1.12.2 github.com/VictoriaMetrics/fastcache v1.12.2
github.com/VictoriaMetrics/metrics v1.32.0 github.com/VictoriaMetrics/metrics v1.33.0
github.com/VictoriaMetrics/metricsql v0.74.0 github.com/VictoriaMetrics/metricsql v0.74.0
github.com/aws/aws-sdk-go-v2 v1.25.0 github.com/aws/aws-sdk-go-v2 v1.25.0
github.com/aws/aws-sdk-go-v2/config v1.27.0 github.com/aws/aws-sdk-go-v2/config v1.27.0

4
go.sum
View file

@ -69,8 +69,8 @@ github.com/VictoriaMetrics/easyproto v0.1.4/go.mod h1:QlGlzaJnDfFd8Lk6Ci/fuLxfTo
github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI=
github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI=
github.com/VictoriaMetrics/metrics v1.24.0/go.mod h1:eFT25kvsTidQFHb6U0oa0rTrDRdz4xTYjpL8+UPohys= github.com/VictoriaMetrics/metrics v1.24.0/go.mod h1:eFT25kvsTidQFHb6U0oa0rTrDRdz4xTYjpL8+UPohys=
github.com/VictoriaMetrics/metrics v1.32.0 h1:r9JK2zndYv0TIxFXLEHwhQqRdnu8/O3cwJiCBX4vJCM= github.com/VictoriaMetrics/metrics v1.33.0 h1:EnkDEaGiL2u95t+W76GfecC/LMYpy+tFrexYzBWQIAc=
github.com/VictoriaMetrics/metrics v1.32.0/go.mod h1:r7hveu6xMdUACXvB8TYdAj8WEsKzWB0EkpJN+RDtOf8= github.com/VictoriaMetrics/metrics v1.33.0/go.mod h1:r7hveu6xMdUACXvB8TYdAj8WEsKzWB0EkpJN+RDtOf8=
github.com/VictoriaMetrics/metricsql v0.74.0 h1:bVO7USXBBYEuEHQ3PZg/6216j0DvblZM+Q8sTRECkv0= github.com/VictoriaMetrics/metricsql v0.74.0 h1:bVO7USXBBYEuEHQ3PZg/6216j0DvblZM+Q8sTRECkv0=
github.com/VictoriaMetrics/metricsql v0.74.0/go.mod h1:k4UaP/+CjuZslIjd+kCigNG9TQmUqh5v0TP/nMEy90I= github.com/VictoriaMetrics/metricsql v0.74.0/go.mod h1:k4UaP/+CjuZslIjd+kCigNG9TQmUqh5v0TP/nMEy90I=
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=

View file

@ -46,14 +46,14 @@ func (p *Part) key() string {
// so it must have an unique key in order to always copy it during // so it must have an unique key in order to always copy it during
// backup, restore and server-side copy. // backup, restore and server-side copy.
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5005 // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5005
id := atomic.AddUint64(&uniqueKeyID, 1) id := uniqueKeyID.Add(1)
return fmt.Sprintf("unique-%016X", id) return fmt.Sprintf("unique-%016X", id)
} }
// Do not use p.FileSize in the key, since it cannot be properly initialized when resuming the restore for partially restored file // Do not use p.FileSize in the key, since it cannot be properly initialized when resuming the restore for partially restored file
return fmt.Sprintf("%s%016X%016X%016X", p.Path, p.Offset, p.Size, p.ActualSize) return fmt.Sprintf("%s%016X%016X%016X", p.Path, p.Offset, p.Size, p.ActualSize)
} }
var uniqueKeyID uint64 var uniqueKeyID atomic.Uint64
// String returns human-readable representation of the part. // String returns human-readable representation of the part.
func (p *Part) String() string { func (p *Part) String() string {

View file

@ -172,14 +172,11 @@ func (c *Cache) cleanPerKeyMisses() {
} }
type cache struct { type cache struct {
// Atomically updated fields must go first in the struct, so they are properly requests atomic.Uint64
// aligned to 8 bytes on 32-bit architectures. misses atomic.Uint64
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/212
requests uint64
misses uint64
// sizeBytes contains an approximate size for all the blocks stored in the cache. // sizeBytes contains an approximate size for all the blocks stored in the cache.
sizeBytes int64 sizeBytes atomic.Int64
// getMaxSizeBytes() is a callback, which returns the maximum allowed cache size in bytes. // getMaxSizeBytes() is a callback, which returns the maximum allowed cache size in bytes.
getMaxSizeBytes func() int getMaxSizeBytes func() int
@ -256,7 +253,7 @@ func (c *cache) RemoveBlocksForPart(p interface{}) {
} }
func (c *cache) updateSizeBytes(n int) { func (c *cache) updateSizeBytes(n int) {
atomic.AddInt64(&c.sizeBytes, int64(n)) c.sizeBytes.Add(int64(n))
} }
func (c *cache) cleanPerKeyMisses() { func (c *cache) cleanPerKeyMisses() {
@ -281,7 +278,7 @@ func (c *cache) cleanByTimeout() {
} }
func (c *cache) GetBlock(k Key) Block { func (c *cache) GetBlock(k Key) Block {
atomic.AddUint64(&c.requests, 1) c.requests.Add(1)
var e *cacheEntry var e *cacheEntry
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
@ -301,7 +298,7 @@ func (c *cache) GetBlock(k Key) Block {
} }
// Slow path - the entry is missing in the cache. // Slow path - the entry is missing in the cache.
c.perKeyMisses[k]++ c.perKeyMisses[k]++
atomic.AddUint64(&c.misses, 1) c.misses.Add(1)
return nil return nil
} }
@ -367,7 +364,7 @@ func (c *cache) Len() int {
} }
func (c *cache) SizeBytes() int { func (c *cache) SizeBytes() int {
return int(atomic.LoadInt64(&c.sizeBytes)) return int(c.sizeBytes.Load())
} }
func (c *cache) SizeMaxBytes() int { func (c *cache) SizeMaxBytes() int {
@ -375,11 +372,11 @@ func (c *cache) SizeMaxBytes() int {
} }
func (c *cache) Requests() uint64 { func (c *cache) Requests() uint64 {
return atomic.LoadUint64(&c.requests) return c.requests.Load()
} }
func (c *cache) Misses() uint64 { func (c *cache) Misses() uint64 {
return atomic.LoadUint64(&c.misses) return c.misses.Load()
} }
// lastAccessHeap implements heap.Interface // lastAccessHeap implements heap.Interface

View file

@ -16,11 +16,11 @@ func BenchmarkKeyHashUint64(b *testing.B) {
h := k.hashUint64() h := k.hashUint64()
hSum += h hSum += h
} }
atomic.AddUint64(&BenchSink, hSum) BenchSink.Add(hSum)
}) })
} }
var BenchSink uint64 var BenchSink atomic.Uint64
func BenchmarkCacheGet(b *testing.B) { func BenchmarkCacheGet(b *testing.B) {
c := NewCache(func() int { c := NewCache(func() int {

View file

@ -56,7 +56,7 @@ func (l *Limiter) MaxItems() int {
// CurrentItems return the current number of items registered in l. // CurrentItems return the current number of items registered in l.
func (l *Limiter) CurrentItems() int { func (l *Limiter) CurrentItems() int {
lm := l.v.Load() lm := l.v.Load()
n := atomic.LoadUint64(&lm.currentItems) n := lm.currentItems.Load()
return int(n) return int(n)
} }
@ -72,7 +72,7 @@ func (l *Limiter) Add(h uint64) bool {
} }
type limiter struct { type limiter struct {
currentItems uint64 currentItems atomic.Uint64
f *filter f *filter
} }
@ -83,12 +83,12 @@ func newLimiter(maxItems int) *limiter {
} }
func (l *limiter) Add(h uint64) bool { func (l *limiter) Add(h uint64) bool {
currentItems := atomic.LoadUint64(&l.currentItems) currentItems := l.currentItems.Load()
if currentItems >= uint64(l.f.maxItems) { if currentItems >= uint64(l.f.maxItems) {
return l.f.Has(h) return l.f.Has(h)
} }
if l.f.Add(h) { if l.f.Add(h) {
atomic.AddUint64(&l.currentItems, 1) l.currentItems.Add(1)
} }
return true return true
} }

View file

@ -17,7 +17,7 @@ func BenchmarkToUnsafeString(b *testing.B) {
n += len(s) n += len(s)
} }
} }
atomic.AddUint64(&Sink, uint64(n)) Sink.Add(uint64(n))
}) })
} }
@ -33,8 +33,8 @@ func BenchmarkToUnsafeBytes(b *testing.B) {
n += len(s) n += len(s)
} }
} }
atomic.AddUint64(&Sink, uint64(n)) Sink.Add(uint64(n))
}) })
} }
var Sink uint64 var Sink atomic.Uint64

View file

@ -13,7 +13,7 @@ import (
// It caches string match results and returns them back on the next calls // It caches string match results and returns them back on the next calls
// without calling the matchFunc, which may be expensive. // without calling the matchFunc, which may be expensive.
type FastStringMatcher struct { type FastStringMatcher struct {
lastCleanupTime uint64 lastCleanupTime atomic.Uint64
m sync.Map m sync.Map
@ -21,7 +21,7 @@ type FastStringMatcher struct {
} }
type fsmEntry struct { type fsmEntry struct {
lastAccessTime uint64 lastAccessTime atomic.Uint64
ok bool ok bool
} }
@ -29,10 +29,11 @@ type fsmEntry struct {
// //
// matchFunc must return the same result for the same input. // matchFunc must return the same result for the same input.
func NewFastStringMatcher(matchFunc func(s string) bool) *FastStringMatcher { func NewFastStringMatcher(matchFunc func(s string) bool) *FastStringMatcher {
return &FastStringMatcher{ fsm := &FastStringMatcher{
lastCleanupTime: fasttime.UnixTimestamp(),
matchFunc: matchFunc, matchFunc: matchFunc,
} }
fsm.lastCleanupTime.Store(fasttime.UnixTimestamp())
return fsm
} }
// Match applies matchFunc to s and returns the result. // Match applies matchFunc to s and returns the result.
@ -46,19 +47,19 @@ func (fsm *FastStringMatcher) Match(s string) bool {
if ok { if ok {
// Fast path - s match result is found in the cache. // Fast path - s match result is found in the cache.
e := v.(*fsmEntry) e := v.(*fsmEntry)
if atomic.LoadUint64(&e.lastAccessTime)+10 < ct { if e.lastAccessTime.Load()+10 < ct {
// Reduce the frequency of e.lastAccessTime update to once per 10 seconds // Reduce the frequency of e.lastAccessTime update to once per 10 seconds
// in order to improve the fast path speed on systems with many CPU cores. // in order to improve the fast path speed on systems with many CPU cores.
atomic.StoreUint64(&e.lastAccessTime, ct) e.lastAccessTime.Store(ct)
} }
return e.ok return e.ok
} }
// Slow path - run matchFunc for s and store the result in the cache. // Slow path - run matchFunc for s and store the result in the cache.
b := fsm.matchFunc(s) b := fsm.matchFunc(s)
e := &fsmEntry{ e := &fsmEntry{
lastAccessTime: ct,
ok: b, ok: b,
} }
e.lastAccessTime.Store(ct)
// Make a copy of s in order to limit memory usage to the s length, // Make a copy of s in order to limit memory usage to the s length,
// since the s may point to bigger string. // since the s may point to bigger string.
// This also protects from the case when s contains unsafe string, which points to a temporary byte slice. // This also protects from the case when s contains unsafe string, which points to a temporary byte slice.
@ -72,7 +73,7 @@ func (fsm *FastStringMatcher) Match(s string) bool {
deadline := ct - uint64(cacheExpireDuration.Seconds()) deadline := ct - uint64(cacheExpireDuration.Seconds())
m.Range(func(k, v interface{}) bool { m.Range(func(k, v interface{}) bool {
e := v.(*fsmEntry) e := v.(*fsmEntry)
if atomic.LoadUint64(&e.lastAccessTime) < deadline { if e.lastAccessTime.Load() < deadline {
m.Delete(k) m.Delete(k)
} }
return true return true
@ -82,13 +83,13 @@ func (fsm *FastStringMatcher) Match(s string) bool {
return b return b
} }
func needCleanup(lastCleanupTime *uint64, currentTime uint64) bool { func needCleanup(lastCleanupTime *atomic.Uint64, currentTime uint64) bool {
lct := atomic.LoadUint64(lastCleanupTime) lct := lastCleanupTime.Load()
if lct+61 >= currentTime { if lct+61 >= currentTime {
return false return false
} }
// Atomically compare and swap the current time with the lastCleanupTime // Atomically compare and swap the current time with the lastCleanupTime
// in order to guarantee that only a single goroutine out of multiple // in order to guarantee that only a single goroutine out of multiple
// concurrently executing goroutines gets true from the call. // concurrently executing goroutines gets true from the call.
return atomic.CompareAndSwapUint64(lastCleanupTime, lct, currentTime) return lastCleanupTime.CompareAndSwap(lct, currentTime)
} }

View file

@ -2,6 +2,7 @@ package bytesutil
import ( import (
"strings" "strings"
"sync/atomic"
"testing" "testing"
) )
@ -27,18 +28,19 @@ func TestFastStringMatcher(t *testing.T) {
func TestNeedCleanup(t *testing.T) { func TestNeedCleanup(t *testing.T) {
f := func(lastCleanupTime, currentTime uint64, resultExpected bool) { f := func(lastCleanupTime, currentTime uint64, resultExpected bool) {
t.Helper() t.Helper()
lct := lastCleanupTime var lct atomic.Uint64
lct.Store(lastCleanupTime)
result := needCleanup(&lct, currentTime) result := needCleanup(&lct, currentTime)
if result != resultExpected { if result != resultExpected {
t.Fatalf("unexpected result for needCleanup(%d, %d); got %v; want %v", lastCleanupTime, currentTime, result, resultExpected) t.Fatalf("unexpected result for needCleanup(%d, %d); got %v; want %v", lastCleanupTime, currentTime, result, resultExpected)
} }
if result { if result {
if lct != currentTime { if n := lct.Load(); n != currentTime {
t.Fatalf("unexpected value for lct; got %d; want currentTime=%d", lct, currentTime) t.Fatalf("unexpected value for lct; got %d; want currentTime=%d", n, currentTime)
} }
} else { } else {
if lct != lastCleanupTime { if n := lct.Load(); n != lastCleanupTime {
t.Fatalf("unexpected value for lct; got %d; want lastCleanupTime=%d", lct, lastCleanupTime) t.Fatalf("unexpected value for lct; got %d; want lastCleanupTime=%d", n, lastCleanupTime)
} }
} }
} }

View file

@ -2,7 +2,6 @@ package bytesutil
import ( import (
"strings" "strings"
"sync/atomic"
"testing" "testing"
) )
@ -28,6 +27,6 @@ func benchmarkFastStringMatcher(b *testing.B, s string) {
n++ n++
} }
} }
atomic.AddUint64(&GlobalSink, n) GlobalSink.Add(n)
}) })
} }

View file

@ -13,7 +13,7 @@ import (
// It caches transformed strings and returns them back on the next calls // It caches transformed strings and returns them back on the next calls
// without calling the transformFunc, which may be expensive. // without calling the transformFunc, which may be expensive.
type FastStringTransformer struct { type FastStringTransformer struct {
lastCleanupTime uint64 lastCleanupTime atomic.Uint64
m sync.Map m sync.Map
@ -21,7 +21,7 @@ type FastStringTransformer struct {
} }
type fstEntry struct { type fstEntry struct {
lastAccessTime uint64 lastAccessTime atomic.Uint64
s string s string
} }
@ -29,10 +29,11 @@ type fstEntry struct {
// //
// transformFunc must return the same result for the same input. // transformFunc must return the same result for the same input.
func NewFastStringTransformer(transformFunc func(s string) string) *FastStringTransformer { func NewFastStringTransformer(transformFunc func(s string) string) *FastStringTransformer {
return &FastStringTransformer{ fst := &FastStringTransformer{
lastCleanupTime: fasttime.UnixTimestamp(),
transformFunc: transformFunc, transformFunc: transformFunc,
} }
fst.lastCleanupTime.Store(fasttime.UnixTimestamp())
return fst
} }
// Transform applies transformFunc to s and returns the result. // Transform applies transformFunc to s and returns the result.
@ -52,10 +53,10 @@ func (fst *FastStringTransformer) Transform(s string) string {
if ok { if ok {
// Fast path - the transformed s is found in the cache. // Fast path - the transformed s is found in the cache.
e := v.(*fstEntry) e := v.(*fstEntry)
if atomic.LoadUint64(&e.lastAccessTime)+10 < ct { if e.lastAccessTime.Load()+10 < ct {
// Reduce the frequency of e.lastAccessTime update to once per 10 seconds // Reduce the frequency of e.lastAccessTime update to once per 10 seconds
// in order to improve the fast path speed on systems with many CPU cores. // in order to improve the fast path speed on systems with many CPU cores.
atomic.StoreUint64(&e.lastAccessTime, ct) e.lastAccessTime.Store(ct)
} }
return e.s return e.s
} }
@ -72,9 +73,9 @@ func (fst *FastStringTransformer) Transform(s string) string {
sTransformed = s sTransformed = s
} }
e := &fstEntry{ e := &fstEntry{
lastAccessTime: ct,
s: sTransformed, s: sTransformed,
} }
e.lastAccessTime.Store(ct)
fst.m.Store(s, e) fst.m.Store(s, e)
if needCleanup(&fst.lastCleanupTime, ct) { if needCleanup(&fst.lastCleanupTime, ct) {
@ -83,7 +84,7 @@ func (fst *FastStringTransformer) Transform(s string) string {
deadline := ct - uint64(cacheExpireDuration.Seconds()) deadline := ct - uint64(cacheExpireDuration.Seconds())
m.Range(func(k, v interface{}) bool { m.Range(func(k, v interface{}) bool {
e := v.(*fstEntry) e := v.(*fstEntry)
if atomic.LoadUint64(&e.lastAccessTime) < deadline { if e.lastAccessTime.Load() < deadline {
m.Delete(k) m.Delete(k)
} }
return true return true

View file

@ -24,8 +24,8 @@ func benchmarkFastStringTransformer(b *testing.B, s string) {
sTransformed := fst.Transform(s) sTransformed := fst.Transform(s)
n += uint64(len(sTransformed)) n += uint64(len(sTransformed))
} }
atomic.AddUint64(&GlobalSink, n) GlobalSink.Add(n)
}) })
} }
var GlobalSink uint64 var GlobalSink atomic.Uint64

View file

@ -42,19 +42,19 @@ func InternString(s string) string {
ct := fasttime.UnixTimestamp() ct := fasttime.UnixTimestamp()
if v, ok := internStringsMap.Load(s); ok { if v, ok := internStringsMap.Load(s); ok {
e := v.(*ismEntry) e := v.(*ismEntry)
if atomic.LoadUint64(&e.lastAccessTime)+10 < ct { if e.lastAccessTime.Load()+10 < ct {
// Reduce the frequency of e.lastAccessTime update to once per 10 seconds // Reduce the frequency of e.lastAccessTime update to once per 10 seconds
// in order to improve the fast path speed on systems with many CPU cores. // in order to improve the fast path speed on systems with many CPU cores.
atomic.StoreUint64(&e.lastAccessTime, ct) e.lastAccessTime.Store(ct)
} }
return e.s return e.s
} }
// Make a new copy for s in order to remove references from possible bigger string s refers to. // Make a new copy for s in order to remove references from possible bigger string s refers to.
sCopy := strings.Clone(s) sCopy := strings.Clone(s)
e := &ismEntry{ e := &ismEntry{
lastAccessTime: ct,
s: sCopy, s: sCopy,
} }
e.lastAccessTime.Store(ct)
internStringsMap.Store(sCopy, e) internStringsMap.Store(sCopy, e)
if needCleanup(&internStringsMapLastCleanupTime, ct) { if needCleanup(&internStringsMapLastCleanupTime, ct) {
@ -63,7 +63,7 @@ func InternString(s string) string {
deadline := ct - uint64(cacheExpireDuration.Seconds()) deadline := ct - uint64(cacheExpireDuration.Seconds())
m.Range(func(k, v interface{}) bool { m.Range(func(k, v interface{}) bool {
e := v.(*ismEntry) e := v.(*ismEntry)
if atomic.LoadUint64(&e.lastAccessTime) < deadline { if e.lastAccessTime.Load() < deadline {
m.Delete(k) m.Delete(k)
} }
return true return true
@ -74,11 +74,11 @@ func InternString(s string) string {
} }
type ismEntry struct { type ismEntry struct {
lastAccessTime uint64 lastAccessTime atomic.Uint64
s string s string
} }
var ( var (
internStringsMap sync.Map internStringsMap sync.Map
internStringsMapLastCleanupTime uint64 internStringsMapLastCleanupTime atomic.Uint64
) )

View file

@ -51,7 +51,7 @@ func benchmarkAppendDecimalToFloat(b *testing.B, a []int64, scale int16) {
var fa []float64 var fa []float64
for pb.Next() { for pb.Next() {
fa = AppendDecimalToFloat(fa[:0], a, scale) fa = AppendDecimalToFloat(fa[:0], a, scale)
atomic.AddUint64(&Sink, uint64(len(fa))) Sink.Add(uint64(len(fa)))
} }
}) })
} }
@ -101,7 +101,7 @@ func benchmarkAppendFloatToDecimal(b *testing.B, fa []float64) {
sink += uint64(len(da)) sink += uint64(len(da))
sink += uint64(e) sink += uint64(e)
} }
atomic.AddUint64(&Sink, sink) Sink.Add(sink)
}) })
} }
@ -138,10 +138,10 @@ func BenchmarkFromFloat(b *testing.B) {
sink += uint64(v) sink += uint64(v)
sink += uint64(e) sink += uint64(e)
} }
atomic.AddUint64(&Sink, sink) Sink.Add(sink)
}) })
}) })
} }
} }
var Sink uint64 var Sink atomic.Uint64

View file

@ -18,12 +18,12 @@ func BenchmarkMarshalGaugeArray(b *testing.B) {
if mt != MarshalTypeZSTDNearestDelta { if mt != MarshalTypeZSTDNearestDelta {
panic(fmt.Errorf("unexpected marshal type; got %d; expecting %d", mt, MarshalTypeZSTDNearestDelta)) panic(fmt.Errorf("unexpected marshal type; got %d; expecting %d", mt, MarshalTypeZSTDNearestDelta))
} }
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }
var Sink uint64 var Sink atomic.Uint64
func BenchmarkUnmarshalGaugeArray(b *testing.B) { func BenchmarkUnmarshalGaugeArray(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
@ -36,7 +36,7 @@ func BenchmarkUnmarshalGaugeArray(b *testing.B) {
if err != nil { if err != nil {
panic(fmt.Errorf("cannot unmarshal gauge array: %w", err)) panic(fmt.Errorf("cannot unmarshal gauge array: %w", err))
} }
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }
@ -68,7 +68,7 @@ func BenchmarkMarshalDeltaConstArray(b *testing.B) {
if mt != MarshalTypeDeltaConst { if mt != MarshalTypeDeltaConst {
panic(fmt.Errorf("unexpected marshal type; got %d; expecting %d", mt, MarshalTypeDeltaConst)) panic(fmt.Errorf("unexpected marshal type; got %d; expecting %d", mt, MarshalTypeDeltaConst))
} }
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }
@ -84,7 +84,7 @@ func BenchmarkUnmarshalDeltaConstArray(b *testing.B) {
if err != nil { if err != nil {
panic(fmt.Errorf("cannot unmarshal delta const array: %w", err)) panic(fmt.Errorf("cannot unmarshal delta const array: %w", err))
} }
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }
@ -115,7 +115,7 @@ func BenchmarkMarshalConstArray(b *testing.B) {
if mt != MarshalTypeConst { if mt != MarshalTypeConst {
panic(fmt.Errorf("unexpected marshal type; got %d; expecting %d", mt, MarshalTypeConst)) panic(fmt.Errorf("unexpected marshal type; got %d; expecting %d", mt, MarshalTypeConst))
} }
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }
@ -131,7 +131,7 @@ func BenchmarkUnmarshalConstArray(b *testing.B) {
if err != nil { if err != nil {
panic(fmt.Errorf("cannot unmarshal const array: %w", err)) panic(fmt.Errorf("cannot unmarshal const array: %w", err))
} }
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }
@ -160,7 +160,7 @@ func BenchmarkMarshalZeroConstArray(b *testing.B) {
if mt != MarshalTypeConst { if mt != MarshalTypeConst {
panic(fmt.Errorf("unexpected marshal type; got %d; expecting %d", mt, MarshalTypeConst)) panic(fmt.Errorf("unexpected marshal type; got %d; expecting %d", mt, MarshalTypeConst))
} }
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }
@ -176,7 +176,7 @@ func BenchmarkUnmarshalZeroConstArray(b *testing.B) {
if err != nil { if err != nil {
panic(fmt.Errorf("cannot unmarshal zero const array: %w", err)) panic(fmt.Errorf("cannot unmarshal zero const array: %w", err))
} }
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }
@ -199,7 +199,7 @@ func BenchmarkMarshalInt64Array(b *testing.B) {
if mt != benchMarshalType { if mt != benchMarshalType {
panic(fmt.Errorf("unexpected marshal type; got %d; expecting %d", mt, benchMarshalType)) panic(fmt.Errorf("unexpected marshal type; got %d; expecting %d", mt, benchMarshalType))
} }
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }
@ -215,7 +215,7 @@ func BenchmarkUnmarshalInt64Array(b *testing.B) {
if err != nil { if err != nil {
panic(fmt.Errorf("cannot unmarshal int64 array: %w", err)) panic(fmt.Errorf("cannot unmarshal int64 array: %w", err))
} }
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }

View file

@ -2,7 +2,6 @@ package encoding
import ( import (
"fmt" "fmt"
"sync/atomic"
"testing" "testing"
) )
@ -16,7 +15,7 @@ func BenchmarkMarshalUint64(b *testing.B) {
dst = MarshalUint64(dst[:0], sink) dst = MarshalUint64(dst[:0], sink)
sink += uint64(len(dst)) sink += uint64(len(dst))
} }
atomic.AddUint64(&Sink, sink) Sink.Add(sink)
}) })
} }
@ -29,7 +28,7 @@ func BenchmarkUnmarshalUint64(b *testing.B) {
v := UnmarshalUint64(testMarshaledUint64Data) v := UnmarshalUint64(testMarshaledUint64Data)
sink += v sink += v
} }
atomic.AddUint64(&Sink, sink) Sink.Add(sink)
}) })
} }
@ -43,7 +42,7 @@ func BenchmarkMarshalInt64(b *testing.B) {
dst = MarshalInt64(dst[:0], int64(sink)) dst = MarshalInt64(dst[:0], int64(sink))
sink += uint64(len(dst)) sink += uint64(len(dst))
} }
atomic.AddUint64(&Sink, sink) Sink.Add(sink)
}) })
} }
@ -56,7 +55,7 @@ func BenchmarkUnmarshalInt64(b *testing.B) {
v := UnmarshalInt64(testMarshaledInt64Data) v := UnmarshalInt64(testMarshaledInt64Data)
sink += uint64(v) sink += uint64(v)
} }
atomic.AddUint64(&Sink, sink) Sink.Add(sink)
}) })
} }
@ -96,7 +95,7 @@ func benchmarkMarshalVarUint64s(b *testing.B, maxValue uint64) {
dst = MarshalVarUint64s(dst[:0], data) dst = MarshalVarUint64s(dst[:0], data)
sink += uint64(len(dst)) sink += uint64(len(dst))
} }
atomic.AddUint64(&Sink, sink) Sink.Add(sink)
}) })
} }
@ -136,7 +135,7 @@ func benchmarkMarshalVarInt64s(b *testing.B, maxValue int64) {
dst = MarshalVarInt64s(dst[:0], data) dst = MarshalVarInt64s(dst[:0], data)
sink += uint64(len(dst)) sink += uint64(len(dst))
} }
atomic.AddUint64(&Sink, sink) Sink.Add(sink)
}) })
} }
@ -182,7 +181,7 @@ func benchmarkUnmarshalVarUint64s(b *testing.B, maxValue uint64) {
} }
sink += uint64(len(dst)) sink += uint64(len(dst))
} }
atomic.AddUint64(&Sink, sink) Sink.Add(sink)
}) })
} }
@ -228,7 +227,7 @@ func benchmarkUnmarshalVarInt64s(b *testing.B, maxValue int64) {
} }
sink += uint64(len(dst)) sink += uint64(len(dst))
} }
atomic.AddUint64(&Sink, sink) Sink.Add(sink)
}) })
} }

View file

@ -2,7 +2,6 @@ package encoding
import ( import (
"fmt" "fmt"
"sync/atomic"
"testing" "testing"
) )
@ -21,7 +20,7 @@ func benchmarkMarshalInt64NearestDelta2(b *testing.B, precisionBits uint8) {
var dst []byte var dst []byte
for pb.Next() { for pb.Next() {
dst, _ = marshalInt64NearestDelta2(dst[:0], benchInt64Array, precisionBits) dst, _ = marshalInt64NearestDelta2(dst[:0], benchInt64Array, precisionBits)
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }
@ -37,7 +36,7 @@ func BenchmarkUnmarshalInt64NearestDelta2(b *testing.B) {
if err != nil { if err != nil {
panic(fmt.Errorf("unexpected error: %w", err)) panic(fmt.Errorf("unexpected error: %w", err))
} }
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }

View file

@ -2,7 +2,6 @@ package encoding
import ( import (
"fmt" "fmt"
"sync/atomic"
"testing" "testing"
) )
@ -21,7 +20,7 @@ func benchmarkMarshalInt64NearestDelta(b *testing.B, precisionBits uint8) {
var dst []byte var dst []byte
for pb.Next() { for pb.Next() {
dst, _ = marshalInt64NearestDelta(dst[:0], benchInt64Array, precisionBits) dst, _ = marshalInt64NearestDelta(dst[:0], benchInt64Array, precisionBits)
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }
@ -37,7 +36,7 @@ func BenchmarkUnmarshalInt64NearestDelta(b *testing.B) {
if err != nil { if err != nil {
panic(fmt.Errorf("unexpected error: %w", err)) panic(fmt.Errorf("unexpected error: %w", err))
} }
atomic.AddUint64(&Sink, uint64(len(dst))) Sink.Add(uint64(len(dst)))
} }
}) })
} }

View file

@ -11,18 +11,22 @@ func init() {
defer ticker.Stop() defer ticker.Stop()
for tm := range ticker.C { for tm := range ticker.C {
t := uint64(tm.Unix()) t := uint64(tm.Unix())
atomic.StoreUint64(&currentTimestamp, t) currentTimestamp.Store(t)
} }
}() }()
} }
var currentTimestamp = uint64(time.Now().Unix()) var currentTimestamp = func() *atomic.Uint64 {
var x atomic.Uint64
x.Store(uint64(time.Now().Unix()))
return &x
}()
// UnixTimestamp returns the current unix timestamp in seconds. // UnixTimestamp returns the current unix timestamp in seconds.
// //
// It is faster than time.Now().Unix() // It is faster than time.Now().Unix()
func UnixTimestamp() uint64 { func UnixTimestamp() uint64 {
return atomic.LoadUint64(&currentTimestamp) return currentTimestamp.Load()
} }
// UnixDate returns date from the current unix timestamp. // UnixDate returns date from the current unix timestamp.

View file

@ -13,7 +13,7 @@ func BenchmarkUnixTimestamp(b *testing.B) {
for pb.Next() { for pb.Next() {
ts += UnixTimestamp() ts += UnixTimestamp()
} }
atomic.StoreUint64(&Sink, ts) Sink.Store(ts)
}) })
} }
@ -24,9 +24,9 @@ func BenchmarkTimeNowUnix(b *testing.B) {
for pb.Next() { for pb.Next() {
ts += uint64(time.Now().Unix()) ts += uint64(time.Now().Unix())
} }
atomic.StoreUint64(&Sink, ts) Sink.Store(ts)
}) })
} }
// Sink should prevent from code elimination by optimizing compiler // Sink should prevent from code elimination by optimizing compiler
var Sink uint64 var Sink atomic.Uint64

View file

@ -35,7 +35,7 @@ func NewPassword(name, description string) *Password {
// If the flag value is file:///path/to/file or http://host/path , // If the flag value is file:///path/to/file or http://host/path ,
// then its contents is automatically re-read from the given file or url // then its contents is automatically re-read from the given file or url
type Password struct { type Password struct {
nextRefreshTimestamp uint64 nextRefreshTimestamp atomic.Uint64
value atomic.Pointer[string] value atomic.Pointer[string]
@ -62,14 +62,14 @@ func (p *Password) maybeRereadPassword() {
return return
} }
tsCurr := fasttime.UnixTimestamp() tsCurr := fasttime.UnixTimestamp()
tsNext := atomic.LoadUint64(&p.nextRefreshTimestamp) tsNext := p.nextRefreshTimestamp.Load()
if tsCurr < tsNext { if tsCurr < tsNext {
// Fast path - nothing to re-read // Fast path - nothing to re-read
return return
} }
// Re-read password from p.sourcePath // Re-read password from p.sourcePath
atomic.StoreUint64(&p.nextRefreshTimestamp, tsCurr+2) p.nextRefreshTimestamp.Store(tsCurr + 2)
s, err := fscore.ReadPasswordFromFileOrHTTP(p.sourcePath) s, err := fscore.ReadPasswordFromFileOrHTTP(p.sourcePath)
if err != nil { if err != nil {
// cannot use lib/logger, since it can be uninitialized yet // cannot use lib/logger, since it can be uninitialized yet
@ -86,7 +86,7 @@ func (p *Password) String() string {
// Set implements flag.Value interface. // Set implements flag.Value interface.
func (p *Password) Set(value string) error { func (p *Password) Set(value string) error {
atomic.StoreUint64(&p.nextRefreshTimestamp, 0) p.nextRefreshTimestamp.Store(0)
switch { switch {
case strings.HasPrefix(value, "file://"): case strings.HasPrefix(value, "file://"):
p.sourcePath = strings.TrimPrefix(value, "file://") p.sourcePath = strings.TrimPrefix(value, "file://")

View file

@ -16,7 +16,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
) )
var tmpFileNum uint64 var tmpFileNum atomic.Uint64
// MustSyncPath syncs contents of the given path. // MustSyncPath syncs contents of the given path.
func MustSyncPath(path string) { func MustSyncPath(path string) {
@ -62,7 +62,7 @@ func MustWriteAtomic(path string, data []byte, canOverwrite bool) {
} }
// Write data to a temporary file. // Write data to a temporary file.
n := atomic.AddUint64(&tmpFileNum, 1) n := tmpFileNum.Add(1)
tmpPath := fmt.Sprintf("%s.tmp.%d", path, n) tmpPath := fmt.Sprintf("%s.tmp.%d", path, n)
MustWriteSync(tmpPath, data) MustWriteSync(tmpPath, data)
@ -207,7 +207,11 @@ func MustRemoveDirAtomic(dir string) {
MustSyncPath(parentDir) MustSyncPath(parentDir)
} }
var atomicDirRemoveCounter = uint64(time.Now().UnixNano()) var atomicDirRemoveCounter = func() *atomic.Uint64 {
var x atomic.Uint64
x.Store(uint64(time.Now().UnixNano()))
return &x
}()
// MustReadDir reads directory entries at the given dir. // MustReadDir reads directory entries at the given dir.
func MustReadDir(dir string) []os.DirEntry { func MustReadDir(dir string) []os.DirEntry {

View file

@ -5,7 +5,6 @@ package fs
import ( import (
"fmt" "fmt"
"os" "os"
"sync/atomic"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
@ -16,7 +15,7 @@ func freeSpace(stat unix.Statfs_t) uint64 {
} }
func mustRemoveDirAtomic(dir string) { func mustRemoveDirAtomic(dir string) {
n := atomic.AddUint64(&atomicDirRemoveCounter, 1) n := atomicDirRemoveCounter.Add(1)
tmpDir := fmt.Sprintf("%s.must-remove.%d", dir, n) tmpDir := fmt.Sprintf("%s.must-remove.%d", dir, n)
if err := os.Rename(dir, tmpDir); err != nil { if err := os.Rename(dir, tmpDir); err != nil {
logger.Panicf("FATAL: cannot move %s to %s: %s", dir, tmpDir, err) logger.Panicf("FATAL: cannot move %s to %s: %s", dir, tmpDir, err)

View file

@ -3,7 +3,6 @@ package fs
import ( import (
"fmt" "fmt"
"os" "os"
"sync/atomic"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
@ -14,7 +13,7 @@ func freeSpace(stat unix.Statfs_t) uint64 {
} }
func mustRemoveDirAtomic(dir string) { func mustRemoveDirAtomic(dir string) {
n := atomic.AddUint64(&atomicDirRemoveCounter, 1) n := atomicDirRemoveCounter.Add(1)
tmpDir := fmt.Sprintf("%s.must-remove.%d", dir, n) tmpDir := fmt.Sprintf("%s.must-remove.%d", dir, n)
if err := os.Rename(dir, tmpDir); err != nil { if err := os.Rename(dir, tmpDir); err != nil {
logger.Panicf("FATAL: cannot move %s to %s: %s", dir, tmpDir, err) logger.Panicf("FATAL: cannot move %s to %s: %s", dir, tmpDir, err)

View file

@ -3,14 +3,13 @@ package fs
import ( import (
"fmt" "fmt"
"os" "os"
"sync/atomic"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
func mustRemoveDirAtomic(dir string) { func mustRemoveDirAtomic(dir string) {
n := atomic.AddUint64(&atomicDirRemoveCounter, 1) n := atomicDirRemoveCounter.Add(1)
tmpDir := fmt.Sprintf("%s.must-remove.%d", dir, n) tmpDir := fmt.Sprintf("%s.must-remove.%d", dir, n)
if err := os.Rename(dir, tmpDir); err != nil { if err := os.Rename(dir, tmpDir); err != nil {
logger.Panicf("FATAL: cannot move %s to %s: %s", dir, tmpDir, err) logger.Panicf("FATAL: cannot move %s to %s: %s", dir, tmpDir, err)

View file

@ -5,7 +5,6 @@ import (
"os" "os"
"reflect" "reflect"
"sync" "sync"
"sync/atomic"
"unsafe" "unsafe"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
@ -25,7 +24,7 @@ func mustSyncPath(path string) {
} }
func mustRemoveDirAtomic(dir string) { func mustRemoveDirAtomic(dir string) {
n := atomic.AddUint64(&atomicDirRemoveCounter, 1) n := atomicDirRemoveCounter.Add(1)
tmpDir := fmt.Sprintf("%s.must-remove.%d", dir, n) tmpDir := fmt.Sprintf("%s.must-remove.%d", dir, n)
if err := os.Rename(dir, tmpDir); err != nil { if err := os.Rename(dir, tmpDir); err != nil {
logger.Panicf("FATAL: cannot move %s to %s: %s", dir, tmpDir, err) logger.Panicf("FATAL: cannot move %s to %s: %s", dir, tmpDir, err)

View file

@ -32,8 +32,8 @@ type MustReadAtCloser interface {
// ReaderAt implements rand-access reader. // ReaderAt implements rand-access reader.
type ReaderAt struct { type ReaderAt struct {
readCalls uint64 readCalls atomic.Int64
readBytes uint64 readBytes atomic.Int64
// path contains the path to the file for reading // path contains the path to the file for reading
path string path string
@ -81,8 +81,8 @@ func (r *ReaderAt) MustReadAt(p []byte, off int64) {
copy(p, src) copy(p, src)
} }
if r.useLocalStats { if r.useLocalStats {
atomic.AddUint64(&r.readCalls, 1) r.readCalls.Add(1)
atomic.AddUint64(&r.readBytes, uint64(len(p))) r.readBytes.Add(int64(len(p)))
} else { } else {
readCalls.Inc() readCalls.Inc()
readBytes.Add(len(p)) readBytes.Add(len(p))
@ -119,10 +119,10 @@ func (r *ReaderAt) MustClose() {
} }
if r.useLocalStats { if r.useLocalStats {
readCalls.Add(int(r.readCalls)) readCalls.AddInt64(r.readCalls.Load())
readBytes.Add(int(r.readBytes)) readBytes.AddInt64(r.readBytes.Load())
r.readCalls = 0 r.readCalls.Store(0)
r.readBytes = 0 r.readBytes.Store(0)
r.useLocalStats = false r.useLocalStats = false
} }
} }

View file

@ -68,7 +68,7 @@ var (
) )
type server struct { type server struct {
shutdownDelayDeadline int64 shutdownDelayDeadline atomic.Int64
s *http.Server s *http.Server
} }
@ -225,7 +225,7 @@ func stop(addr string) error {
} }
deadline := time.Now().Add(*shutdownDelay).UnixNano() deadline := time.Now().Add(*shutdownDelay).UnixNano()
atomic.StoreInt64(&s.shutdownDelayDeadline, deadline) s.shutdownDelayDeadline.Store(deadline)
if *shutdownDelay > 0 { if *shutdownDelay > 0 {
// Sleep for a while until load balancer in front of the server // Sleep for a while until load balancer in front of the server
// notifies that "/health" endpoint returns non-OK responses. // notifies that "/health" endpoint returns non-OK responses.
@ -339,7 +339,7 @@ func handlerWrapper(s *server, w http.ResponseWriter, r *http.Request, rh Reques
switch r.URL.Path { switch r.URL.Path {
case "/health": case "/health":
h.Set("Content-Type", "text/plain; charset=utf-8") h.Set("Content-Type", "text/plain; charset=utf-8")
deadline := atomic.LoadInt64(&s.shutdownDelayDeadline) deadline := s.shutdownDelayDeadline.Load()
if deadline <= 0 { if deadline <= 0 {
w.Write([]byte("OK")) w.Write([]byte("OK"))
return return

View file

@ -149,14 +149,11 @@ func (c *Cache) cleanByTimeout() {
} }
type cache struct { type cache struct {
// Atomically updated fields must go first in the struct, so they are properly requests atomic.Uint64
// aligned to 8 bytes on 32-bit architectures. misses atomic.Uint64
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/212
requests uint64
misses uint64
// sizeBytes contains an approximate size for all the blocks stored in the cache. // sizeBytes contains an approximate size for all the blocks stored in the cache.
sizeBytes int64 sizeBytes atomic.Int64
// getMaxSizeBytes() is a callback, which returns the maximum allowed cache size in bytes. // getMaxSizeBytes() is a callback, which returns the maximum allowed cache size in bytes.
getMaxSizeBytes func() int getMaxSizeBytes func() int
@ -204,7 +201,7 @@ func newCache(getMaxSizeBytes func() int) *cache {
} }
func (c *cache) updateSizeBytes(n int) { func (c *cache) updateSizeBytes(n int) {
atomic.AddInt64(&c.sizeBytes, int64(n)) c.sizeBytes.Add(int64(n))
} }
func (c *cache) cleanByTimeout() { func (c *cache) cleanByTimeout() {
@ -223,13 +220,13 @@ func (c *cache) cleanByTimeout() {
} }
func (c *cache) GetEntry(k string) Entry { func (c *cache) GetEntry(k string) Entry {
atomic.AddUint64(&c.requests, 1) c.requests.Add(1)
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
ce := c.m[k] ce := c.m[k]
if ce == nil { if ce == nil {
atomic.AddUint64(&c.misses, 1) c.misses.Add(1)
return nil return nil
} }
currentTime := fasttime.UnixTimestamp() currentTime := fasttime.UnixTimestamp()
@ -277,7 +274,7 @@ func (c *cache) Len() int {
} }
func (c *cache) SizeBytes() int { func (c *cache) SizeBytes() int {
return int(atomic.LoadInt64(&c.sizeBytes)) return int(c.sizeBytes.Load())
} }
func (c *cache) SizeMaxBytes() int { func (c *cache) SizeMaxBytes() int {
@ -285,11 +282,11 @@ func (c *cache) SizeMaxBytes() int {
} }
func (c *cache) Requests() uint64 { func (c *cache) Requests() uint64 {
return atomic.LoadUint64(&c.requests) return c.requests.Load()
} }
func (c *cache) Misses() uint64 { func (c *cache) Misses() uint64 {
return atomic.LoadUint64(&c.misses) return c.misses.Load()
} }
// lastAccessHeap implements heap.Interface // lastAccessHeap implements heap.Interface

View file

@ -44,10 +44,7 @@ func (cm *connMetrics) init(ms *metrics.Set, group, name, addr string) {
} }
type statConn struct { type statConn struct {
// Move atomic counters to the top of struct in order to properly align them on 32-bit arch. closeCalls atomic.Uint64
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/212
closeCalls uint64
net.Conn net.Conn
@ -90,7 +87,7 @@ func (sc *statConn) Write(p []byte) (int, error) {
} }
func (sc *statConn) Close() error { func (sc *statConn) Close() error {
n := atomic.AddUint64(&sc.closeCalls, 1) n := sc.closeCalls.Add(1)
if n > 1 { if n > 1 {
// The connection has been already closed. // The connection has been already closed.
return nil return nil

View file

@ -104,9 +104,9 @@ func newAPIWatcher(apiServer string, ac *promauth.Config, sdc *SDConfig, swcFunc
} }
func (aw *apiWatcher) mustStart() { func (aw *apiWatcher) mustStart() {
atomic.AddInt32(&aw.gw.apiWatcherInflightStartCalls, 1) aw.gw.apiWatcherInflightStartCalls.Add(1)
aw.gw.startWatchersForRole(aw.role, aw) aw.gw.startWatchersForRole(aw.role, aw)
atomic.AddInt32(&aw.gw.apiWatcherInflightStartCalls, -1) aw.gw.apiWatcherInflightStartCalls.Add(-1)
} }
func (aw *apiWatcher) updateSwosCount(multiplier int, swosByKey map[string][]interface{}) { func (aw *apiWatcher) updateSwosCount(multiplier int, swosByKey map[string][]interface{}) {
@ -214,15 +214,15 @@ func (aw *apiWatcher) getScrapeWorkObjects() []interface{} {
type groupWatcher struct { type groupWatcher struct {
// The number of in-flight apiWatcher.mustStart() calls for the given groupWatcher. // The number of in-flight apiWatcher.mustStart() calls for the given groupWatcher.
// This field is used by groupWatchersCleaner() in order to determine when the given groupWatcher can be stopped. // This field is used by groupWatchersCleaner() in order to determine when the given groupWatcher can be stopped.
apiWatcherInflightStartCalls int32 apiWatcherInflightStartCalls atomic.Int32
// Old Kubernetes doesn't support /apis/networking.k8s.io/v1/, so /apis/networking.k8s.io/v1beta1/ must be used instead. // Old Kubernetes doesn't support /apis/networking.k8s.io/v1/, so /apis/networking.k8s.io/v1beta1/ must be used instead.
// This flag is used for automatic substitution of v1 API path with v1beta1 API path during requests to apiServer. // This flag is used for automatic substitution of v1 API path with v1beta1 API path during requests to apiServer.
useNetworkingV1Beta1 uint32 useNetworkingV1Beta1 atomic.Bool
// Old Kubernetes doesn't support /apis/discovery.k8s.io/v1/, so discovery.k8s.io/v1beta1/ must be used instead. // Old Kubernetes doesn't support /apis/discovery.k8s.io/v1/, so discovery.k8s.io/v1beta1/ must be used instead.
// This flag is used for automatic substitution of v1 API path with v1beta1 API path during requests to apiServer. // This flag is used for automatic substitution of v1 API path with v1beta1 API path during requests to apiServer.
useDiscoveryV1Beta1 uint32 useDiscoveryV1Beta1 atomic.Bool
apiServer string apiServer string
namespaces []string namespaces []string
@ -343,7 +343,7 @@ func groupWatchersCleaner() {
awsTotal += len(uw.aws) + len(uw.awsPending) awsTotal += len(uw.aws) + len(uw.awsPending)
} }
if awsTotal == 0 && atomic.LoadInt32(&gw.apiWatcherInflightStartCalls) == 0 { if awsTotal == 0 && gw.apiWatcherInflightStartCalls.Load() == 0 {
// There are no API watchers subscribed to gw and there are no in-flight apiWatcher.mustStart() calls. // There are no API watchers subscribed to gw and there are no in-flight apiWatcher.mustStart() calls.
// Stop all the urlWatcher instances at gw and drop gw from groupWatchers in this case, // Stop all the urlWatcher instances at gw and drop gw from groupWatchers in this case,
// but do it only on the second iteration in order to reduce urlWatcher churn // but do it only on the second iteration in order to reduce urlWatcher churn
@ -471,11 +471,11 @@ func (gw *groupWatcher) startWatchersForRole(role string, aw *apiWatcher) {
// doRequest performs http request to the given requestURL. // doRequest performs http request to the given requestURL.
func (gw *groupWatcher) doRequest(ctx context.Context, requestURL string) (*http.Response, error) { func (gw *groupWatcher) doRequest(ctx context.Context, requestURL string) (*http.Response, error) {
if strings.Contains(requestURL, "/apis/networking.k8s.io/v1/") && atomic.LoadUint32(&gw.useNetworkingV1Beta1) == 1 { if strings.Contains(requestURL, "/apis/networking.k8s.io/v1/") && gw.useNetworkingV1Beta1.Load() {
// Update networking URL for old Kubernetes API, which supports only v1beta1 path. // Update networking URL for old Kubernetes API, which supports only v1beta1 path.
requestURL = strings.Replace(requestURL, "/apis/networking.k8s.io/v1/", "/apis/networking.k8s.io/v1beta1/", 1) requestURL = strings.Replace(requestURL, "/apis/networking.k8s.io/v1/", "/apis/networking.k8s.io/v1beta1/", 1)
} }
if strings.Contains(requestURL, "/apis/discovery.k8s.io/v1/") && atomic.LoadUint32(&gw.useDiscoveryV1Beta1) == 1 { if strings.Contains(requestURL, "/apis/discovery.k8s.io/v1/") && gw.useDiscoveryV1Beta1.Load() {
// Update discovery URL for old Kubernetes API, which supports only v1beta1 path. // Update discovery URL for old Kubernetes API, which supports only v1beta1 path.
requestURL = strings.Replace(requestURL, "/apis/discovery.k8s.io/v1/", "/apis/discovery.k8s.io/v1beta1/", 1) requestURL = strings.Replace(requestURL, "/apis/discovery.k8s.io/v1/", "/apis/discovery.k8s.io/v1beta1/", 1)
} }
@ -491,12 +491,12 @@ func (gw *groupWatcher) doRequest(ctx context.Context, requestURL string) (*http
return nil, err return nil, err
} }
if resp.StatusCode == http.StatusNotFound { if resp.StatusCode == http.StatusNotFound {
if strings.Contains(requestURL, "/apis/networking.k8s.io/v1/") && atomic.LoadUint32(&gw.useNetworkingV1Beta1) == 0 { if strings.Contains(requestURL, "/apis/networking.k8s.io/v1/") && !gw.useNetworkingV1Beta1.Load() {
atomic.StoreUint32(&gw.useNetworkingV1Beta1, 1) gw.useNetworkingV1Beta1.Store(true)
return gw.doRequest(ctx, requestURL) return gw.doRequest(ctx, requestURL)
} }
if strings.Contains(requestURL, "/apis/discovery.k8s.io/v1/") && atomic.LoadUint32(&gw.useDiscoveryV1Beta1) == 0 { if strings.Contains(requestURL, "/apis/discovery.k8s.io/v1/") && !gw.useDiscoveryV1Beta1.Load() {
atomic.StoreUint32(&gw.useDiscoveryV1Beta1, 1) gw.useDiscoveryV1Beta1.Store(true)
return gw.doRequest(ctx, requestURL) return gw.doRequest(ctx, requestURL)
} }
} }

View file

@ -79,9 +79,9 @@ func Stop() {
var ( var (
globalStopChan chan struct{} globalStopChan chan struct{}
scraperWG sync.WaitGroup scraperWG sync.WaitGroup
// PendingScrapeConfigs - zero value means, that
// all scrapeConfigs are inited and ready for work. // PendingScrapeConfigs - zero value means, that all scrapeConfigs are inited and ready for work.
PendingScrapeConfigs int32 PendingScrapeConfigs atomic.Int32
// configData contains -promscrape.config data // configData contains -promscrape.config data
configData atomic.Pointer[[]byte] configData atomic.Pointer[[]byte]
@ -225,7 +225,7 @@ func newScrapeConfigs(pushData func(at *auth.Token, wr *prompbmarshal.WriteReque
} }
func (scs *scrapeConfigs) add(name string, checkInterval time.Duration, getScrapeWork func(cfg *Config, swsPrev []*ScrapeWork) []*ScrapeWork) { func (scs *scrapeConfigs) add(name string, checkInterval time.Duration, getScrapeWork func(cfg *Config, swsPrev []*ScrapeWork) []*ScrapeWork) {
atomic.AddInt32(&PendingScrapeConfigs, 1) PendingScrapeConfigs.Add(1)
scfg := &scrapeConfig{ scfg := &scrapeConfig{
name: name, name: name,
pushData: scs.pushData, pushData: scs.pushData,
@ -292,7 +292,7 @@ func (scfg *scrapeConfig) run(globalStopCh <-chan struct{}) {
} }
} }
updateScrapeWork(cfg) updateScrapeWork(cfg)
atomic.AddInt32(&PendingScrapeConfigs, -1) PendingScrapeConfigs.Add(-1)
for { for {

View file

@ -56,7 +56,7 @@ var (
) )
type statConn struct { type statConn struct {
closed uint64 closed atomic.Int32
net.Conn net.Conn
} }
@ -82,7 +82,7 @@ func (sc *statConn) Write(p []byte) (int, error) {
func (sc *statConn) Close() error { func (sc *statConn) Close() error {
err := sc.Conn.Close() err := sc.Conn.Close()
if atomic.AddUint64(&sc.closed, 1) == 1 { if sc.closed.Add(1) == 1 {
conns.Dec() conns.Dec()
} }
return err return err

View file

@ -41,7 +41,11 @@ func NewName() string {
} }
func nextSnapshotIdx() uint64 { func nextSnapshotIdx() uint64 {
return atomic.AddUint64(&snapshotIdx, 1) return snapshotIdx.Add(1)
} }
var snapshotIdx = uint64(time.Now().UnixNano()) var snapshotIdx = func() *atomic.Uint64 {
var x atomic.Uint64
x.Store(uint64(time.Now().UnixNano()))
return &x
}()

View file

@ -43,7 +43,7 @@ type Cache struct {
// In this case using prev would result in RAM waste, // In this case using prev would result in RAM waste,
// it is better to use only curr cache with doubled size. // it is better to use only curr cache with doubled size.
// After the process of switching, this flag will be set to whole. // After the process of switching, this flag will be set to whole.
mode uint32 mode atomic.Uint32
// The maxBytes value passed to New() or to Load(). // The maxBytes value passed to New() or to Load().
maxBytes int maxBytes int
@ -110,7 +110,7 @@ func newCacheInternal(curr, prev *fastcache.Cache, mode, maxBytes int) *Cache {
c.curr.Store(curr) c.curr.Store(curr)
c.prev.Store(prev) c.prev.Store(prev)
c.stopCh = make(chan struct{}) c.stopCh = make(chan struct{})
c.setMode(mode) c.mode.Store(uint32(mode))
return &c return &c
} }
@ -143,7 +143,7 @@ func (c *Cache) expirationWatcher(expireDuration time.Duration) {
case <-t.C: case <-t.C:
} }
c.mu.Lock() c.mu.Lock()
if atomic.LoadUint32(&c.mode) != split { if c.mode.Load() != split {
// Stop the expirationWatcher on non-split mode. // Stop the expirationWatcher on non-split mode.
c.mu.Unlock() c.mu.Unlock()
return return
@ -183,7 +183,7 @@ func (c *Cache) prevCacheWatcher() {
case <-t.C: case <-t.C:
} }
c.mu.Lock() c.mu.Lock()
if atomic.LoadUint32(&c.mode) != split { if c.mode.Load() != split {
// Do nothing in non-split mode. // Do nothing in non-split mode.
c.mu.Unlock() c.mu.Unlock()
return return
@ -227,7 +227,7 @@ func (c *Cache) cacheSizeWatcher() {
return return
case <-t.C: case <-t.C:
} }
if c.loadMode() != split { if c.mode.Load() != split {
continue continue
} }
var cs fastcache.Stats var cs fastcache.Stats
@ -252,7 +252,7 @@ func (c *Cache) cacheSizeWatcher() {
// 6) drop prev cache // 6) drop prev cache
c.mu.Lock() c.mu.Lock()
c.setMode(switching) c.mode.Store(switching)
prev := c.prev.Load() prev := c.prev.Load()
curr := c.curr.Load() curr := c.curr.Load()
c.prev.Store(curr) c.prev.Store(curr)
@ -280,7 +280,7 @@ func (c *Cache) cacheSizeWatcher() {
} }
c.mu.Lock() c.mu.Lock()
c.setMode(whole) c.mode.Store(whole)
prev = c.prev.Load() prev = c.prev.Load()
c.prev.Store(fastcache.New(1024)) c.prev.Store(fastcache.New(1024))
cs.Reset() cs.Reset()
@ -318,15 +318,7 @@ func (c *Cache) Reset() {
updateCacheStatsHistory(&c.csHistory, &cs) updateCacheStatsHistory(&c.csHistory, &cs)
curr.Reset() curr.Reset()
// Reset the mode to `split` in the hope the working set size becomes smaller after the reset. // Reset the mode to `split` in the hope the working set size becomes smaller after the reset.
c.setMode(split) c.mode.Store(split)
}
func (c *Cache) setMode(mode int) {
atomic.StoreUint32(&c.mode, uint32(mode))
}
func (c *Cache) loadMode() int {
return int(atomic.LoadUint32(&c.mode))
} }
// UpdateStats updates fcs with cache stats. // UpdateStats updates fcs with cache stats.
@ -374,7 +366,7 @@ func (c *Cache) Get(dst, key []byte) []byte {
// Fast path - the entry is found in the current cache. // Fast path - the entry is found in the current cache.
return result return result
} }
if c.loadMode() == whole { if c.mode.Load() == whole {
// Nothing found. // Nothing found.
return result return result
} }
@ -397,7 +389,7 @@ func (c *Cache) Has(key []byte) bool {
if curr.Has(key) { if curr.Has(key) {
return true return true
} }
if c.loadMode() == whole { if c.mode.Load() == whole {
return false return false
} }
prev := c.prev.Load() prev := c.prev.Load()
@ -428,7 +420,7 @@ func (c *Cache) GetBig(dst, key []byte) []byte {
// Fast path - the entry is found in the current cache. // Fast path - the entry is found in the current cache.
return result return result
} }
if c.loadMode() == whole { if c.mode.Load() == whole {
// Nothing found. // Nothing found.
return result return result
} }

View file

@ -42,6 +42,11 @@ func (c *Counter) Add(n int) {
atomic.AddUint64(&c.n, uint64(n)) atomic.AddUint64(&c.n, uint64(n))
} }
// AddInt64 adds n to c.
func (c *Counter) AddInt64(n int64) {
atomic.AddUint64(&c.n, uint64(n))
}
// Get returns the current value for c. // Get returns the current value for c.
func (c *Counter) Get() uint64 { func (c *Counter) Get() uint64 {
return atomic.LoadUint64(&c.n) return atomic.LoadUint64(&c.n)

2
vendor/modules.txt vendored
View file

@ -99,7 +99,7 @@ github.com/VictoriaMetrics/easyproto
# github.com/VictoriaMetrics/fastcache v1.12.2 # github.com/VictoriaMetrics/fastcache v1.12.2
## explicit; go 1.13 ## explicit; go 1.13
github.com/VictoriaMetrics/fastcache github.com/VictoriaMetrics/fastcache
# github.com/VictoriaMetrics/metrics v1.32.0 # github.com/VictoriaMetrics/metrics v1.33.0
## explicit; go 1.17 ## explicit; go 1.17
github.com/VictoriaMetrics/metrics github.com/VictoriaMetrics/metrics
# github.com/VictoriaMetrics/metricsql v0.74.0 # github.com/VictoriaMetrics/metricsql v0.74.0