@@ -10,6 +10,7 @@ import (
1010 "os"
1111 "reflect"
1212 "sync"
13+ "sync/atomic"
1314 "time"
1415
1516 "code.gitea.io/gitea/modules/log"
@@ -31,7 +32,7 @@ type locale struct {
3132
3233 sourceFileName string
3334 sourceFileInfo os.FileInfo
34- lastReloadCheckTime time. Time
35+ lastReloadCheckTime atomic. Value
3536}
3637
3738type LocaleStore struct {
@@ -66,6 +67,7 @@ func (ls *LocaleStore) AddLocaleByIni(langName, langDesc string, source interfac
6667 if fileName , ok := source .(string ); ok {
6768 lc .sourceFileName = fileName
6869 lc .sourceFileInfo , _ = os .Stat (fileName ) // live-reload only works for regular files. the error can be ignored
70+ lc .lastReloadCheckTime .Store (& time.Time {})
6971 }
7072
7173 ls .langNames = append (ls .langNames , langName )
@@ -146,22 +148,27 @@ func (l *locale) Tr(trKey string, trArgs ...interface{}) string {
146148func (l * locale ) tryTr (trKey string , trArgs ... interface {}) (msg string , found bool ) {
147149 if l .store .reloadMu != nil {
148150 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+
150156 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
155160 if err = l .store .reloadLocaleByIni (l .langName , l .sourceFileName ); err == nil {
156161 l .sourceFileInfo = sourceFileInfo
162+ log .Info ("reloaded locale file %q" , l .sourceFileName )
157163 } else {
158164 log .Error ("unable to live-reload the locale file %q, err: %v" , l .sourceFileName , err )
159165 }
166+ l .store .reloadMu .Unlock () // release the write-lock
160167 } else if err != nil {
161168 log .Error ("unable to stat the locale file %q, err: %v" , l .sourceFileName , err )
162169 }
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
165172 }
166173 }
167174 trMsg := trKey
0 commit comments