From 86cf8e1fe888b06343a625372adfe33a5c8d724d Mon Sep 17 00:00:00 2001 From: Kleissner Date: Mon, 17 Jan 2022 15:39:39 +0100 Subject: [PATCH] Improve performance of Warehouse.ReadFile by detecting file not found error via os.Open, instead of wh.FileExists which is a very expensive function. --- warehouse/Store.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/warehouse/Store.go b/warehouse/Store.go index 61a1c15..10471db 100644 --- a/warehouse/Store.go +++ b/warehouse/Store.go @@ -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 {