mirror of
https://github.com/minio/minio.git
synced 2025-01-11 15:03:22 -05:00
fs: Convert repeated code in rwpool.Open() into a single function. (#4864)
Refer https://github.com/minio/minio/issues/4658 for more information.
This commit is contained in:
parent
9e9faf7b53
commit
6dca044ea8
@ -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…
Reference in New Issue
Block a user