Skip to content

Commit 7d43437

Browse files
zeripathlafriks
authored andcommitted
Pooled and buffered gzip implementation (#5722)
* Pooled and buffered gzip implementation * Add test for gzip * Add integration test * Ensure lfs check within transaction The previous code made it possible for a race condition to occur whereby a LFSMetaObject could be checked into the database twice. We should check if the LFSMetaObject is within the database and insert it if not in one transaction. * Try to avoid primary key problem in postgres The integration tests are being affected by go-testfixtures/testfixtures#39 if we set the primary key high enough, keep a count of this and remove at the end of each test we shouldn't be affected by this.
1 parent 0756495 commit 7d43437

File tree

6 files changed

+598
-10
lines changed

6 files changed

+598
-10
lines changed

integrations/lfs_getobject_test.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// Copyright 2019 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package integrations
6+
7+
import (
8+
"archive/zip"
9+
"bytes"
10+
"crypto/sha256"
11+
"encoding/hex"
12+
"io"
13+
"io/ioutil"
14+
"net/http"
15+
"testing"
16+
17+
"code.gitea.io/gitea/models"
18+
"code.gitea.io/gitea/modules/gzip"
19+
"code.gitea.io/gitea/modules/lfs"
20+
"code.gitea.io/gitea/modules/setting"
21+
"github.com/stretchr/testify/assert"
22+
23+
gzipp "github.com/klauspost/compress/gzip"
24+
)
25+
26+
func GenerateLFSOid(content io.Reader) (string, error) {
27+
h := sha256.New()
28+
if _, err := io.Copy(h, content); err != nil {
29+
return "", err
30+
}
31+
sum := h.Sum(nil)
32+
return hex.EncodeToString(sum), nil
33+
}
34+
35+
var lfsID = int64(20000)
36+
37+
func storeObjectInRepo(t *testing.T, repositoryID int64, content *[]byte) string {
38+
oid, err := GenerateLFSOid(bytes.NewReader(*content))
39+
assert.NoError(t, err)
40+
var lfsMetaObject *models.LFSMetaObject
41+
42+
if setting.UsePostgreSQL {
43+
lfsMetaObject = &models.LFSMetaObject{ID: lfsID, Oid: oid, Size: int64(len(*content)), RepositoryID: repositoryID}
44+
} else {
45+
lfsMetaObject = &models.LFSMetaObject{Oid: oid, Size: int64(len(*content)), RepositoryID: repositoryID}
46+
}
47+
48+
lfsID = lfsID + 1
49+
lfsMetaObject, err = models.NewLFSMetaObject(lfsMetaObject)
50+
assert.NoError(t, err)
51+
contentStore := &lfs.ContentStore{BasePath: setting.LFS.ContentPath}
52+
if !contentStore.Exists(lfsMetaObject) {
53+
err := contentStore.Put(lfsMetaObject, bytes.NewReader(*content))
54+
assert.NoError(t, err)
55+
}
56+
return oid
57+
}
58+
59+
func doLfs(t *testing.T, content *[]byte, expectGzip bool) {
60+
prepareTestEnv(t)
61+
repo, err := models.GetRepositoryByOwnerAndName("user2", "repo1")
62+
assert.NoError(t, err)
63+
oid := storeObjectInRepo(t, repo.ID, content)
64+
defer repo.RemoveLFSMetaObjectByOid(oid)
65+
66+
session := loginUser(t, "user2")
67+
68+
// Request OID
69+
req := NewRequest(t, "GET", "/user2/repo1.git/info/lfs/objects/"+oid+"/test")
70+
req.Header.Set("Accept-Encoding", "gzip")
71+
resp := session.MakeRequest(t, req, http.StatusOK)
72+
73+
contentEncoding := resp.Header().Get("Content-Encoding")
74+
if !expectGzip || !setting.EnableGzip {
75+
assert.NotContains(t, contentEncoding, "gzip")
76+
77+
result := resp.Body.Bytes()
78+
assert.Equal(t, *content, result)
79+
} else {
80+
assert.Contains(t, contentEncoding, "gzip")
81+
gzippReader, err := gzipp.NewReader(resp.Body)
82+
assert.NoError(t, err)
83+
result, err := ioutil.ReadAll(gzippReader)
84+
assert.NoError(t, err)
85+
assert.Equal(t, *content, result)
86+
}
87+
88+
}
89+
90+
func TestGetLFSSmall(t *testing.T) {
91+
content := []byte("A very small file\n")
92+
doLfs(t, &content, false)
93+
}
94+
95+
func TestGetLFSLarge(t *testing.T) {
96+
content := make([]byte, gzip.MinSize*10)
97+
for i := range content {
98+
content[i] = byte(i % 256)
99+
}
100+
doLfs(t, &content, true)
101+
}
102+
103+
func TestGetLFSGzip(t *testing.T) {
104+
b := make([]byte, gzip.MinSize*10)
105+
for i := range b {
106+
b[i] = byte(i % 256)
107+
}
108+
outputBuffer := bytes.NewBuffer([]byte{})
109+
gzippWriter := gzipp.NewWriter(outputBuffer)
110+
gzippWriter.Write(b)
111+
gzippWriter.Close()
112+
content := outputBuffer.Bytes()
113+
doLfs(t, &content, false)
114+
}
115+
116+
func TestGetLFSZip(t *testing.T) {
117+
b := make([]byte, gzip.MinSize*10)
118+
for i := range b {
119+
b[i] = byte(i % 256)
120+
}
121+
outputBuffer := bytes.NewBuffer([]byte{})
122+
zipWriter := zip.NewWriter(outputBuffer)
123+
fileWriter, err := zipWriter.Create("default")
124+
assert.NoError(t, err)
125+
fileWriter.Write(b)
126+
zipWriter.Close()
127+
content := outputBuffer.Bytes()
128+
doLfs(t, &content, false)
129+
}

integrations/sqlite.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ LFS_CONTENT_PATH = data/lfs-sqlite
3030
OFFLINE_MODE = false
3131
LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
3232
APP_DATA_PATH = integrations/gitea-integration-sqlite/data
33+
ENABLE_GZIP = true
3334

3435
[mailer]
3536
ENABLED = false

models/lfs.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,20 @@ const (
4444
func NewLFSMetaObject(m *LFSMetaObject) (*LFSMetaObject, error) {
4545
var err error
4646

47-
has, err := x.Get(m)
47+
sess := x.NewSession()
48+
defer sess.Close()
49+
if err = sess.Begin(); err != nil {
50+
return nil, err
51+
}
52+
53+
has, err := sess.Get(m)
4854
if err != nil {
4955
return nil, err
5056
}
5157

5258
if has {
5359
m.Existing = true
54-
return m, nil
55-
}
56-
57-
sess := x.NewSession()
58-
defer sess.Close()
59-
if err = sess.Begin(); err != nil {
60-
return nil, err
60+
return m, sess.Commit()
6161
}
6262

6363
if _, err = sess.Insert(m); err != nil {

0 commit comments

Comments
 (0)