Merge pull request #559 from domcyrus/fix-race-on-table-file

fix race condition on table.file #557
This commit is contained in:
Max Mazurov 2022-12-05 17:22:02 +03:00 committed by GitHub
commit 01ff37a9c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 47 deletions

View file

@ -124,24 +124,31 @@ func (f *File) reloader() {
for {
select {
case <-t.C:
f.reload()
case <-f.forceReload:
f.reload()
case <-f.stopReloader:
f.stopReloader <- struct{}{}
return
}
}
}
func (f *File) reload() {
info, err := os.Stat(f.file)
if err != nil {
if os.IsNotExist(err) {
f.mLck.Lock()
f.m = map[string][]string{}
f.mStamp = time.Now()
f.mLck.Unlock()
continue
return
}
f.log.Error("os stat", err)
}
if info.ModTime().Before(f.mStamp) {
continue // reload not necessary
}
case <-f.forceReload:
case <-f.stopReloader:
f.stopReloader <- struct{}{}
return
if info.ModTime().Before(f.mStamp) || time.Since(info.ModTime()) < (reloadInterval/2) {
return // reload not necessary
}
f.log.Debugf("reloading")
@ -150,19 +157,29 @@ func (f *File) reloader() {
if err := readFile(f.file, newm); err != nil {
if os.IsNotExist(err) {
f.log.Printf("ignoring non-existent file: %s", f.file)
continue
return
}
f.log.Println(err)
continue
return
}
// after reading we need to check whether file has changed in between
info2, err := os.Stat(f.file)
if err != nil {
f.log.Println(err)
return
}
if !info2.ModTime().Equal(info.ModTime()) {
// file has changed in the meantime
return
}
f.mLck.Lock()
f.m = newm
f.mStamp = time.Now()
f.mStamp = info.ModTime()
f.mLck.Unlock()
}
}
func (f *File) Close() error {
f.stopReloader <- struct{}{}

View file

@ -111,27 +111,26 @@ func TestFileReload(t *testing.T) {
t.Fatal(err)
}
// This delay is somehow important. Not sure why.
time.Sleep(500 * time.Millisecond)
// ensure it is correctly loaded at first time.
m.mLck.RLock()
if m.m["cat"] == nil {
t.Fatalf("wrong content loaded, new m were not loaded, %v", m.m)
}
m.mLck.RUnlock()
if err := ioutil.WriteFile(f.Name(), []byte("dog: cat"), os.ModePerm); err != nil {
for i := 0; i < 100; i++ {
// try to provoke race condition on file writing
if i%2 == 0 {
if err := os.WriteFile(f.Name(), []byte("dog: cat"), os.ModePerm); err != nil {
t.Fatal(err)
}
for i := 0; i < 10; i++ {
time.Sleep(reloadInterval + 50*time.Millisecond)
m.mLck.RLock()
if m.m["dog"] != nil {
m.mLck.RUnlock()
break
}
m.mLck.RUnlock()
}
time.Sleep(reloadInterval + 5*time.Millisecond)
m.mLck.RLock()
defer m.mLck.RUnlock()
if m.m["dog"] == nil {
t.Fatal("New m were not loaded")
t.Fatalf("wrong content loaded, new m were not loaded, %v", m.m)
}
m.mLck.RUnlock()
}
}
@ -208,9 +207,6 @@ func TestFileReload_Removed(t *testing.T) {
t.Fatal(err)
}
// This delay is somehow important. Not sure why.
time.Sleep(250 * time.Millisecond)
os.Remove(f.Name())
time.Sleep(3 * reloadInterval)
@ -223,5 +219,5 @@ func TestFileReload_Removed(t *testing.T) {
}
func init() {
reloadInterval = 250 * time.Millisecond
reloadInterval = 10 * time.Millisecond
}