From c603f8548891180c19bfc7e9d53968e5e1de617d Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Thu, 28 Oct 2021 17:02:22 -0700 Subject: [PATCH] readAllData: Reuse small file buffers (#13530) (Re)use small buffers for small readAllData operations. --- cmd/storage-rest-server.go | 3 +++ cmd/xl-storage.go | 25 ++++++++++++++++++++++--- cmd/xl-storage_test.go | 3 ++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/cmd/storage-rest-server.go b/cmd/storage-rest-server.go index 75a7621df..66d68ea5e 100644 --- a/cmd/storage-rest-server.go +++ b/cmd/storage-rest-server.go @@ -497,6 +497,8 @@ func (s *storageRESTServer) ReadAllHandler(w http.ResponseWriter, r *http.Reques s.writeErrorResponse(w, err) return } + // Reuse after return. + defer metaDataPoolPut(buf) w.Header().Set(xhttp.ContentLength, strconv.Itoa(len(buf))) w.Write(buf) } @@ -535,6 +537,7 @@ func (s *storageRESTServer) ReadFileHandler(w http.ResponseWriter, r *http.Reque verifier = NewBitrotVerifier(BitrotAlgorithmFromString(vars[storageRESTBitrotAlgo]), hash) } buf := make([]byte, length) + defer metaDataPoolPut(buf) // Reuse if we can. _, err = s.storage.ReadFile(r.Context(), volume, filePath, int64(offset), buf, verifier) if err != nil { s.writeErrorResponse(w, err) diff --git a/cmd/xl-storage.go b/cmd/xl-storage.go index a2ee4af0a..831cdc530 100644 --- a/cmd/xl-storage.go +++ b/cmd/xl-storage.go @@ -859,6 +859,8 @@ func (s *xlStorage) DeleteVersion(ctx context.Context, volume, path string, fi F // Create a new xl.meta with a delete marker in it return s.WriteMetadata(ctx, volume, path, fi) } + metaDataPoolPut(buf) // Never used, return it + buf, err = s.ReadAll(ctx, volume, pathJoin(path, xlStorageFormatFileV1)) if err != nil { if err == errFileNotFound && fi.VersionID != "" { @@ -1232,12 +1234,29 @@ func (s *xlStorage) readAllData(volumeDir string, filePath string) (buf []byte, SmallFile: true, } defer r.Close() - buf, err = ioutil.ReadAll(r) + + // Get size for precise allocation. + stat, err := f.Stat() if err != nil { - err = osErrToFileErr(err) + buf, err = ioutil.ReadAll(r) + return buf, osErrToFileErr(err) + } + if stat.IsDir() { + return nil, errFileNotFound } - return buf, err + // Read into appropriate buffer. + sz := stat.Size() + if sz <= metaDataReadDefault { + buf = metaDataPoolGet() + buf = buf[:sz] + } else { + buf = make([]byte, sz) + } + // Read file... + _, err = io.ReadFull(r, buf) + + return buf, osErrToFileErr(err) } // ReadAll reads from r until an error or EOF and returns the data it read. diff --git a/cmd/xl-storage_test.go b/cmd/xl-storage_test.go index 339126943..e752698b4 100644 --- a/cmd/xl-storage_test.go +++ b/cmd/xl-storage_test.go @@ -443,7 +443,8 @@ func TestXLStorageReadAll(t *testing.T) { for i, testCase := range testCases { dataRead, err = xlStorage.ReadAll(context.Background(), testCase.volume, testCase.path) if err != testCase.err { - t.Fatalf("TestXLStorage %d: Expected err \"%s\", got err \"%s\"", i+1, testCase.err, err) + t.Errorf("TestXLStorage %d: Expected err \"%v\", got err \"%v\"", i+1, testCase.err, err) + continue } if err == nil { if string(dataRead) != string([]byte("Hello, World")) {