From 5c7314644639343d067fcd47c8b1ece8e500232e Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 24 Sep 2020 09:17:46 +0200 Subject: git2go: Serialize results directly into os.Stdout When spawning Git2Go commands, communication happens via serialized messages between parent and its child process. This is currently done by serializing into a string, only to print that string to standard output immediately afterwards. This pattern is quite inefficient, as we first need to serialize the whole string into memory. This commit implements a new function to serialize directly into a reader in order to avoid this overhead and adjusts the merge command to use it. --- internal/git2go/command.go | 8 ++++++++ internal/git2go/command_test.go | 28 ++++++++++++++++++++++++++++ internal/git2go/merge.go | 7 ++++--- internal/git2go/merge_test.go | 6 ++++-- 4 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 internal/git2go/command_test.go (limited to 'internal/git2go') diff --git a/internal/git2go/command.go b/internal/git2go/command.go index df94a9c0a..2409b847c 100644 --- a/internal/git2go/command.go +++ b/internal/git2go/command.go @@ -6,6 +6,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "io" "os/exec" "path" "strings" @@ -46,3 +47,10 @@ func deserialize(serialized string, v interface{}) error { jsonDecoder := json.NewDecoder(base64Decoder) return jsonDecoder.Decode(v) } + +func serializeTo(writer io.Writer, v interface{}) error { + base64Encoder := base64.NewEncoder(base64.StdEncoding, writer) + defer base64Encoder.Close() + jsonEncoder := json.NewEncoder(base64Encoder) + return jsonEncoder.Encode(v) +} diff --git a/internal/git2go/command_test.go b/internal/git2go/command_test.go new file mode 100644 index 000000000..14f1c0a3a --- /dev/null +++ b/internal/git2go/command_test.go @@ -0,0 +1,28 @@ +package git2go + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSerialization_SerializeTo(t *testing.T) { + type testStruct struct { + Contents string `json:"contents"` + } + + var buf bytes.Buffer + + input := testStruct{ + Contents: "foobar", + } + err := serializeTo(&buf, &input) + require.NoError(t, err) + require.NotZero(t, buf.Len()) + + var output testStruct + err = deserialize(buf.String(), &output) + require.NoError(t, err) + require.Equal(t, input, output) +} diff --git a/internal/git2go/merge.go b/internal/git2go/merge.go index 39cf88b4a..a60ff51c8 100644 --- a/internal/git2go/merge.go +++ b/internal/git2go/merge.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "io" "time" "gitlab.com/gitlab-org/gitaly/internal/gitaly/config" @@ -52,9 +53,9 @@ func MergeCommandFromSerialized(serialized string) (MergeCommand, error) { return request, nil } -// Serialize serializes the merge response into its JSON representation and encodes it with base64. -func (m MergeResult) Serialize() (string, error) { - return serialize(m) +// SerializeTo serializes the merge result and writes it into the writer. +func (m MergeResult) SerializeTo(w io.Writer) error { + return serializeTo(w, m) } // Merge performs a merge via gitaly-git2go. diff --git a/internal/git2go/merge_test.go b/internal/git2go/merge_test.go index 1de4f3cab..5f0bc60c4 100644 --- a/internal/git2go/merge_test.go +++ b/internal/git2go/merge_test.go @@ -1,6 +1,7 @@ package git2go import ( + "bytes" "testing" "time" @@ -108,9 +109,10 @@ func TestGit2Go_MergeCommandSerialization(t *testing.T) { func TestGit2Go_MergeResultSerialization(t *testing.T) { serializeResult := func(t *testing.T, result MergeResult) string { - serialized, err := result.Serialize() + var buf bytes.Buffer + err := result.SerializeTo(&buf) require.NoError(t, err) - return serialized + return buf.String() } testcases := []struct { -- cgit v1.2.3