Improve performance of Warehouse.ReadFile by detecting file not found error via os.Open, instead of wh.FileExists which is a very expensive function.

This commit is contained in:
Kleissner
2022-01-17 15:39:39 +01:00
parent 1af98ab141
commit 86cf8e1fe8

View File

@@ -139,18 +139,26 @@ func (wh *Warehouse) CreateFileFromPath(file string) (hash []byte, status int, e
// Offset is the position in the file to start reading. Limit (0 = not used) defines how many bytes to read starting at the offset.
// Return status codes: StatusInvalidHash, StatusFileNotFound, StatusErrorOpenFile, StatusErrorSeekFile, StatusErrorReadFile, StatusOK
func (wh *Warehouse) ReadFile(hash []byte, offset, limit int64, writer io.Writer) (status int, bytesRead int64, err error) {
path, _, status, err := wh.FileExists(hash)
if status != StatusOK { // file does not exist or invalid hash
return status, 0, err
// validate the hash and build the path
// 17.01.2022: This code previously used wh.FileExists which is not performant when used frequently. It is faster to instead catch the file-not-exist error on os.Open.
hashA, err := ValidateHash(hash)
if err != nil {
return StatusInvalidHash, 0, err
}
a, b := buildPath(wh.Directory, hashA)
path := filepath.Join(a, b)
// read the file from disk
var reader io.ReadSeeker
retryCount := 0
retryOpenFile:
file, err := os.Open(path)
if err != nil {
if err != nil && os.IsNotExist(err) {
// Catch the error file not exist here.
return StatusFileNotFound, 0, err
} else if err != nil {
// There may be a race condition when the file is being written: "The process cannot access the file because it is being used by another process."
// Wait up to 3 times for 400ms.
if strings.Contains(err.Error(), "cannot access the file because it is being used by another process") && retryCount < 3 {