Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 2da64ea

Browse files
committed
core: ObjectStorage.Begin and TxObjectStorage
1 parent 20b74b8 commit 2da64ea

File tree

14 files changed

+180
-38
lines changed

14 files changed

+180
-38
lines changed

blame_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ func (s *BlameCommon) SetUpSuite(c *C) {
3131

3232
stream := packfile.NewStream(bytes.NewReader(data))
3333

34-
d := packfile.NewDecoder(stream)
35-
err = d.Decode(r.s.ObjectStorage())
34+
d := packfile.NewDecoder(stream, r.s.ObjectStorage())
35+
err = d.Decode()
3636
c.Assert(err, IsNil)
3737

3838
c.Assert(f.Close(), IsNil)

common_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ func unpackFixtures(c *C, fixtures ...[]packedFixture) map[string]*Repository {
123123
memStream := bytes.NewReader(data)
124124
r := packfile.NewStream(memStream)
125125

126-
d := packfile.NewDecoder(r)
127-
err = d.Decode(repos[fixture.url].s.ObjectStorage())
126+
d := packfile.NewDecoder(r, repos[fixture.url].s.ObjectStorage())
127+
err = d.Decode()
128128
c.Assert(err, IsNil, comment)
129129

130130
c.Assert(f.Close(), IsNil, comment)

core/storage.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,28 @@ var ErrStop = errors.New("stop iter")
77

88
// ObjectStorage generic storage of objects
99
type ObjectStorage interface {
10+
// NewObject returns a new Object, the real type of the object can be a
11+
// custom implementation or the defaul one, MemoryObject
1012
NewObject() Object
13+
// Set save an object into the storage, the object shuld be create with
14+
// the NewObject, method, and file if the type is not supported.
1115
Set(Object) (Hash, error)
12-
// Get an object by hash with the given ObjectType.
13-
//
14-
// Implementors should return (nil, core.ErrObjectNotFound) if an object
15-
// doesn't exist with both the given hash and object type.
16+
// Get an object by hash with the given ObjectType. Implementors should
17+
// return (nil, ErrObjectNotFound) if an object doesn't exist with both the
18+
// given hash and object type.
1619
//
1720
// Valid ObjectType values are CommitObject, BlobObject, TagObject, TreeObject
1821
// and AnyObject.
1922
//
2023
// If AnyObject is given, the object must be looked up regardless of its type.
2124
Get(ObjectType, Hash) (Object, error)
25+
// Iter returns a custom ObjectIter over all the object on the storage.
26+
//
27+
// Valid ObjectType values are CommitObject, BlobObject, TagObject, TreeObject
28+
// and AnyObject.
2229
Iter(ObjectType) (ObjectIter, error)
30+
// Begin starts a transaction.
31+
Begin() TxObjectStorage
2332
}
2433

2534
// ObjectIter is a generic closable interface for iterating over objects.
@@ -29,6 +38,14 @@ type ObjectIter interface {
2938
Close()
3039
}
3140

41+
// TxObjectStorage is an in-progress storage transaction.
42+
// A transaction must end with a call to Commit or Rollback.
43+
type TxObjectStorage interface {
44+
Set(Object) (Hash, error)
45+
Commit() error
46+
Rollback() error
47+
}
48+
3249
// ReferenceStorage generic storage of references
3350
type ReferenceStorage interface {
3451
Set(*Reference) error

examples/storage/aerospike/storage.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,26 @@ func (s *ObjectStorage) buildKey(h core.Hash, t core.ObjectType) (*driver.Key, e
131131
return driver.NewKey(s.ns, t.String(), fmt.Sprintf("%s|%s", s.url, h.String()))
132132
}
133133

134+
func (s *ObjectStorage) Begin() core.TxObjectStorage {
135+
return &TxObjectStorage{Storage: s}
136+
}
137+
138+
type TxObjectStorage struct {
139+
Storage *ObjectStorage
140+
}
141+
142+
func (tx *TxObjectStorage) Set(obj core.Object) (core.Hash, error) {
143+
return tx.Storage.Set(obj)
144+
}
145+
146+
func (tx *TxObjectStorage) Commit() error {
147+
return nil
148+
}
149+
150+
func (tx *TxObjectStorage) Rollback() error {
151+
return nil
152+
}
153+
134154
type ObjectIter struct {
135155
t core.ObjectType
136156
ch chan *driver.Record

formats/packfile/decoder.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,33 @@ type Decoder struct {
4242
}
4343

4444
// NewDecoder returns a new Decoder that reads from r.
45-
func NewDecoder(r ReadRecaller) *Decoder {
45+
func NewDecoder(r ReadRecaller, s core.ObjectStorage) *Decoder {
4646
return &Decoder{
4747
p: NewParser(r),
48+
s: s,
4849
}
4950
}
5051

5152
// Decode reads a packfile and stores it in the value pointed to by s.
52-
func (d *Decoder) Decode(s core.ObjectStorage) error {
53-
d.s = s
54-
53+
func (d *Decoder) Decode() error {
5554
count, err := d.p.ReadHeader()
5655
if err != nil {
5756
return err
5857
}
5958

60-
return d.readObjects(count)
59+
tx := d.s.Begin()
60+
if err := d.readObjects(tx, count); err != nil {
61+
if err := tx.Rollback(); err != nil {
62+
return nil
63+
}
64+
65+
return err
66+
}
67+
68+
return tx.Commit()
6169
}
6270

63-
func (d *Decoder) readObjects(count uint32) error {
71+
func (d *Decoder) readObjects(tx core.TxObjectStorage, count uint32) error {
6472
// This code has 50-80 µs of overhead per object not counting zlib inflation.
6573
// Together with zlib inflation, it's 400-410 µs for small objects.
6674
// That's 1 sec for ~2450 objects, ~4.20 MB, or ~250 ms per MB,
@@ -85,7 +93,7 @@ func (d *Decoder) readObjects(count uint32) error {
8593
return err
8694
}
8795

88-
_, err = d.s.Set(obj)
96+
_, err = tx.Set(obj)
8997
if err == io.EOF {
9098
break
9199
}

formats/packfile/decoder_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ func (s *ReaderSuite) TestReadPackfile(c *C) {
2828
data, _ := base64.StdEncoding.DecodeString(packFileWithEmptyObjects)
2929
f := bytes.NewReader(data)
3030
r := NewStream(f)
31-
d := NewDecoder(r)
32-
3331
sto := memory.NewStorage()
34-
err := d.Decode(sto.ObjectStorage())
32+
d := NewDecoder(r, sto.ObjectStorage())
33+
34+
err := d.Decode()
3535
c.Assert(err, IsNil)
3636

3737
AssertObjects(c, sto, []string{
@@ -61,10 +61,10 @@ func (s *ReaderSuite) testReadPackfileGitFixture(c *C, file string, format Forma
6161
f, err := os.Open(file)
6262
c.Assert(err, IsNil)
6363
r := NewSeekable(f)
64-
d := NewDecoder(r)
65-
6664
sto := memory.NewStorage()
67-
err = d.Decode(sto.ObjectStorage())
65+
d := NewDecoder(r, sto.ObjectStorage())
66+
67+
err = d.Decode()
6868
c.Assert(err, IsNil)
6969

7070
AssertObjects(c, sto, []string{
@@ -170,10 +170,10 @@ func readFromFile(c *C, file string, format Format) *memory.ObjectStorage {
170170
f, err := os.Open(file)
171171
c.Assert(err, IsNil)
172172
r := NewSeekable(f)
173-
d := NewDecoder(r)
174-
175173
sto := memory.NewStorage()
176-
err = d.Decode(sto.ObjectStorage())
174+
d := NewDecoder(r, sto.ObjectStorage())
175+
176+
err = d.Decode()
177177
c.Assert(err, IsNil)
178178

179179
return sto.ObjectStorage().(*memory.ObjectStorage)

references_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ func (s *ReferencesSuite) SetUpSuite(c *C) {
2727
defer f.Close()
2828
c.Assert(err, IsNil)
2929
r := packfile.NewSeekable(f)
30-
d := packfile.NewDecoder(r)
31-
err = d.Decode(s.repos[fix.url].s.ObjectStorage())
30+
d := packfile.NewDecoder(r, s.repos[fix.url].s.ObjectStorage())
31+
err = d.Decode()
3232
c.Assert(err, IsNil)
3333
}
3434
}

remote.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ func (r *Remote) buildRequest(
163163
func (r *Remote) updateObjectStorage(reader io.Reader) error {
164164
stream := packfile.NewStream(reader)
165165

166-
d := packfile.NewDecoder(stream)
167-
return d.Decode(r.s.ObjectStorage())
166+
d := packfile.NewDecoder(stream, r.s.ObjectStorage())
167+
return d.Decode()
168168
}
169169

170170
func (r *Remote) updateLocalReferenceStorage(specs []config.RefSpec, refs []*core.Reference) error {

storage/filesystem/object.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,20 @@ func buildIndexFromIdxfile(fs fs.FS, path string) (index.Index, error) {
217217

218218
return index.NewFromIdx(f)
219219
}
220+
func (o *ObjectStorage) Begin() core.TxObjectStorage {
221+
return &TxObjectStorage{}
222+
}
223+
224+
type TxObjectStorage struct{}
225+
226+
func (tx *TxObjectStorage) Set(obj core.Object) (core.Hash, error) {
227+
return core.ZeroHash, fmt.Errorf("not implemented yet")
228+
}
229+
230+
func (tx *TxObjectStorage) Commit() error {
231+
return fmt.Errorf("not implemented yet")
232+
}
233+
234+
func (tx *TxObjectStorage) Rollback() error {
235+
return fmt.Errorf("not implemented yet")
236+
}

storage/filesystem/object_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,9 @@ func memStorageFromGitDir(fs fs.FS, path string) (core.ObjectStorage, error) {
124124

125125
sto := memory.NewStorage()
126126
r := packfile.NewStream(f)
127-
d := packfile.NewDecoder(r)
127+
d := packfile.NewDecoder(r, sto.ObjectStorage())
128128

129-
err = d.Decode(sto.ObjectStorage())
129+
err = d.Decode()
130130
if err != nil {
131131
return nil, err
132132
}
@@ -267,8 +267,8 @@ func memStorageFromDirPath(fs fs.FS, path string) (core.ObjectStorage, error) {
267267
}
268268

269269
r := packfile.NewStream(f)
270-
d := packfile.NewDecoder(r)
271-
err = d.Decode(sto.ObjectStorage())
270+
d := packfile.NewDecoder(r, sto.ObjectStorage())
271+
err = d.Decode()
272272
if err != nil {
273273
return nil, err
274274
}

storage/memory/storage.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,41 @@ func flattenObjectMap(m map[core.Hash]core.Object) []core.Object {
166166
return objects
167167
}
168168

169+
func (o *ObjectStorage) Begin() core.TxObjectStorage {
170+
return &TxObjectStorage{
171+
Storage: o,
172+
Objects: make(map[core.Hash]core.Object, 0),
173+
}
174+
}
175+
176+
type TxObjectStorage struct {
177+
Storage *ObjectStorage
178+
Objects map[core.Hash]core.Object
179+
}
180+
181+
func (tx *TxObjectStorage) Set(obj core.Object) (core.Hash, error) {
182+
h := obj.Hash()
183+
tx.Objects[h] = obj
184+
185+
return h, nil
186+
}
187+
188+
func (tx *TxObjectStorage) Commit() error {
189+
for h, obj := range tx.Objects {
190+
delete(tx.Objects, h)
191+
if _, err := tx.Storage.Set(obj); err != nil {
192+
return err
193+
}
194+
}
195+
196+
return nil
197+
}
198+
199+
func (tx *TxObjectStorage) Rollback() error {
200+
tx.Objects = make(map[core.Hash]core.Object, 0)
201+
return nil
202+
}
203+
169204
type ReferenceStorage map[core.ReferenceName]*core.Reference
170205

171206
// Set stores a reference.

storage/memory/storage_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ import (
66

77
. "gopkg.in/check.v1"
88
"gopkg.in/src-d/go-git.v4/core"
9-
. "gopkg.in/src-d/go-git.v4/storage/test"
9+
"gopkg.in/src-d/go-git.v4/storage/test"
1010
)
1111

1212
func Test(t *testing.T) { TestingT(t) }
1313

1414
type StorageSuite struct {
15-
BaseStorageSuite
15+
test.BaseStorageSuite
1616
}
1717

1818
var _ = Suite(&StorageSuite{})
1919

20-
func (s *StorageSuite) SetUpSuite(c *C) {
21-
s.BaseStorageSuite = NewBaseStorageSuite(NewStorage().ObjectStorage())
20+
func (s *StorageSuite) SetUpTest(c *C) {
21+
s.BaseStorageSuite = test.NewBaseStorageSuite(NewStorage().ObjectStorage())
2222
}
2323

2424
func (s *StorageSuite) TestStorageObjectStorage(c *C) {

storage/test/storage_suite.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,48 @@ func (s *BaseStorageSuite) TestObjectStorageIter(c *C) {
114114
c.Assert(found, Equals, true, Commentf("Object of type %s not found", to.Type.String()))
115115
}
116116
}
117+
118+
func (s *BaseStorageSuite) TestTxObjectStorageSetAndCommit(c *C) {
119+
tx := s.ObjectStorage.Begin()
120+
for _, o := range s.testObjects {
121+
h, err := tx.Set(o.Object)
122+
c.Assert(err, IsNil)
123+
c.Assert(h.String(), Equals, o.Hash)
124+
}
125+
126+
iter, err := s.ObjectStorage.Iter(core.AnyObject)
127+
c.Assert(err, IsNil)
128+
_, err = iter.Next()
129+
c.Assert(err, Equals, io.EOF)
130+
131+
err = tx.Commit()
132+
c.Assert(err, IsNil)
133+
134+
iter, err = s.ObjectStorage.Iter(core.AnyObject)
135+
c.Assert(err, IsNil)
136+
137+
var count int
138+
iter.ForEach(func(o core.Object) error {
139+
count++
140+
return nil
141+
})
142+
143+
c.Assert(count, Equals, 4)
144+
}
145+
146+
func (s *BaseStorageSuite) TestTxObjectStorageSetAndRollback(c *C) {
147+
tx := s.ObjectStorage.Begin()
148+
for _, o := range s.testObjects {
149+
h, err := tx.Set(o.Object)
150+
c.Assert(err, IsNil)
151+
c.Assert(h.String(), Equals, o.Hash)
152+
}
153+
154+
err := tx.Rollback()
155+
c.Assert(err, IsNil)
156+
157+
iter, err := s.ObjectStorage.Iter(core.AnyObject)
158+
c.Assert(err, IsNil)
159+
_, err = iter.Next()
160+
c.Assert(err, Equals, io.EOF)
161+
}

tree_diff_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ func (s *DiffTreeSuite) SetUpSuite(c *C) {
4949
c.Assert(err, IsNil)
5050

5151
r := packfile.NewSeekable(f)
52-
d := packfile.NewDecoder(r)
53-
err = d.Decode(s.repos[fixRepo.url].s.ObjectStorage())
52+
d := packfile.NewDecoder(r, s.repos[fixRepo.url].s.ObjectStorage())
53+
err = d.Decode()
5454
c.Assert(err, IsNil)
5555

5656
c.Assert(f.Close(), IsNil)

0 commit comments

Comments
 (0)