From 5fffd558d041da6a3263335ced05ab34c9e81985 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Wed, 27 Apr 2016 15:10:19 -0700 Subject: [PATCH] xl/heal: Make healFile non-blocking for StatFile and ReadFile. (#1399) Fixes #1355 --- xl-v1-healfile.go | 1 + xl-v1-readfile.go | 25 ++++++++++++++----------- xl-v1.go | 17 ++++++++++------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/xl-v1-healfile.go b/xl-v1-healfile.go index c23aa3595..71debfcff 100644 --- a/xl-v1-healfile.go +++ b/xl-v1-healfile.go @@ -37,6 +37,7 @@ func (xl XL) healFile(volume string, path string) error { xl.lockNS(volume, path, readLock) defer xl.unlockNS(volume, path, readLock) + // Fetch all online disks. onlineDisks, metadata, heal, err := xl.listOnlineDisks(volume, path) if err != nil { log.WithFields(logrus.Fields{ diff --git a/xl-v1-readfile.go b/xl-v1-readfile.go index 5285dc35b..3fca69085 100644 --- a/xl-v1-readfile.go +++ b/xl-v1-readfile.go @@ -49,19 +49,19 @@ func (xl XL) ReadFile(volume, path string, offset int64) (io.ReadCloser, error) } if heal { - if err = xl.healFile(volume, path); err != nil { - log.WithFields(logrus.Fields{ - "volume": volume, - "path": path, - }).Errorf("healFile failed with %s", err) - return nil, err - } + // Heal in background safely, since we already have read + // quorum disks. Let the reads continue. + go func() { + if err = xl.healFile(volume, path); err != nil { + log.WithFields(logrus.Fields{ + "volume": volume, + "path": path, + }).Errorf("healFile failed with %s", err) + return + } + }() } - // Acquire read lock again. - xl.lockNS(volume, path, readLock) - defer xl.unlockNS(volume, path, readLock) - fileSize, err := metadata.GetSize() if err != nil { log.WithFields(logrus.Fields{ @@ -71,6 +71,8 @@ func (xl XL) ReadFile(volume, path string, offset int64) (io.ReadCloser, error) return nil, err } + // Acquire read lock again. + xl.lockNS(volume, path, readLock) readers := make([]io.ReadCloser, len(xl.storageDisks)) for index, disk := range onlineDisks { if disk == nil { @@ -84,6 +86,7 @@ func (xl XL) ReadFile(volume, path string, offset int64) (io.ReadCloser, error) readers[index] = reader } } + xl.unlockNS(volume, path, readLock) // Initialize pipe. pipeReader, pipeWriter := io.Pipe() diff --git a/xl-v1.go b/xl-v1.go index 54d8c3119..d024b0d8c 100644 --- a/xl-v1.go +++ b/xl-v1.go @@ -536,13 +536,16 @@ func (xl XL) StatFile(volume, path string) (FileInfo, error) { } if heal { - if err = xl.healFile(volume, path); err != nil { - log.WithFields(logrus.Fields{ - "volume": volume, - "path": path, - }).Errorf("healFile failed with %s", err) - return FileInfo{}, err - } + // Heal in background safely, since we already have read quorum disks. + go func() { + if err = xl.healFile(volume, path); err != nil { + log.WithFields(logrus.Fields{ + "volume": volume, + "path": path, + }).Errorf("healFile failed with %s", err) + return + } + }() } // Extract metadata.