mirror of
https://github.com/dolthub/dolt.git
synced 2026-05-13 03:10:03 -05:00
Added Reachable and correct calculation of current roots
This commit is contained in:
+23
-12
@@ -8,10 +8,15 @@ import (
|
||||
"github.com/attic-labs/noms/types"
|
||||
)
|
||||
|
||||
type Reachable interface {
|
||||
IsSupercededFrom(candidate, root ref.Ref) bool
|
||||
}
|
||||
|
||||
type Commit struct {
|
||||
root store.RootStore
|
||||
source store.ChunkSource
|
||||
sink store.ChunkSink
|
||||
root store.RootStore
|
||||
source store.ChunkSource
|
||||
sink store.ChunkSink
|
||||
reachable Reachable
|
||||
}
|
||||
|
||||
func (c *Commit) GetRoots() (currentRoots types.Set) {
|
||||
@@ -20,9 +25,7 @@ func (c *Commit) GetRoots() (currentRoots types.Set) {
|
||||
return types.NewSet()
|
||||
}
|
||||
|
||||
rootSetValue, err := enc.ReadValue(rootRef, c.source)
|
||||
Chk.NoError(err)
|
||||
return rootSetValue.(types.Set)
|
||||
return enc.MustReadValue(rootRef, c.source).(types.Set)
|
||||
}
|
||||
|
||||
func (c *Commit) Commit(newRoots types.Set) {
|
||||
@@ -42,18 +45,26 @@ func (c *Commit) Commit(newRoots types.Set) {
|
||||
}
|
||||
|
||||
func (c *Commit) doCommit(add, remove types.Set) bool {
|
||||
oldRoot := c.root.Root()
|
||||
oldRoots := c.GetRoots()
|
||||
oldRef := oldRoots.Ref()
|
||||
if oldRoots.Len() == 0 {
|
||||
oldRef = ref.Ref{}
|
||||
|
||||
prexisting := make([]types.Value, 0)
|
||||
add.Iter(func(r types.Value) (stop bool) {
|
||||
if c.reachable.IsSupercededFrom(r.Ref(), oldRoot) {
|
||||
prexisting = append(prexisting, r)
|
||||
}
|
||||
return false
|
||||
})
|
||||
add = add.Remove(prexisting...)
|
||||
if add.Len() == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
newRoots := oldRoots.Subtract(remove)
|
||||
newRoots = newRoots.Union(add)
|
||||
newRoots := oldRoots.Subtract(remove).Union(add)
|
||||
|
||||
// TODO(rafael): This set will be orphaned if this UpdateRoot below fails
|
||||
newRef, err := enc.WriteValue(newRoots, c.sink)
|
||||
Chk.NoError(err)
|
||||
|
||||
return c.root.UpdateRoot(newRef, oldRef)
|
||||
return c.root.UpdateRoot(newRef, oldRoot)
|
||||
}
|
||||
|
||||
+46
-7
@@ -18,7 +18,12 @@ func TestCommit(t *testing.T) {
|
||||
assert.NoError(err)
|
||||
|
||||
store := store.NewFileStore(dir, "root")
|
||||
commit := &Commit{store, store, store}
|
||||
commit := &Commit{
|
||||
store,
|
||||
store,
|
||||
store,
|
||||
NewMemCacheReachable(store),
|
||||
}
|
||||
|
||||
roots := commit.GetRoots()
|
||||
assert.Equal(uint64(0), roots.Len())
|
||||
@@ -29,7 +34,6 @@ func TestCommit(t *testing.T) {
|
||||
types.NewString("value"), types.NewString("a"),
|
||||
)
|
||||
aSet := types.NewSet(a)
|
||||
enc.WriteValue(aSet, store)
|
||||
commit.Commit(aSet)
|
||||
assert.Equal(commit.GetRoots(), aSet)
|
||||
|
||||
@@ -39,7 +43,6 @@ func TestCommit(t *testing.T) {
|
||||
types.NewString("value"), types.NewString("b"),
|
||||
)
|
||||
bSet := types.NewSet(b)
|
||||
enc.WriteValue(bSet, store)
|
||||
commit.Commit(bSet)
|
||||
assert.Equal(commit.GetRoots(), bSet)
|
||||
|
||||
@@ -50,7 +53,6 @@ func TestCommit(t *testing.T) {
|
||||
types.NewString("value"), types.NewString("c"),
|
||||
)
|
||||
cSet := types.NewSet(c)
|
||||
enc.WriteValue(cSet, store)
|
||||
commit.Commit(cSet)
|
||||
bcSet := bSet.Insert(c)
|
||||
assert.Equal(commit.GetRoots(), bcSet)
|
||||
@@ -77,7 +79,6 @@ func TestCommit(t *testing.T) {
|
||||
types.NewString("value"), types.NewString("e"),
|
||||
)
|
||||
eSet := types.NewSet(e)
|
||||
enc.WriteValue(eSet, store)
|
||||
commit.Commit(eSet)
|
||||
deSet := dSet.Insert(e)
|
||||
assert.Equal(commit.GetRoots(), deSet)
|
||||
@@ -85,14 +86,52 @@ func TestCommit(t *testing.T) {
|
||||
// |a| <- |b| <-- |e| <- |f|
|
||||
// \----|c| <--/ /
|
||||
// \---|d| <-------/
|
||||
|
||||
f := types.NewMap(
|
||||
types.NewString("parents"), deSet,
|
||||
types.NewString("value"), types.NewString("f"),
|
||||
)
|
||||
|
||||
fSet := types.NewSet(f)
|
||||
enc.WriteValue(fSet, store)
|
||||
commit.Commit(fSet)
|
||||
assert.Equal(commit.GetRoots(), fSet)
|
||||
|
||||
// Attempt to recommit |b|
|
||||
commit.Commit(bSet)
|
||||
assert.Equal(commit.GetRoots(), fSet)
|
||||
|
||||
// Attempt to recommit |f|
|
||||
commit.Commit(fSet)
|
||||
assert.Equal(commit.GetRoots(), fSet)
|
||||
|
||||
// Attempt to recommit |c| while committing |g|
|
||||
// |a| <- |b| <-- |e| <- |f| <- |g|
|
||||
// \----|c| <--/ / /
|
||||
// \---|d| <-------/------/
|
||||
fdSet := fSet.Insert(d)
|
||||
g := types.NewMap(
|
||||
types.NewString("parents"), fdSet,
|
||||
types.NewString("value"), types.NewString("g"),
|
||||
)
|
||||
gSet := types.NewSet(g)
|
||||
gdSet := gSet.Insert(c)
|
||||
|
||||
commit.Commit(gdSet)
|
||||
assert.Equal(commit.GetRoots(), gSet)
|
||||
|
||||
// / -|h|
|
||||
// / |
|
||||
// |a| <- |b| <-- |e| <- |f| <- |g|
|
||||
// \----|c| <--/ / /
|
||||
// \---|d| <-------/------/
|
||||
abSet := aSet.Insert(b)
|
||||
h := types.NewMap(
|
||||
types.NewString("parents"), abSet,
|
||||
types.NewString("value"), types.NewString("h"),
|
||||
)
|
||||
hSet := types.NewSet(h)
|
||||
|
||||
commit.Commit(hSet)
|
||||
hgSet := hSet.Insert(g)
|
||||
roots = commit.GetRoots()
|
||||
assert.Equal(commit.GetRoots(), hgSet)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package commit
|
||||
|
||||
import (
|
||||
. "github.com/attic-labs/noms/dbg"
|
||||
"github.com/attic-labs/noms/enc"
|
||||
"github.com/attic-labs/noms/ref"
|
||||
"github.com/attic-labs/noms/store"
|
||||
"github.com/attic-labs/noms/types"
|
||||
)
|
||||
|
||||
// TODO(rafael):
|
||||
type memcacheReachable struct {
|
||||
source store.ChunkSource
|
||||
refs map[string]bool
|
||||
}
|
||||
|
||||
func (cache *memcacheReachable) updateFromCommitMap(commitMap types.Map) {
|
||||
refString := commitMap.Ref().String()
|
||||
if _, ok := cache.refs[refString]; ok {
|
||||
return
|
||||
}
|
||||
|
||||
parents := commitMap.Get(types.NewString("parents")).(types.Set)
|
||||
parents.Iter(func(commit types.Value) (stop bool) {
|
||||
cache.updateFromCommitMap(commit.(types.Map))
|
||||
return false
|
||||
})
|
||||
cache.refs[refString] = true
|
||||
}
|
||||
|
||||
func (cache *memcacheReachable) updateFromRootSet(rootRef ref.Ref) {
|
||||
refString := rootRef.String()
|
||||
if _, ok := cache.refs[refString]; ok {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(rafael): This is super-inefficient with eager ReadValue and no caching
|
||||
rootSet := enc.MustReadValue(rootRef, cache.source).(types.Set)
|
||||
rootSet.Iter(func(commit types.Value) (stop bool) {
|
||||
cache.updateFromCommitMap(commit.(types.Map))
|
||||
return false
|
||||
})
|
||||
cache.refs[refString] = true
|
||||
}
|
||||
|
||||
func (cache *memcacheReachable) IsSupercededFrom(candidate, root ref.Ref) bool {
|
||||
Chk.NotEqual(candidate, root)
|
||||
if (root == ref.Ref{}) {
|
||||
return false
|
||||
}
|
||||
|
||||
cache.updateFromRootSet(root)
|
||||
_, ok := cache.refs[candidate.String()]
|
||||
return ok
|
||||
}
|
||||
|
||||
func NewMemCacheReachable(source store.ChunkSource) Reachable {
|
||||
return &memcacheReachable{
|
||||
source,
|
||||
make(map[string]bool),
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
. "github.com/attic-labs/noms/dbg"
|
||||
"github.com/attic-labs/noms/ref"
|
||||
"github.com/attic-labs/noms/store"
|
||||
"github.com/attic-labs/noms/types"
|
||||
@@ -34,3 +35,9 @@ func ReadValue(ref ref.Ref, cs store.ChunkSource) (types.Value, error) {
|
||||
|
||||
return nil, fmt.Errorf("Unsupported chunk tag: %+v", prefix)
|
||||
}
|
||||
|
||||
func MustReadValue(ref ref.Ref, cs store.ChunkSource) types.Value {
|
||||
val, err := ReadValue(ref, cs)
|
||||
Chk.NoError(err)
|
||||
return val
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user