From e4168fdde5962f2097d106360cb2f2c52078e9cd Mon Sep 17 00:00:00 2001 From: Fabian Wickborn Date: Mon, 22 Feb 2016 11:50:32 +0100 Subject: [PATCH] restic-server: Reduce memory footprint for saving blobs Before, the restic-server read the whole blob (up to 8MB) into memory prior to writing it to disk. Concurrent writes consumed a lot of memory. This change writes the blob to a tmp file directly and renames it afterwards in case there where no errors. --- src/restic/cmd/restic-server/handlers.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/restic/cmd/restic-server/handlers.go b/src/restic/cmd/restic-server/handlers.go index 6c87ef121..f7c4d8c5d 100644 --- a/src/restic/cmd/restic-server/handlers.go +++ b/src/restic/cmd/restic-server/handlers.go @@ -5,6 +5,7 @@ package main import ( "encoding/json" "fmt" + "io" "io/ioutil" "net/http" "os" @@ -150,13 +151,22 @@ func SaveBlob(c *Context) http.HandlerFunc { dir := vars[1] name := vars[2] path := filepath.Join(c.path, dir, name) - bytes, err := ioutil.ReadAll(r.Body) + tmp := path + "_tmp" + tf, err := os.OpenFile(tmp, os.O_CREATE|os.O_WRONLY, 0600) if err != nil { - http.Error(w, "400 bad request", 400) + http.Error(w, "500 internal server error", 500) return } - errw := ioutil.WriteFile(path, bytes, 0600) - if errw != nil { + if _, err := io.Copy(tf, r.Body); err != nil { + http.Error(w, "400 bad request", 400) + tf.Close() + os.Remove(tmp) + return + } + if err := tf.Close(); err != nil { + http.Error(w, "500 internal server error", 500) + } + if err := os.Rename(tmp, path); err != nil { http.Error(w, "500 internal server error", 500) return }