@@ -10,6 +10,7 @@ import (
10
10
"os"
11
11
"reflect"
12
12
"sync"
13
+ "sync/atomic"
13
14
"time"
14
15
15
16
"code.gitea.io/gitea/modules/log"
@@ -31,7 +32,7 @@ type locale struct {
31
32
32
33
sourceFileName string
33
34
sourceFileInfo os.FileInfo
34
- lastReloadCheckTime time. Time
35
+ lastReloadCheckTime atomic. Value
35
36
}
36
37
37
38
type LocaleStore struct {
@@ -66,6 +67,7 @@ func (ls *LocaleStore) AddLocaleByIni(langName, langDesc string, source interfac
66
67
if fileName , ok := source .(string ); ok {
67
68
lc .sourceFileName = fileName
68
69
lc .sourceFileInfo , _ = os .Stat (fileName ) // live-reload only works for regular files. the error can be ignored
70
+ lc .lastReloadCheckTime .Store (& time.Time {})
69
71
}
70
72
71
73
ls .langNames = append (ls .langNames , langName )
@@ -146,22 +148,27 @@ func (l *locale) Tr(trKey string, trArgs ...interface{}) string {
146
148
func (l * locale ) tryTr (trKey string , trArgs ... interface {}) (msg string , found bool ) {
147
149
if l .store .reloadMu != nil {
148
150
now := time .Now ()
149
- if now .Sub (l .lastReloadCheckTime ) >= time .Second && l .sourceFileInfo != nil && l .sourceFileName != "" {
151
+ lastCheckTime , ok := l .lastReloadCheckTime .Load ().(* time.Time )
152
+ if ok && now .Sub (* lastCheckTime ) >= time .Second && l .sourceFileInfo != nil {
153
+ lastModTime := l .sourceFileInfo .ModTime ()
154
+ l .store .reloadMu .RUnlock () // the file may need to be reloaded with a write-lock, release the read-lock first
155
+
150
156
sourceFileInfo , err := os .Stat (l .sourceFileName )
151
- l .store .reloadMu .RUnlock () // if the locale file should be reloaded, then we release the read-lock
152
- l .store .reloadMu .Lock () // and acquire the write-lock
153
- l .lastReloadCheckTime = now
154
- if err == nil && ! sourceFileInfo .ModTime ().Equal (l .sourceFileInfo .ModTime ()) {
157
+ casOk := l .lastReloadCheckTime .CompareAndSwap (lastCheckTime , & now )
158
+ if err == nil && casOk && ! sourceFileInfo .ModTime ().Equal (lastModTime ) {
159
+ l .store .reloadMu .Lock () // acquire the write-lock only if the file need to be reloaded
155
160
if err = l .store .reloadLocaleByIni (l .langName , l .sourceFileName ); err == nil {
156
161
l .sourceFileInfo = sourceFileInfo
162
+ log .Info ("reloaded locale file %q" , l .sourceFileName )
157
163
} else {
158
164
log .Error ("unable to live-reload the locale file %q, err: %v" , l .sourceFileName , err )
159
165
}
166
+ l .store .reloadMu .Unlock () // release the write-lock
160
167
} else if err != nil {
161
168
log .Error ("unable to stat the locale file %q, err: %v" , l .sourceFileName , err )
162
169
}
163
- l . store . reloadMu . Unlock () // release the write-lock
164
- l .store .reloadMu .RLock () // and re-acquire the read-lock, which was managed by outer Tr function
170
+
171
+ l .store .reloadMu .RLock () // re-acquire the read-lock, which was managed by outer Tr function
165
172
}
166
173
}
167
174
trMsg := trKey
0 commit comments