fs: Convert repeated code in rwpool.Open() into a single function. (#4864)

Refer https://github.com/minio/minio/issues/4658 for more information.
master
Harshavardhana 7 years ago committed by Dee Koder
parent 9e9faf7b53
commit 6dca044ea8
  1. 95
      cmd/fs-v1-rwpool.go

@ -31,24 +31,16 @@ type fsIOPool struct {
readersMap map[string]*lock.RLockedFile readersMap map[string]*lock.RLockedFile
} }
// Open is a wrapper call to read locked file which // lookupToRead - looks up an fd from readers map and
// returns a ReadAtCloser. // returns read locked fd for caller to read from, if
// fd found increments the reference count. If the fd
// is found to be closed then purges it from the
// readersMap and returns nil instead.
// //
// ReaderAt is provided so that the fd is non seekable, since // NOTE: this function is not protected and it is callers
// we are sharing fd's with concurrent threads, we don't want // responsibility to lock this call to be thread safe. For
// all readers to change offsets on each other during such // implementation ideas look at the usage inside Open() call.
// concurrent operations. Using ReadAt allows us to read from func (fsi *fsIOPool) lookupToRead(path string) (*lock.RLockedFile, bool) {
// any offsets.
//
// Closer is implemented to track total readers and to close
// only when there no more readers, the fd is purged if the lock
// count has reached zero.
func (fsi *fsIOPool) Open(path string) (*lock.RLockedFile, error) {
if err := checkPathLength(path); err != nil {
return nil, err
}
fsi.Lock()
rlkFile, ok := fsi.readersMap[path] rlkFile, ok := fsi.readersMap[path]
// File reference exists on map, validate if its // File reference exists on map, validate if its
// really closed and we are safe to purge it. // really closed and we are safe to purge it.
@ -69,15 +61,33 @@ func (fsi *fsIOPool) Open(path string) (*lock.RLockedFile, error) {
rlkFile.IncLockRef() rlkFile.IncLockRef()
} }
} }
fsi.Unlock() return rlkFile, ok
}
// Locked path reference doesn't exist, freshly open the file in // Open is a wrapper call to read locked file which
// read lock mode. // returns a ReadAtCloser.
//
// ReaderAt is provided so that the fd is non seekable, since
// we are sharing fd's with concurrent threads, we don't want
// all readers to change offsets on each other during such
// concurrent operations. Using ReadAt allows us to read from
// any offsets.
//
// Closer is implemented to track total readers and to close
// only when there no more readers, the fd is purged if the lock
// count has reached zero.
func (fsi *fsIOPool) Open(path string) (*lock.RLockedFile, error) {
if err := checkPathLength(path); err != nil {
return nil, err
}
fsi.Lock()
rlkFile, ok := fsi.lookupToRead(path)
fsi.Unlock()
// Locked path reference doesn't exist, acquire a read lock again on the file.
if !ok { if !ok {
var err error // Open file for reading with read lock.
var newRlkFile *lock.RLockedFile newRlkFile, err := lock.RLockedOpenFile(path)
// Open file for reading.
newRlkFile, err = lock.RLockedOpenFile(path)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil, errFileNotFound return nil, errFileNotFound
@ -93,34 +103,29 @@ func (fsi *fsIOPool) Open(path string) (*lock.RLockedFile, error) {
return nil, err return nil, err
} }
// Save new reader on the map. /// Save new reader on the map.
// It is possible by this time due to concurrent
// i/o we might have another lock present. Lookup
// again to check for such a possibility. If no such
// file exists save the newly opened fd, if not
// reuse the existing fd and close the newly opened
// file
fsi.Lock() fsi.Lock()
rlkFile, ok = fsi.readersMap[path] rlkFile, ok = fsi.lookupToRead(path)
if ok && rlkFile != nil { if ok {
// If the file is closed and not removed from map is a bug. // Close the new fd, since we already seem to have
if rlkFile.IsClosed() { // an active reference.
// Log this as an error. newRlkFile.Close()
errorIf(errUnexpected, "Unexpected entry found on the map %s", path)
// Purge the cached lock path from map.
delete(fsi.readersMap, path)
// Save the newly acquired read locked file.
rlkFile = newRlkFile
} else {
// Increment the lock ref, since the file is not closed yet
// and caller requested to read the file again.
rlkFile.IncLockRef()
newRlkFile.Close()
}
} else { } else {
// Save the newly acquired read locked file. // Save the new rlk file.
rlkFile = newRlkFile rlkFile = newRlkFile
} }
// Save the rlkFile back on the map. // Save the new fd on the map.
fsi.readersMap[path] = rlkFile fsi.readersMap[path] = rlkFile
fsi.Unlock() fsi.Unlock()
} }
// Success. // Success.

Loading…
Cancel
Save