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 --- plumbing/storer/object.go | 2 +- 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 + 6 files changed, 290 insertions(+), 1 deletion(-) 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 diff --git a/plumbing/storer/object.go b/plumbing/storer/object.go index 2ac9b09..98d1ec3 100644 --- a/plumbing/storer/object.go +++ b/plumbing/storer/object.go @@ -222,7 +222,7 @@ type MultiEncodedObjectIter struct { } // NewMultiEncodedObjectIter returns an object iterator for the given slice of -// objects. +// EncodedObjectIters. func NewMultiEncodedObjectIter(iters []EncodedObjectIter) EncodedObjectIter { return &MultiEncodedObjectIter{iters: iters} } 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