From ff04a1db6fcec4ab06c65f65fff1cfbc8925ae8c Mon Sep 17 00:00:00 2001 From: Máximo Cuadros Date: Mon, 29 Oct 2018 15:43:44 +0100 Subject: storage: transactional, new storage with transactional capabilities (WIP) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Máximo Cuadros --- storage/transactional/config.go | 36 +++++++++++ storage/transactional/config_test.go | 70 +++++++++++++++++++++ storage/transactional/object.go | 63 +++++++++++++++++++ storage/transactional/object_test.go | 119 +++++++++++++++++++++++++++++++++++ storage/transactional/storage.go | 1 + 5 files changed, 289 insertions(+) create mode 100644 storage/transactional/config.go create mode 100644 storage/transactional/config_test.go create mode 100644 storage/transactional/object.go create mode 100644 storage/transactional/object_test.go create mode 100644 storage/transactional/storage.go (limited to 'storage/transactional') diff --git a/storage/transactional/config.go b/storage/transactional/config.go new file mode 100644 index 0000000..2fc6583 --- /dev/null +++ b/storage/transactional/config.go @@ -0,0 +1,36 @@ +package transactional + +import "gopkg.in/src-d/go-git.v4/config" + +type ConfigStorage struct { + config.ConfigStorer + temporal config.ConfigStorer + + set bool +} + +func NewConfigStorage(s, temporal config.ConfigStorer) *ConfigStorage { + return &ConfigStorage{ConfigStorer: s, temporal: temporal} +} + +func (c *ConfigStorage) SetConfig(cfg *config.Config) error { + if err := c.temporal.SetConfig(cfg); err != nil { + return err + } + + c.set = true + return nil +} + +func (c *ConfigStorage) Commit() error { + if !c.set { + return nil + } + + cfg, err := c.temporal.Config() + if err != nil { + return err + } + + return c.ConfigStorer.SetConfig(cfg) +} diff --git a/storage/transactional/config_test.go b/storage/transactional/config_test.go new file mode 100644 index 0000000..c178bec --- /dev/null +++ b/storage/transactional/config_test.go @@ -0,0 +1,70 @@ +package transactional + +import ( + "testing" + + . "gopkg.in/check.v1" + "gopkg.in/src-d/go-git.v4/config" + "gopkg.in/src-d/go-git.v4/storage/memory" +) + +func Test(t *testing.T) { TestingT(t) } + +var _ = Suite(&ConfigSuite{}) + +type ConfigSuite struct{} + +func (s *ConfigSuite) TestSetConfig(c *C) { + cfg := config.NewConfig() + cfg.Core.Worktree = "foo" + + base := memory.NewStorage() + err := base.SetConfig(cfg) + c.Assert(err, IsNil) + + temporal := memory.NewStorage() + + cfg = config.NewConfig() + cfg.Core.Worktree = "bar" + + cs := NewConfigStorage(base, temporal) + err = cs.SetConfig(cfg) + c.Assert(err, IsNil) + + baseCfg, err := base.Config() + c.Assert(err, IsNil) + c.Assert(baseCfg.Core.Worktree, Equals, "foo") + + temporalCfg, err := temporal.Config() + c.Assert(err, IsNil) + c.Assert(temporalCfg.Core.Worktree, Equals, "bar") + + cfg, err = cs.Config() + c.Assert(err, IsNil) + c.Assert(temporalCfg.Core.Worktree, Equals, "bar") +} + +func (s *ConfigSuite) TestCommit(c *C) { + cfg := config.NewConfig() + cfg.Core.Worktree = "foo" + + base := memory.NewStorage() + err := base.SetConfig(cfg) + c.Assert(err, IsNil) + + temporal := memory.NewStorage() + + cfg = config.NewConfig() + cfg.Core.Worktree = "bar" + + cs := NewConfigStorage(base, temporal) + err = cs.SetConfig(cfg) + c.Assert(err, IsNil) + + err = cs.Commit() + c.Assert(err, IsNil) + + baseCfg, err := base.Config() + c.Assert(err, IsNil) + c.Assert(baseCfg.Core.Worktree, Equals, "bar") +} diff --git a/storage/transactional/object.go b/storage/transactional/object.go new file mode 100644 index 0000000..2a46d3c --- /dev/null +++ b/storage/transactional/object.go @@ -0,0 +1,63 @@ +package transactional + +import ( + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/plumbing/storer" +) + +type ObjectStorage struct { + storer.EncodedObjectStorer + temporal storer.EncodedObjectStorer +} + +func NewObjectStorage(s, temporal storer.EncodedObjectStorer) *ObjectStorage { + return &ObjectStorage{EncodedObjectStorer: s, temporal: temporal} +} + +func (o *ObjectStorage) SetEncodedObject(obj plumbing.EncodedObject) (plumbing.Hash, error) { + return o.temporal.SetEncodedObject(obj) +} + +func (o *ObjectStorage) HasEncodedObject(h plumbing.Hash) error { + err := o.EncodedObjectStorer.HasEncodedObject(h) + if err == plumbing.ErrObjectNotFound { + return o.temporal.HasEncodedObject(h) + } + + return err +} + +func (o *ObjectStorage) EncodedObjectSize(h plumbing.Hash) (int64, error) { + sz, err := o.EncodedObjectStorer.EncodedObjectSize(h) + if err == plumbing.ErrObjectNotFound { + return o.temporal.EncodedObjectSize(h) + } + + return sz, err +} + +func (o *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (plumbing.EncodedObject, error) { + obj, err := o.EncodedObjectStorer.EncodedObject(t, h) + if err == plumbing.ErrObjectNotFound { + return o.temporal.EncodedObject(t, h) + } + + return obj, err +} + +func (o *ObjectStorage) IterEncodedObjects(t plumbing.ObjectType) (storer.EncodedObjectIter, error) { + baseIter, err := o.EncodedObjectStorer.IterEncodedObjects(t) + if err != nil { + return nil, err + } + + temporalIter, err := o.temporal.IterEncodedObjects(t) + if err != nil { + return nil, err + } + + return storer.NewMultiEncodedObjectIter([]storer.EncodedObjectIter{ + baseIter, + temporalIter, + }), nil +} diff --git a/storage/transactional/object_test.go b/storage/transactional/object_test.go new file mode 100644 index 0000000..ff8cd4e --- /dev/null +++ b/storage/transactional/object_test.go @@ -0,0 +1,119 @@ +package transactional + +import ( + . "gopkg.in/check.v1" + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/storage/memory" +) + +var _ = Suite(&ObjectSuite{}) + +type ObjectSuite struct{} + +func (s *ObjectSuite) TestHasEncodedObject(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + + os := NewObjectStorage(base, temporal) + + commit := base.NewEncodedObject() + commit.SetType(plumbing.CommitObject) + + ch, err := base.SetEncodedObject(commit) + c.Assert(ch.IsZero(), Equals, false) + c.Assert(err, IsNil) + + tree := base.NewEncodedObject() + tree.SetType(plumbing.TreeObject) + + th, err := os.SetEncodedObject(tree) + c.Assert(th.IsZero(), Equals, false) + c.Assert(err, IsNil) + + err = os.HasEncodedObject(th) + c.Assert(err, IsNil) + + err = os.HasEncodedObject(ch) + c.Assert(err, IsNil) + + err = base.HasEncodedObject(th) + c.Assert(err, Equals, plumbing.ErrObjectNotFound) +} + +func (s *ObjectSuite) TestEncodedObjectAndEncodedObjectSize(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + + os := NewObjectStorage(base, temporal) + + commit := base.NewEncodedObject() + commit.SetType(plumbing.CommitObject) + + ch, err := base.SetEncodedObject(commit) + c.Assert(ch.IsZero(), Equals, false) + c.Assert(err, IsNil) + + tree := base.NewEncodedObject() + tree.SetType(plumbing.TreeObject) + + th, err := os.SetEncodedObject(tree) + c.Assert(th.IsZero(), Equals, false) + c.Assert(err, IsNil) + + otree, err := os.EncodedObject(plumbing.TreeObject, th) + c.Assert(err, IsNil) + c.Assert(otree.Hash(), Equals, tree.Hash()) + + treeSz, err := os.EncodedObjectSize(th) + c.Assert(err, IsNil) + c.Assert(treeSz, Equals, int64(0)) + + ocommit, err := os.EncodedObject(plumbing.CommitObject, ch) + c.Assert(err, IsNil) + c.Assert(ocommit.Hash(), Equals, commit.Hash()) + + commitSz, err := os.EncodedObjectSize(ch) + c.Assert(err, IsNil) + c.Assert(commitSz, Equals, int64(0)) + + _, err = base.EncodedObject(plumbing.TreeObject, th) + c.Assert(err, Equals, plumbing.ErrObjectNotFound) + + _, err = base.EncodedObjectSize(th) + c.Assert(err, Equals, plumbing.ErrObjectNotFound) +} + +func (s *ObjectSuite) TestIterEncodedObjects(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + + os := NewObjectStorage(base, temporal) + + commit := base.NewEncodedObject() + commit.SetType(plumbing.CommitObject) + + ch, err := base.SetEncodedObject(commit) + c.Assert(ch.IsZero(), Equals, false) + c.Assert(err, IsNil) + + tree := base.NewEncodedObject() + tree.SetType(plumbing.TreeObject) + + th, err := os.SetEncodedObject(tree) + c.Assert(th.IsZero(), Equals, false) + c.Assert(err, IsNil) + + iter, err := os.IterEncodedObjects(plumbing.AnyObject) + c.Assert(err, IsNil) + + var hashes []plumbing.Hash + err = iter.ForEach(func(obj plumbing.EncodedObject) error { + hashes = append(hashes, obj.Hash()) + return nil + }) + + c.Assert(err, IsNil) + c.Assert(hashes, HasLen, 2) + c.Assert(hashes[0], Equals, ch) + c.Assert(hashes[1], Equals, th) +} diff --git a/storage/transactional/storage.go b/storage/transactional/storage.go new file mode 100644 index 0000000..d5f5a24 --- /dev/null +++ b/storage/transactional/storage.go @@ -0,0 +1 @@ +package transactional -- cgit From 12dc3ef13e5c783b9e304aa8b6a2f7097880ab87 Mon Sep 17 00:00:00 2001 From: Máximo Cuadros Date: Mon, 10 Dec 2018 20:18:50 +0100 Subject: storage: transactional, new storage with transactional capabilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Máximo Cuadros --- storage/transactional/config.go | 8 ++ storage/transactional/config_test.go | 22 ++++- storage/transactional/index.go | 50 ++++++++++ storage/transactional/index_test.go | 52 +++++++++++ storage/transactional/module.go | 1 + storage/transactional/object.go | 12 +++ storage/transactional/object_test.go | 34 +++++++ storage/transactional/reference.go | 126 +++++++++++++++++++++++++ storage/transactional/reference_test.go | 157 ++++++++++++++++++++++++++++++++ storage/transactional/shallow.go | 44 +++++++++ storage/transactional/shallow_test.go | 62 +++++++++++++ storage/transactional/storage.go | 60 ++++++++++++ storage/transactional/storage_test.go | 52 +++++++++++ 13 files changed, 675 insertions(+), 5 deletions(-) create mode 100644 storage/transactional/index.go create mode 100644 storage/transactional/index_test.go create mode 100644 storage/transactional/module.go create mode 100644 storage/transactional/reference.go create mode 100644 storage/transactional/reference_test.go create mode 100644 storage/transactional/shallow.go create mode 100644 storage/transactional/shallow_test.go create mode 100644 storage/transactional/storage_test.go (limited to 'storage/transactional') diff --git a/storage/transactional/config.go b/storage/transactional/config.go index 2fc6583..fec1f28 100644 --- a/storage/transactional/config.go +++ b/storage/transactional/config.go @@ -22,6 +22,14 @@ func (c *ConfigStorage) SetConfig(cfg *config.Config) error { return nil } +func (c *ConfigStorage) Config() (*config.Config, error) { + if !c.set { + return c.ConfigStorer.Config() + } + + return c.temporal.Config() +} + func (c *ConfigStorage) Commit() error { if !c.set { return nil diff --git a/storage/transactional/config_test.go b/storage/transactional/config_test.go index c178bec..5d1e019 100644 --- a/storage/transactional/config_test.go +++ b/storage/transactional/config_test.go @@ -1,20 +1,32 @@ package transactional import ( - "testing" - . "gopkg.in/check.v1" "gopkg.in/src-d/go-git.v4/config" "gopkg.in/src-d/go-git.v4/storage/memory" ) -func Test(t *testing.T) { TestingT(t) } - var _ = Suite(&ConfigSuite{}) type ConfigSuite struct{} -func (s *ConfigSuite) TestSetConfig(c *C) { +func (s *ConfigSuite) TestSetConfigBase(c *C) { + cfg := config.NewConfig() + cfg.Core.Worktree = "foo" + + base := memory.NewStorage() + err := base.SetConfig(cfg) + c.Assert(err, IsNil) + + temporal := memory.NewStorage() + cs := NewConfigStorage(base, temporal) + + cfg, err = cs.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Core.Worktree, Equals, "foo") +} + +func (s *ConfigSuite) TestSetConfigTemporal(c *C) { cfg := config.NewConfig() cfg.Core.Worktree = "foo" diff --git a/storage/transactional/index.go b/storage/transactional/index.go new file mode 100644 index 0000000..26042d6 --- /dev/null +++ b/storage/transactional/index.go @@ -0,0 +1,50 @@ +package transactional + +import ( + "gopkg.in/src-d/go-git.v4/plumbing/format/index" + "gopkg.in/src-d/go-git.v4/plumbing/storer" +) + +type IndexStorage struct { + storer.IndexStorer + temporal storer.IndexStorer + + set bool +} + +func NewIndexStorage(s, temporal storer.IndexStorer) *IndexStorage { + return &IndexStorage{ + IndexStorer: s, + temporal: temporal, + } +} + +func (s *IndexStorage) SetIndex(idx *index.Index) (err error) { + if err := s.temporal.SetIndex(idx); err != nil { + return err + } + + s.set = true + return nil +} + +func (s *IndexStorage) Index() (*index.Index, error) { + if !s.set { + return s.IndexStorer.Index() + } + + return s.temporal.Index() +} + +func (c *IndexStorage) Commit() error { + if !c.set { + return nil + } + + idx, err := c.temporal.Index() + if err != nil { + return err + } + + return c.IndexStorer.SetIndex(idx) +} diff --git a/storage/transactional/index_test.go b/storage/transactional/index_test.go new file mode 100644 index 0000000..e1c571a --- /dev/null +++ b/storage/transactional/index_test.go @@ -0,0 +1,52 @@ +package transactional + +import ( + . "gopkg.in/check.v1" + "gopkg.in/src-d/go-git.v4/plumbing/format/index" + "gopkg.in/src-d/go-git.v4/storage/memory" +) + +var _ = Suite(&IndexSuite{}) + +type IndexSuite struct{} + +func (s *IndexSuite) TestSetIndexBase(c *C) { + idx := &index.Index{} + idx.Version = 2 + + base := memory.NewStorage() + err := base.SetIndex(idx) + c.Assert(err, IsNil) + + temporal := memory.NewStorage() + cs := NewIndexStorage(base, temporal) + + idx, err = cs.Index() + c.Assert(err, IsNil) + c.Assert(idx.Version, Equals, uint32(2)) +} + +func (s *IndexSuite) TestCommit(c *C) { + idx := &index.Index{} + idx.Version = 2 + + base := memory.NewStorage() + err := base.SetIndex(idx) + c.Assert(err, IsNil) + + temporal := memory.NewStorage() + + idx = &index.Index{} + idx.Version = 3 + + is := NewIndexStorage(base, temporal) + err = is.SetIndex(idx) + c.Assert(err, IsNil) + + err = is.Commit() + c.Assert(err, IsNil) + + baseIndex, err := base.Index() + c.Assert(err, IsNil) + c.Assert(baseIndex.Version, Equals, uint32(3)) +} diff --git a/storage/transactional/module.go b/storage/transactional/module.go new file mode 100644 index 0000000..d5f5a24 --- /dev/null +++ b/storage/transactional/module.go @@ -0,0 +1 @@ +package transactional diff --git a/storage/transactional/object.go b/storage/transactional/object.go index 2a46d3c..21490b7 100644 --- a/storage/transactional/object.go +++ b/storage/transactional/object.go @@ -61,3 +61,15 @@ func (o *ObjectStorage) IterEncodedObjects(t plumbing.ObjectType) (storer.Encode temporalIter, }), nil } + +func (o *ObjectStorage) Commit() error { + iter, err := o.temporal.IterEncodedObjects(plumbing.AnyObject) + if err != nil { + return err + } + + return iter.ForEach(func(obj plumbing.EncodedObject) error { + _, err := o.EncodedObjectStorer.SetEncodedObject(obj) + return err + }) +} diff --git a/storage/transactional/object_test.go b/storage/transactional/object_test.go index ff8cd4e..10b6318 100644 --- a/storage/transactional/object_test.go +++ b/storage/transactional/object_test.go @@ -117,3 +117,37 @@ func (s *ObjectSuite) TestIterEncodedObjects(c *C) { c.Assert(hashes[0], Equals, ch) c.Assert(hashes[1], Equals, th) } + +func (s *ObjectSuite) TestCommit(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + + os := NewObjectStorage(base, temporal) + + commit := base.NewEncodedObject() + commit.SetType(plumbing.CommitObject) + + _, err := os.SetEncodedObject(commit) + c.Assert(err, IsNil) + + tree := base.NewEncodedObject() + tree.SetType(plumbing.TreeObject) + + _, err = os.SetEncodedObject(tree) + c.Assert(err, IsNil) + + err = os.Commit() + c.Assert(err, IsNil) + + iter, err := base.IterEncodedObjects(plumbing.AnyObject) + c.Assert(err, IsNil) + + var hashes []plumbing.Hash + err = iter.ForEach(func(obj plumbing.EncodedObject) error { + hashes = append(hashes, obj.Hash()) + return nil + }) + + c.Assert(err, IsNil) + c.Assert(hashes, HasLen, 2) +} diff --git a/storage/transactional/reference.go b/storage/transactional/reference.go new file mode 100644 index 0000000..2efefd2 --- /dev/null +++ b/storage/transactional/reference.go @@ -0,0 +1,126 @@ +package transactional + +import ( + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/plumbing/storer" + "gopkg.in/src-d/go-git.v4/storage" +) + +type ReferenceStorage struct { + storer.ReferenceStorer + temporal storer.ReferenceStorer + + // deleted, remaining references at this maps are going to be deleted when + // commit is requested, the entries are added when RemoveReference is called + // and deleted if SetReference is called. + deleted map[plumbing.ReferenceName]struct{} + // packRefs if true PackRefs is going to be called in the based storer when + // commit is called. + packRefs bool +} + +func NewReferenceStorage(s, temporal storer.ReferenceStorer) *ReferenceStorage { + return &ReferenceStorage{ + ReferenceStorer: s, + temporal: temporal, + + deleted: make(map[plumbing.ReferenceName]struct{}, 0), + } +} + +func (r *ReferenceStorage) SetReference(ref *plumbing.Reference) error { + delete(r.deleted, ref.Name()) + return r.temporal.SetReference(ref) +} + +func (r *ReferenceStorage) CheckAndSetReference(ref, old *plumbing.Reference) error { + if old == nil { + return r.SetReference(ref) + } + + tmp, err := r.temporal.Reference(old.Name()) + if err == plumbing.ErrReferenceNotFound { + tmp, err = r.ReferenceStorer.Reference(old.Name()) + } + + if err != nil { + return err + } + + if tmp.Hash() != old.Hash() { + return storage.ErrReferenceHasChanged + } + + return r.SetReference(ref) +} + +func (r ReferenceStorage) Reference(n plumbing.ReferenceName) (*plumbing.Reference, error) { + if _, deleted := r.deleted[n]; deleted { + return nil, plumbing.ErrReferenceNotFound + } + + ref, err := r.temporal.Reference(n) + if err == plumbing.ErrReferenceNotFound { + return r.ReferenceStorer.Reference(n) + } + + return ref, err +} + +func (r ReferenceStorage) IterReferences() (storer.ReferenceIter, error) { + baseIter, err := r.ReferenceStorer.IterReferences() + if err != nil { + return nil, err + } + + temporalIter, err := r.temporal.IterReferences() + if err != nil { + return nil, err + } + + return storer.NewMultiReferenceIter([]storer.ReferenceIter{ + baseIter, + temporalIter, + }), nil +} + +func (r ReferenceStorage) CountLooseRefs() (int, error) { + tc, err := r.temporal.CountLooseRefs() + if err != nil { + return -1, err + } + + bc, err := r.ReferenceStorer.CountLooseRefs() + if err != nil { + return -1, err + } + + return tc + bc, nil +} + +func (r ReferenceStorage) PackRefs() error { + r.packRefs = true + return nil +} + +func (r ReferenceStorage) RemoveReference(n plumbing.ReferenceName) error { + r.deleted[n] = struct{}{} + return r.temporal.RemoveReference(n) +} + +func (r ReferenceStorage) Commit() error { + for name := range r.deleted { + if err := r.ReferenceStorer.RemoveReference(name); err != nil { + return err + } + } + + iter, err := r.temporal.IterReferences() + if err != nil { + return err + } + + return iter.ForEach(func(ref *plumbing.Reference) error { + return r.ReferenceStorer.SetReference(ref) + }) +} diff --git a/storage/transactional/reference_test.go b/storage/transactional/reference_test.go new file mode 100644 index 0000000..5793549 --- /dev/null +++ b/storage/transactional/reference_test.go @@ -0,0 +1,157 @@ +package transactional + +import ( + . "gopkg.in/check.v1" + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/storage/memory" +) + +var _ = Suite(&ReferenceSuite{}) + +type ReferenceSuite struct{} + +func (s *ReferenceSuite) TestReference(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + + rs := NewReferenceStorage(base, temporal) + + refA := plumbing.NewReferenceFromStrings("refs/a", "bc9968d75e48de59f0870ffb71f5e160bbbdcf52") + refB := plumbing.NewReferenceFromStrings("refs/b", "bc9968d75e48de59f0870ffb71f5e160bbbdcf52") + + err := base.SetReference(refA) + c.Assert(err, IsNil) + + err = rs.SetReference(refB) + c.Assert(err, IsNil) + + _, err = rs.Reference("refs/a") + c.Assert(err, IsNil) + + _, err = rs.Reference("refs/b") + c.Assert(err, IsNil) + + _, err = base.Reference("refs/b") + c.Assert(err, Equals, plumbing.ErrReferenceNotFound) +} + +func (s *ReferenceSuite) TestRemoveReferenceTemporal(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + + ref := plumbing.NewReferenceFromStrings("refs/a", "bc9968d75e48de59f0870ffb71f5e160bbbdcf52") + + rs := NewReferenceStorage(base, temporal) + err := rs.SetReference(ref) + c.Assert(err, IsNil) + + err = rs.RemoveReference("refs/a") + c.Assert(err, IsNil) + + _, err = rs.Reference("refs/a") + c.Assert(err, Equals, plumbing.ErrReferenceNotFound) +} + +func (s *ReferenceSuite) TestRemoveReferenceBase(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + + ref := plumbing.NewReferenceFromStrings("refs/a", "bc9968d75e48de59f0870ffb71f5e160bbbdcf52") + + rs := NewReferenceStorage(base, temporal) + err := base.SetReference(ref) + c.Assert(err, IsNil) + + err = rs.RemoveReference("refs/a") + c.Assert(err, IsNil) + + _, err = rs.Reference("refs/a") + c.Assert(err, Equals, plumbing.ErrReferenceNotFound) +} + +func (s *ReferenceSuite) TestCheckAndSetReferenceInBase(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + rs := NewReferenceStorage(base, temporal) + + err := base.SetReference( + plumbing.NewReferenceFromStrings("foo", "482e0eada5de4039e6f216b45b3c9b683b83bfa"), + ) + c.Assert(err, IsNil) + + err = rs.CheckAndSetReference( + plumbing.NewReferenceFromStrings("foo", "bc9968d75e48de59f0870ffb71f5e160bbbdcf52"), + plumbing.NewReferenceFromStrings("foo", "482e0eada5de4039e6f216b45b3c9b683b83bfa"), + ) + c.Assert(err, IsNil) + + e, err := rs.Reference(plumbing.ReferenceName("foo")) + c.Assert(err, IsNil) + c.Assert(e.Hash().String(), Equals, "bc9968d75e48de59f0870ffb71f5e160bbbdcf52") +} + +func (s *ReferenceSuite) TestCommit(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + + refA := plumbing.NewReferenceFromStrings("refs/a", "bc9968d75e48de59f0870ffb71f5e160bbbdcf52") + refB := plumbing.NewReferenceFromStrings("refs/b", "b66c08ba28aa1f81eb06a1127aa3936ff77e5e2c") + refC := plumbing.NewReferenceFromStrings("refs/c", "c3f4688a08fd86f1bf8e055724c84b7a40a09733") + + rs := NewReferenceStorage(base, temporal) + c.Assert(rs.SetReference(refA), IsNil) + c.Assert(rs.SetReference(refB), IsNil) + c.Assert(rs.SetReference(refC), IsNil) + + err := rs.Commit() + c.Assert(err, IsNil) + + iter, err := base.IterReferences() + c.Assert(err, IsNil) + + var count int + iter.ForEach(func(ref *plumbing.Reference) error { + count++ + return nil + }) + + c.Assert(count, Equals, 3) +} + +func (s *ReferenceSuite) TestCommitDelete(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + + refA := plumbing.NewReferenceFromStrings("refs/a", "bc9968d75e48de59f0870ffb71f5e160bbbdcf52") + refB := plumbing.NewReferenceFromStrings("refs/b", "b66c08ba28aa1f81eb06a1127aa3936ff77e5e2c") + refC := plumbing.NewReferenceFromStrings("refs/c", "c3f4688a08fd86f1bf8e055724c84b7a40a09733") + + rs := NewReferenceStorage(base, temporal) + c.Assert(base.SetReference(refA), IsNil) + c.Assert(base.SetReference(refB), IsNil) + c.Assert(base.SetReference(refC), IsNil) + + c.Assert(rs.RemoveReference(refA.Name()), IsNil) + c.Assert(rs.RemoveReference(refB.Name()), IsNil) + c.Assert(rs.RemoveReference(refC.Name()), IsNil) + c.Assert(rs.SetReference(refC), IsNil) + + err := rs.Commit() + c.Assert(err, IsNil) + + iter, err := base.IterReferences() + c.Assert(err, IsNil) + + var count int + iter.ForEach(func(ref *plumbing.Reference) error { + count++ + return nil + }) + + c.Assert(count, Equals, 1) + + ref, err := rs.Reference(refC.Name()) + c.Assert(err, IsNil) + c.Assert(ref.Hash().String(), Equals, "c3f4688a08fd86f1bf8e055724c84b7a40a09733") + +} diff --git a/storage/transactional/shallow.go b/storage/transactional/shallow.go new file mode 100644 index 0000000..07663d4 --- /dev/null +++ b/storage/transactional/shallow.go @@ -0,0 +1,44 @@ +package transactional + +import ( + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/plumbing/storer" +) + +type ShallowStorage struct { + storer.ShallowStorer + temporal storer.ShallowStorer +} + +func NewShallowStorage(s, temporal storer.ShallowStorer) *ShallowStorage { + return &ShallowStorage{ + ShallowStorer: s, + temporal: temporal, + } +} + +func (s *ShallowStorage) SetShallow(commits []plumbing.Hash) error { + return s.temporal.SetShallow(commits) +} + +func (s *ShallowStorage) Shallow() ([]plumbing.Hash, error) { + shallow, err := s.temporal.Shallow() + if err != nil { + return nil, err + } + + if len(shallow) != 0 { + return shallow, nil + } + + return s.ShallowStorer.Shallow() +} + +func (s *ShallowStorage) Commit() error { + commits, err := s.temporal.Shallow() + if err != nil || len(commits) == 0 { + return err + } + + return s.ShallowStorer.SetShallow(commits) +} diff --git a/storage/transactional/shallow_test.go b/storage/transactional/shallow_test.go new file mode 100644 index 0000000..5141782 --- /dev/null +++ b/storage/transactional/shallow_test.go @@ -0,0 +1,62 @@ +package transactional + +import ( + . "gopkg.in/check.v1" + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/storage/memory" +) + +var _ = Suite(&ShallowSuite{}) + +type ShallowSuite struct{} + +func (s *ShallowSuite) TestShallow(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + + rs := NewShallowStorage(base, temporal) + + commitA := plumbing.NewHash("bc9968d75e48de59f0870ffb71f5e160bbbdcf52") + commitB := plumbing.NewHash("aa9968d75e48de59f0870ffb71f5e160bbbdcf52") + + err := base.SetShallow([]plumbing.Hash{commitA}) + c.Assert(err, IsNil) + + err = rs.SetShallow([]plumbing.Hash{commitB}) + c.Assert(err, IsNil) + + commits, err := rs.Shallow() + c.Assert(err, IsNil) + c.Assert(commits, HasLen, 1) + c.Assert(commits[0], Equals, commitB) + + commits, err = base.Shallow() + c.Assert(err, IsNil) + c.Assert(commits, HasLen, 1) + c.Assert(commits[0], Equals, commitA) +} + +func (s *ShallowSuite) TestCommit(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + + rs := NewShallowStorage(base, temporal) + + commitA := plumbing.NewHash("bc9968d75e48de59f0870ffb71f5e160bbbdcf52") + commitB := plumbing.NewHash("aa9968d75e48de59f0870ffb71f5e160bbbdcf52") + + c.Assert(base.SetShallow([]plumbing.Hash{commitA}), IsNil) + c.Assert(rs.SetShallow([]plumbing.Hash{commitB}), IsNil) + + c.Assert(rs.Commit(), IsNil) + + commits, err := rs.Shallow() + c.Assert(err, IsNil) + c.Assert(commits, HasLen, 1) + c.Assert(commits[0], Equals, commitB) + + commits, err = base.Shallow() + c.Assert(err, IsNil) + c.Assert(commits, HasLen, 1) + c.Assert(commits[0], Equals, commitB) +} diff --git a/storage/transactional/storage.go b/storage/transactional/storage.go index d5f5a24..6611a43 100644 --- a/storage/transactional/storage.go +++ b/storage/transactional/storage.go @@ -1 +1,61 @@ package transactional + +import ( + "gopkg.in/src-d/go-git.v4/storage" +) + +// Storage is an implementation of git.Storer that stores data on disk in the +// standard git format (this is, the .git directory). Zero values of this type +// are not safe to use, see the NewStorage function below. +type Storage struct { + s, temporal storage.Storer + + *ObjectStorage + *ReferenceStorage + *IndexStorage + *ShallowStorage + *ConfigStorage +} + +func NewStorage(s, temporal storage.Storer) *Storage { + return &Storage{ + s: s, + temporal: temporal, + + ObjectStorage: NewObjectStorage(s, temporal), + ReferenceStorage: NewReferenceStorage(s, temporal), + IndexStorage: NewIndexStorage(s, temporal), + ShallowStorage: NewShallowStorage(s, temporal), + ConfigStorage: NewConfigStorage(s, temporal), + } +} + +func (s *Storage) Module(name string) (storage.Storer, error) { + base, err := s.s.Module(name) + if err != nil { + return nil, err + } + + temporal, err := s.temporal.Module(name) + if err != nil { + return nil, err + } + + return NewStorage(base, temporal), nil +} + +func (s *Storage) Commit() error { + for _, c := range []interface{ Commit() error }{ + s.ObjectStorage, + s.ReferenceStorage, + s.IndexStorage, + s.ShallowStorage, + s.ConfigStorage, + } { + if err := c.Commit(); err != nil { + return err + } + } + + return nil +} diff --git a/storage/transactional/storage_test.go b/storage/transactional/storage_test.go new file mode 100644 index 0000000..6aaea0d --- /dev/null +++ b/storage/transactional/storage_test.go @@ -0,0 +1,52 @@ +package transactional + +import ( + "testing" + + . "gopkg.in/check.v1" + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/storage/memory" + "gopkg.in/src-d/go-git.v4/storage/test" +) + +func Test(t *testing.T) { TestingT(t) } + +type StorageSuite struct { + test.BaseStorageSuite +} + +var _ = Suite(&StorageSuite{}) + +func (s *StorageSuite) SetUpTest(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + + s.BaseStorageSuite = test.NewBaseStorageSuite(NewStorage(base, temporal)) + s.BaseStorageSuite.SetUpTest(c) +} + +func (s *StorageSuite) TestCommit(c *C) { + base := memory.NewStorage() + temporal := memory.NewStorage() + st := NewStorage(base, temporal) + + commit := base.NewEncodedObject() + commit.SetType(plumbing.CommitObject) + + _, err := st.SetEncodedObject(commit) + c.Assert(err, IsNil) + + ref := plumbing.NewHashReference("refs/a", commit.Hash()) + c.Assert(st.SetReference(ref), IsNil) + + err = st.Commit() + c.Assert(err, IsNil) + + ref, err = base.Reference(ref.Name()) + c.Assert(err, IsNil) + c.Assert(ref.Hash(), Equals, commit.Hash()) + + obj, err := base.EncodedObject(plumbing.AnyObject, commit.Hash()) + c.Assert(err, IsNil) + c.Assert(obj.Hash(), Equals, commit.Hash()) +} -- cgit From 96317743391ac87aeb07d292469e212671628437 Mon Sep 17 00:00:00 2001 From: Máximo Cuadros Date: Sat, 2 Feb 2019 10:14:24 +0100 Subject: storage: transactional, package documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Máximo Cuadros --- storage/transactional/config.go | 6 ++++++ storage/transactional/doc.go | 7 +++++++ storage/transactional/index.go | 14 ++++++++++---- storage/transactional/module.go | 1 - storage/transactional/object.go | 13 +++++++++++-- storage/transactional/reference.go | 16 ++++++++++++++-- storage/transactional/shallow.go | 11 +++++++++-- storage/transactional/storage.go | 28 ++++++++++++++++++---------- 8 files changed, 75 insertions(+), 21 deletions(-) create mode 100644 storage/transactional/doc.go delete mode 100644 storage/transactional/module.go (limited to 'storage/transactional') diff --git a/storage/transactional/config.go b/storage/transactional/config.go index fec1f28..4d8efe1 100644 --- a/storage/transactional/config.go +++ b/storage/transactional/config.go @@ -2,6 +2,7 @@ package transactional import "gopkg.in/src-d/go-git.v4/config" +// ConfigStorage implements the storer.ConfigStorage for the transactional package. type ConfigStorage struct { config.ConfigStorer temporal config.ConfigStorer @@ -9,10 +10,13 @@ type ConfigStorage struct { set bool } +// NewConfigStorage returns a new ConfigStorer based on a base storer and a +// temporal storer. func NewConfigStorage(s, temporal config.ConfigStorer) *ConfigStorage { return &ConfigStorage{ConfigStorer: s, temporal: temporal} } +// SetConfig honors the storer.ConfigStorer interface. func (c *ConfigStorage) SetConfig(cfg *config.Config) error { if err := c.temporal.SetConfig(cfg); err != nil { return err @@ -22,6 +26,7 @@ func (c *ConfigStorage) SetConfig(cfg *config.Config) error { return nil } +// Config honors the storer.ConfigStorer interface. func (c *ConfigStorage) Config() (*config.Config, error) { if !c.set { return c.ConfigStorer.Config() @@ -30,6 +35,7 @@ func (c *ConfigStorage) Config() (*config.Config, error) { return c.temporal.Config() } +// Commit it copies the config from the temporal storage into the base storage. func (c *ConfigStorage) Commit() error { if !c.set { return nil diff --git a/storage/transactional/doc.go b/storage/transactional/doc.go new file mode 100644 index 0000000..3a68f5f --- /dev/null +++ b/storage/transactional/doc.go @@ -0,0 +1,7 @@ +// Package transactional is a transactional implementation of git.Storer, it +// demux the write and read operation of two separate storers, allowing to merge +// content calling Storage.Commit. +// +// The API and functionality of this package are considered EXPERIMENTAL and is +// not considered stable nor production ready. +package transactional diff --git a/storage/transactional/index.go b/storage/transactional/index.go index 26042d6..84e0e2f 100644 --- a/storage/transactional/index.go +++ b/storage/transactional/index.go @@ -5,6 +5,7 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/storer" ) +// IndexStorage implements the storer.IndexStorage for the transactional package. type IndexStorage struct { storer.IndexStorer temporal storer.IndexStorer @@ -12,6 +13,8 @@ type IndexStorage struct { set bool } +// NewIndexStorage returns a new IndexStorer based on a base storer and a +// temporal storer. func NewIndexStorage(s, temporal storer.IndexStorer) *IndexStorage { return &IndexStorage{ IndexStorer: s, @@ -19,6 +22,7 @@ func NewIndexStorage(s, temporal storer.IndexStorer) *IndexStorage { } } +// SetIndex honors the storer.IndexStorer interface. func (s *IndexStorage) SetIndex(idx *index.Index) (err error) { if err := s.temporal.SetIndex(idx); err != nil { return err @@ -28,6 +32,7 @@ func (s *IndexStorage) SetIndex(idx *index.Index) (err error) { return nil } +// Index honors the storer.IndexStorer interface. func (s *IndexStorage) Index() (*index.Index, error) { if !s.set { return s.IndexStorer.Index() @@ -36,15 +41,16 @@ func (s *IndexStorage) Index() (*index.Index, error) { return s.temporal.Index() } -func (c *IndexStorage) Commit() error { - if !c.set { +// Commit it copies the index from the temporal storage into the base storage. +func (s *IndexStorage) Commit() error { + if !s.set { return nil } - idx, err := c.temporal.Index() + idx, err := s.temporal.Index() if err != nil { return err } - return c.IndexStorer.SetIndex(idx) + return s.IndexStorer.SetIndex(idx) } diff --git a/storage/transactional/module.go b/storage/transactional/module.go deleted file mode 100644 index d5f5a24..0000000 --- a/storage/transactional/module.go +++ /dev/null @@ -1 +0,0 @@ -package transactional diff --git a/storage/transactional/object.go b/storage/transactional/object.go index 21490b7..beb63d6 100644 --- a/storage/transactional/object.go +++ b/storage/transactional/object.go @@ -5,19 +5,24 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/storer" ) +// ObjectStorage implements the storer.EncodedObjectStorer for the transactional package. type ObjectStorage struct { storer.EncodedObjectStorer temporal storer.EncodedObjectStorer } -func NewObjectStorage(s, temporal storer.EncodedObjectStorer) *ObjectStorage { - return &ObjectStorage{EncodedObjectStorer: s, temporal: temporal} +// NewObjectStorage returns a new EncodedObjectStorer based on a base storer and +// a temporal storer. +func NewObjectStorage(base, temporal storer.EncodedObjectStorer) *ObjectStorage { + return &ObjectStorage{EncodedObjectStorer: base, temporal: temporal} } +// SetEncodedObject honors the storer.EncodedObjectStorer interface. func (o *ObjectStorage) SetEncodedObject(obj plumbing.EncodedObject) (plumbing.Hash, error) { return o.temporal.SetEncodedObject(obj) } +// HasEncodedObject honors the storer.EncodedObjectStorer interface. func (o *ObjectStorage) HasEncodedObject(h plumbing.Hash) error { err := o.EncodedObjectStorer.HasEncodedObject(h) if err == plumbing.ErrObjectNotFound { @@ -27,6 +32,7 @@ func (o *ObjectStorage) HasEncodedObject(h plumbing.Hash) error { return err } +// EncodedObjectSize honors the storer.EncodedObjectStorer interface. func (o *ObjectStorage) EncodedObjectSize(h plumbing.Hash) (int64, error) { sz, err := o.EncodedObjectStorer.EncodedObjectSize(h) if err == plumbing.ErrObjectNotFound { @@ -36,6 +42,7 @@ func (o *ObjectStorage) EncodedObjectSize(h plumbing.Hash) (int64, error) { return sz, err } +// EncodedObject honors the storer.EncodedObjectStorer interface. func (o *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (plumbing.EncodedObject, error) { obj, err := o.EncodedObjectStorer.EncodedObject(t, h) if err == plumbing.ErrObjectNotFound { @@ -45,6 +52,7 @@ func (o *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (p return obj, err } +// IterEncodedObjects honors the storer.EncodedObjectStorer interface. func (o *ObjectStorage) IterEncodedObjects(t plumbing.ObjectType) (storer.EncodedObjectIter, error) { baseIter, err := o.EncodedObjectStorer.IterEncodedObjects(t) if err != nil { @@ -62,6 +70,7 @@ func (o *ObjectStorage) IterEncodedObjects(t plumbing.ObjectType) (storer.Encode }), nil } +// Commit it copies the objects of the temporal storage into the base storage. func (o *ObjectStorage) Commit() error { iter, err := o.temporal.IterEncodedObjects(plumbing.AnyObject) if err != nil { diff --git a/storage/transactional/reference.go b/storage/transactional/reference.go index 2efefd2..a7be532 100644 --- a/storage/transactional/reference.go +++ b/storage/transactional/reference.go @@ -6,6 +6,7 @@ import ( "gopkg.in/src-d/go-git.v4/storage" ) +// ReferenceStorage implements the storer.ReferenceStorage for the transactional package. type ReferenceStorage struct { storer.ReferenceStorer temporal storer.ReferenceStorer @@ -19,20 +20,24 @@ type ReferenceStorage struct { packRefs bool } -func NewReferenceStorage(s, temporal storer.ReferenceStorer) *ReferenceStorage { +// NewReferenceStorage returns a new ReferenceStorer based on a base storer and +// a temporal storer. +func NewReferenceStorage(base, temporal storer.ReferenceStorer) *ReferenceStorage { return &ReferenceStorage{ - ReferenceStorer: s, + ReferenceStorer: base, temporal: temporal, deleted: make(map[plumbing.ReferenceName]struct{}, 0), } } +// SetReference honors the storer.ReferenceStorer interface. func (r *ReferenceStorage) SetReference(ref *plumbing.Reference) error { delete(r.deleted, ref.Name()) return r.temporal.SetReference(ref) } +// SetReference honors the storer.ReferenceStorer interface. func (r *ReferenceStorage) CheckAndSetReference(ref, old *plumbing.Reference) error { if old == nil { return r.SetReference(ref) @@ -54,6 +59,7 @@ func (r *ReferenceStorage) CheckAndSetReference(ref, old *plumbing.Reference) er return r.SetReference(ref) } +// Reference honors the storer.ReferenceStorer interface. func (r ReferenceStorage) Reference(n plumbing.ReferenceName) (*plumbing.Reference, error) { if _, deleted := r.deleted[n]; deleted { return nil, plumbing.ErrReferenceNotFound @@ -67,6 +73,7 @@ func (r ReferenceStorage) Reference(n plumbing.ReferenceName) (*plumbing.Referen return ref, err } +// IterReferences honors the storer.ReferenceStorer interface. func (r ReferenceStorage) IterReferences() (storer.ReferenceIter, error) { baseIter, err := r.ReferenceStorer.IterReferences() if err != nil { @@ -84,6 +91,7 @@ func (r ReferenceStorage) IterReferences() (storer.ReferenceIter, error) { }), nil } +// CountLooseRefs honors the storer.ReferenceStorer interface. func (r ReferenceStorage) CountLooseRefs() (int, error) { tc, err := r.temporal.CountLooseRefs() if err != nil { @@ -98,16 +106,20 @@ func (r ReferenceStorage) CountLooseRefs() (int, error) { return tc + bc, nil } +// PackRefs honors the storer.ReferenceStorer interface. func (r ReferenceStorage) PackRefs() error { r.packRefs = true return nil } +// RemoveReference honors the storer.ReferenceStorer interface. func (r ReferenceStorage) RemoveReference(n plumbing.ReferenceName) error { r.deleted[n] = struct{}{} return r.temporal.RemoveReference(n) } +// Commit it copies the reference information of the temporal storage into the +// base storage. func (r ReferenceStorage) Commit() error { for name := range r.deleted { if err := r.ReferenceStorer.RemoveReference(name); err != nil { diff --git a/storage/transactional/shallow.go b/storage/transactional/shallow.go index 07663d4..bedc325 100644 --- a/storage/transactional/shallow.go +++ b/storage/transactional/shallow.go @@ -5,22 +5,27 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/storer" ) +// ShallowStorage implements the storer.ShallowStorer for the transactional package. type ShallowStorage struct { storer.ShallowStorer temporal storer.ShallowStorer } -func NewShallowStorage(s, temporal storer.ShallowStorer) *ShallowStorage { +// NewShallowStorage returns a new ShallowStorage based on a base storer and +// a temporal storer. +func NewShallowStorage(base, temporal storer.ShallowStorer) *ShallowStorage { return &ShallowStorage{ - ShallowStorer: s, + ShallowStorer: base, temporal: temporal, } } +// SetShallow honors the storer.ShallowStorer interface. func (s *ShallowStorage) SetShallow(commits []plumbing.Hash) error { return s.temporal.SetShallow(commits) } +// Shallow honors the storer.ShallowStorer interface. func (s *ShallowStorage) Shallow() ([]plumbing.Hash, error) { shallow, err := s.temporal.Shallow() if err != nil { @@ -34,6 +39,8 @@ func (s *ShallowStorage) Shallow() ([]plumbing.Hash, error) { return s.ShallowStorer.Shallow() } +// Commit it copies the shallow information of the temporal storage into the +// base storage. func (s *ShallowStorage) Commit() error { commits, err := s.temporal.Shallow() if err != nil || len(commits) == 0 { diff --git a/storage/transactional/storage.go b/storage/transactional/storage.go index 6611a43..fbb3d35 100644 --- a/storage/transactional/storage.go +++ b/storage/transactional/storage.go @@ -4,9 +4,12 @@ import ( "gopkg.in/src-d/go-git.v4/storage" ) -// Storage is an implementation of git.Storer that stores data on disk in the -// standard git format (this is, the .git directory). Zero values of this type -// are not safe to use, see the NewStorage function below. +// Storage is a transactional implementation of git.Storer, it demux the write +// and read operation of two separate storers, allowing to merge content calling +// Storage.Commit. +// +// The API and functionality of this package are considered EXPERIMENTAL and is +// not considered stable nor production ready. type Storage struct { s, temporal storage.Storer @@ -17,19 +20,23 @@ type Storage struct { *ConfigStorage } -func NewStorage(s, temporal storage.Storer) *Storage { +// NewStorage returns a new Storage based on two repositories, base is the base +// repository where the read operations are read and temportal is were all +// the write operations are stored. +func NewStorage(base, temporal storage.Storer) *Storage { return &Storage{ - s: s, + s: base, temporal: temporal, - ObjectStorage: NewObjectStorage(s, temporal), - ReferenceStorage: NewReferenceStorage(s, temporal), - IndexStorage: NewIndexStorage(s, temporal), - ShallowStorage: NewShallowStorage(s, temporal), - ConfigStorage: NewConfigStorage(s, temporal), + ObjectStorage: NewObjectStorage(base, temporal), + ReferenceStorage: NewReferenceStorage(base, temporal), + IndexStorage: NewIndexStorage(base, temporal), + ShallowStorage: NewShallowStorage(base, temporal), + ConfigStorage: NewConfigStorage(base, temporal), } } +// Module it honors the storage.ModuleStorer interface. func (s *Storage) Module(name string) (storage.Storer, error) { base, err := s.s.Module(name) if err != nil { @@ -44,6 +51,7 @@ func (s *Storage) Module(name string) (storage.Storer, error) { return NewStorage(base, temporal), nil } +// Commit it copies the content of the temporal storage into the base storage. func (s *Storage) Commit() error { for _, c := range []interface{ Commit() error }{ s.ObjectStorage, -- cgit