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

Commit 12dc3ef

Browse files
committed
storage: transactional, new storage with transactional capabilities
Signed-off-by: Máximo Cuadros <mcuadros@gmail.com>
1 parent a2b39f5 commit 12dc3ef

File tree

14 files changed

+675
-7
lines changed

14 files changed

+675
-7
lines changed

plumbing/storer/reference.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,6 @@ func forEachReferenceIter(iter bareReferenceIterator, cb func(*plumbing.Referenc
159159
return err
160160
}
161161
}
162-
163-
return nil
164162
}
165163

166164
// Close releases any resources used by the iterator.

storage/transactional/config.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ func (c *ConfigStorage) SetConfig(cfg *config.Config) error {
2222
return nil
2323
}
2424

25+
func (c *ConfigStorage) Config() (*config.Config, error) {
26+
if !c.set {
27+
return c.ConfigStorer.Config()
28+
}
29+
30+
return c.temporal.Config()
31+
}
32+
2533
func (c *ConfigStorage) Commit() error {
2634
if !c.set {
2735
return nil

storage/transactional/config_test.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
11
package transactional
22

33
import (
4-
"testing"
5-
64
. "gopkg.in/check.v1"
75
"gopkg.in/src-d/go-git.v4/config"
86
"gopkg.in/src-d/go-git.v4/storage/memory"
97
)
108

11-
func Test(t *testing.T) { TestingT(t) }
12-
139
var _ = Suite(&ConfigSuite{})
1410

1511
type ConfigSuite struct{}
1612

17-
func (s *ConfigSuite) TestSetConfig(c *C) {
13+
func (s *ConfigSuite) TestSetConfigBase(c *C) {
14+
cfg := config.NewConfig()
15+
cfg.Core.Worktree = "foo"
16+
17+
base := memory.NewStorage()
18+
err := base.SetConfig(cfg)
19+
c.Assert(err, IsNil)
20+
21+
temporal := memory.NewStorage()
22+
cs := NewConfigStorage(base, temporal)
23+
24+
cfg, err = cs.Config()
25+
c.Assert(err, IsNil)
26+
c.Assert(cfg.Core.Worktree, Equals, "foo")
27+
}
28+
29+
func (s *ConfigSuite) TestSetConfigTemporal(c *C) {
1830
cfg := config.NewConfig()
1931
cfg.Core.Worktree = "foo"
2032

storage/transactional/index.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package transactional
2+
3+
import (
4+
"gopkg.in/src-d/go-git.v4/plumbing/format/index"
5+
"gopkg.in/src-d/go-git.v4/plumbing/storer"
6+
)
7+
8+
type IndexStorage struct {
9+
storer.IndexStorer
10+
temporal storer.IndexStorer
11+
12+
set bool
13+
}
14+
15+
func NewIndexStorage(s, temporal storer.IndexStorer) *IndexStorage {
16+
return &IndexStorage{
17+
IndexStorer: s,
18+
temporal: temporal,
19+
}
20+
}
21+
22+
func (s *IndexStorage) SetIndex(idx *index.Index) (err error) {
23+
if err := s.temporal.SetIndex(idx); err != nil {
24+
return err
25+
}
26+
27+
s.set = true
28+
return nil
29+
}
30+
31+
func (s *IndexStorage) Index() (*index.Index, error) {
32+
if !s.set {
33+
return s.IndexStorer.Index()
34+
}
35+
36+
return s.temporal.Index()
37+
}
38+
39+
func (c *IndexStorage) Commit() error {
40+
if !c.set {
41+
return nil
42+
}
43+
44+
idx, err := c.temporal.Index()
45+
if err != nil {
46+
return err
47+
}
48+
49+
return c.IndexStorer.SetIndex(idx)
50+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package transactional
2+
3+
import (
4+
. "gopkg.in/check.v1"
5+
"gopkg.in/src-d/go-git.v4/plumbing/format/index"
6+
"gopkg.in/src-d/go-git.v4/storage/memory"
7+
)
8+
9+
var _ = Suite(&IndexSuite{})
10+
11+
type IndexSuite struct{}
12+
13+
func (s *IndexSuite) TestSetIndexBase(c *C) {
14+
idx := &index.Index{}
15+
idx.Version = 2
16+
17+
base := memory.NewStorage()
18+
err := base.SetIndex(idx)
19+
c.Assert(err, IsNil)
20+
21+
temporal := memory.NewStorage()
22+
cs := NewIndexStorage(base, temporal)
23+
24+
idx, err = cs.Index()
25+
c.Assert(err, IsNil)
26+
c.Assert(idx.Version, Equals, uint32(2))
27+
}
28+
29+
func (s *IndexSuite) TestCommit(c *C) {
30+
idx := &index.Index{}
31+
idx.Version = 2
32+
33+
base := memory.NewStorage()
34+
err := base.SetIndex(idx)
35+
c.Assert(err, IsNil)
36+
37+
temporal := memory.NewStorage()
38+
39+
idx = &index.Index{}
40+
idx.Version = 3
41+
42+
is := NewIndexStorage(base, temporal)
43+
err = is.SetIndex(idx)
44+
c.Assert(err, IsNil)
45+
46+
err = is.Commit()
47+
c.Assert(err, IsNil)
48+
49+
baseIndex, err := base.Index()
50+
c.Assert(err, IsNil)
51+
c.Assert(baseIndex.Version, Equals, uint32(3))
52+
}

storage/transactional/module.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package transactional

storage/transactional/object.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,15 @@ func (o *ObjectStorage) IterEncodedObjects(t plumbing.ObjectType) (storer.Encode
6161
temporalIter,
6262
}), nil
6363
}
64+
65+
func (o *ObjectStorage) Commit() error {
66+
iter, err := o.temporal.IterEncodedObjects(plumbing.AnyObject)
67+
if err != nil {
68+
return err
69+
}
70+
71+
return iter.ForEach(func(obj plumbing.EncodedObject) error {
72+
_, err := o.EncodedObjectStorer.SetEncodedObject(obj)
73+
return err
74+
})
75+
}

storage/transactional/object_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,37 @@ func (s *ObjectSuite) TestIterEncodedObjects(c *C) {
117117
c.Assert(hashes[0], Equals, ch)
118118
c.Assert(hashes[1], Equals, th)
119119
}
120+
121+
func (s *ObjectSuite) TestCommit(c *C) {
122+
base := memory.NewStorage()
123+
temporal := memory.NewStorage()
124+
125+
os := NewObjectStorage(base, temporal)
126+
127+
commit := base.NewEncodedObject()
128+
commit.SetType(plumbing.CommitObject)
129+
130+
_, err := os.SetEncodedObject(commit)
131+
c.Assert(err, IsNil)
132+
133+
tree := base.NewEncodedObject()
134+
tree.SetType(plumbing.TreeObject)
135+
136+
_, err = os.SetEncodedObject(tree)
137+
c.Assert(err, IsNil)
138+
139+
err = os.Commit()
140+
c.Assert(err, IsNil)
141+
142+
iter, err := base.IterEncodedObjects(plumbing.AnyObject)
143+
c.Assert(err, IsNil)
144+
145+
var hashes []plumbing.Hash
146+
err = iter.ForEach(func(obj plumbing.EncodedObject) error {
147+
hashes = append(hashes, obj.Hash())
148+
return nil
149+
})
150+
151+
c.Assert(err, IsNil)
152+
c.Assert(hashes, HasLen, 2)
153+
}

storage/transactional/reference.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package transactional
2+
3+
import (
4+
"gopkg.in/src-d/go-git.v4/plumbing"
5+
"gopkg.in/src-d/go-git.v4/plumbing/storer"
6+
"gopkg.in/src-d/go-git.v4/storage"
7+
)
8+
9+
type ReferenceStorage struct {
10+
storer.ReferenceStorer
11+
temporal storer.ReferenceStorer
12+
13+
// deleted, remaining references at this maps are going to be deleted when
14+
// commit is requested, the entries are added when RemoveReference is called
15+
// and deleted if SetReference is called.
16+
deleted map[plumbing.ReferenceName]struct{}
17+
// packRefs if true PackRefs is going to be called in the based storer when
18+
// commit is called.
19+
packRefs bool
20+
}
21+
22+
func NewReferenceStorage(s, temporal storer.ReferenceStorer) *ReferenceStorage {
23+
return &ReferenceStorage{
24+
ReferenceStorer: s,
25+
temporal: temporal,
26+
27+
deleted: make(map[plumbing.ReferenceName]struct{}, 0),
28+
}
29+
}
30+
31+
func (r *ReferenceStorage) SetReference(ref *plumbing.Reference) error {
32+
delete(r.deleted, ref.Name())
33+
return r.temporal.SetReference(ref)
34+
}
35+
36+
func (r *ReferenceStorage) CheckAndSetReference(ref, old *plumbing.Reference) error {
37+
if old == nil {
38+
return r.SetReference(ref)
39+
}
40+
41+
tmp, err := r.temporal.Reference(old.Name())
42+
if err == plumbing.ErrReferenceNotFound {
43+
tmp, err = r.ReferenceStorer.Reference(old.Name())
44+
}
45+
46+
if err != nil {
47+
return err
48+
}
49+
50+
if tmp.Hash() != old.Hash() {
51+
return storage.ErrReferenceHasChanged
52+
}
53+
54+
return r.SetReference(ref)
55+
}
56+
57+
func (r ReferenceStorage) Reference(n plumbing.ReferenceName) (*plumbing.Reference, error) {
58+
if _, deleted := r.deleted[n]; deleted {
59+
return nil, plumbing.ErrReferenceNotFound
60+
}
61+
62+
ref, err := r.temporal.Reference(n)
63+
if err == plumbing.ErrReferenceNotFound {
64+
return r.ReferenceStorer.Reference(n)
65+
}
66+
67+
return ref, err
68+
}
69+
70+
func (r ReferenceStorage) IterReferences() (storer.ReferenceIter, error) {
71+
baseIter, err := r.ReferenceStorer.IterReferences()
72+
if err != nil {
73+
return nil, err
74+
}
75+
76+
temporalIter, err := r.temporal.IterReferences()
77+
if err != nil {
78+
return nil, err
79+
}
80+
81+
return storer.NewMultiReferenceIter([]storer.ReferenceIter{
82+
baseIter,
83+
temporalIter,
84+
}), nil
85+
}
86+
87+
func (r ReferenceStorage) CountLooseRefs() (int, error) {
88+
tc, err := r.temporal.CountLooseRefs()
89+
if err != nil {
90+
return -1, err
91+
}
92+
93+
bc, err := r.ReferenceStorer.CountLooseRefs()
94+
if err != nil {
95+
return -1, err
96+
}
97+
98+
return tc + bc, nil
99+
}
100+
101+
func (r ReferenceStorage) PackRefs() error {
102+
r.packRefs = true
103+
return nil
104+
}
105+
106+
func (r ReferenceStorage) RemoveReference(n plumbing.ReferenceName) error {
107+
r.deleted[n] = struct{}{}
108+
return r.temporal.RemoveReference(n)
109+
}
110+
111+
func (r ReferenceStorage) Commit() error {
112+
for name := range r.deleted {
113+
if err := r.ReferenceStorer.RemoveReference(name); err != nil {
114+
return err
115+
}
116+
}
117+
118+
iter, err := r.temporal.IterReferences()
119+
if err != nil {
120+
return err
121+
}
122+
123+
return iter.ForEach(func(ref *plumbing.Reference) error {
124+
return r.ReferenceStorer.SetReference(ref)
125+
})
126+
}

0 commit comments

Comments
 (0)