Skip to content

Commit

Permalink
do not leave orphan goroutine for waiting file handle close
Browse files Browse the repository at this point in the history
  • Loading branch information
iychoi committed Feb 13, 2025
1 parent 750b074 commit 560a240
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 26 deletions.
5 changes: 2 additions & 3 deletions fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package fs

import (
"path"
"sync"
"time"

"github.com/cyverse/go-irodsclient/irods/common"
Expand Down Expand Up @@ -306,7 +305,7 @@ func (fs *FileSystem) RemoveFile(path string, force bool) error {
defer fs.metadataSession.ReturnConnection(conn) //nolint

// if file handle is opened, wg
wg := sync.WaitGroup{}
wg := util.NewTimeoutWaitGroup()
wg.Add(1)

eventHandlerID := fs.fileHandleMap.AddCloseEventHandler(irodsPath, func(path, id string, empty bool) {
Expand All @@ -317,7 +316,7 @@ func (fs *FileSystem) RemoveFile(path string, force bool) error {

defer fs.fileHandleMap.RemoveCloseEventHandler(eventHandlerID)

if util.WaitTimeout(&wg, time.Duration(fs.config.MetadataConnection.OperationTimeout)) {
if wg.WaitTimeout(time.Duration(fs.config.MetadataConnection.OperationTimeout)) {
// timed out
return xerrors.Errorf("failed to remove file, there are files still opened")
}
Expand Down
23 changes: 0 additions & 23 deletions irods/util/timeout.go

This file was deleted.

50 changes: 50 additions & 0 deletions irods/util/timeout_wait.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package util

import (
"sync/atomic"
"time"
)

type TimeoutWaitGroup struct {
count int32
done chan struct{}
}

func NewTimeoutWaitGroup() *TimeoutWaitGroup {
return &TimeoutWaitGroup{
done: make(chan struct{}),
}
}

func (wg *TimeoutWaitGroup) Add(i int32) {
select {
case <-wg.done:
panic("use of an already closed TimeoutWaitGroup")
default:
}

atomic.AddInt32(&wg.count, i)
}

func (wg *TimeoutWaitGroup) Done() {
i := atomic.AddInt32(&wg.count, -1)
if i == 0 {
close(wg.done)
}
if i < 0 {
panic("too many Done() calls")
}
}

func (wg *TimeoutWaitGroup) C() <-chan struct{} {
return wg.done
}

func (wg *TimeoutWaitGroup) WaitTimeout(timeout time.Duration) bool {
select {
case <-wg.done:
return true // done
case <-time.After(timeout):
return false // timed out
}
}

0 comments on commit 560a240

Please sign in to comment.