Added Reachable and correct calculation of current roots

This commit is contained in:
Rafael Weinstein
2015-06-16 15:10:12 -07:00
parent 44fc6bbf39
commit 8b28d4fbba
4 changed files with 138 additions and 19 deletions
+23 -12
View File
@@ -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
View File
@@ -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)
}
+62
View File
@@ -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),
}
}
+7
View File
@@ -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
}