Go: change Datastore/Dataset Commit to use Ref<Commit> for parents

The goal is to remove places where we construct a types.Ref from a
ref.Ref, so that we can attach a height to it later. This should also
make it unnecessary to read in the Commit values at all (which is the
case in the JS SDK) but commit validation prevents that for now.
This commit is contained in:
Benjamin Kalman
2016-05-02 10:25:03 -07:00
parent 8cc0c35829
commit d1484690ff
4 changed files with 42 additions and 11 deletions
+6
View File
@@ -17,9 +17,15 @@ type DataStore interface {
// MaybeHead returns the current Head Commit of this Datastore, which contains the current root of the DataStore's value tree, if available. If not, it returns a new Commit and 'false'.
MaybeHead(datasetID string) (types.Struct, bool)
// MaybeHeadRef returns the types.Ref of the Head Commit of this Datastore, and true, if available. If not, it returns an invalid types.Ref and false.
MaybeHeadRef(datasetID string) (types.Ref, bool)
// Head returns the current head Commit, which contains the current root of the DataStore's value tree.
Head(datasetID string) types.Struct
// HeadRef returns the ref of the current head Commit. See Head(datasetID).
HeadRef(datasetID string) types.Ref
// Datasets returns the root of the datastore which is a MapOfStringToRefOfCommit where string is a datasetID.
Datasets() types.Map
+17 -5
View File
@@ -29,18 +29,31 @@ func newDataStoreCommon(bs types.BatchStore, rt chunks.RootTracker) dataStoreCom
}
func (ds *dataStoreCommon) MaybeHead(datasetID string) (types.Struct, bool) {
if r, ok := ds.Datasets().MaybeGet(types.NewString(datasetID)); ok {
return r.(types.Ref).TargetValue(ds).(types.Struct), true
if r, ok := ds.MaybeHeadRef(datasetID); ok {
return r.TargetValue(ds).(types.Struct), true
}
return NewCommit(), false
}
func (ds *dataStoreCommon) MaybeHeadRef(datasetID string) (types.Ref, bool) {
if r, ok := ds.Datasets().MaybeGet(types.NewString(datasetID)); ok {
return r.(types.Ref), true
}
return types.Ref{}, false
}
func (ds *dataStoreCommon) Head(datasetID string) types.Struct {
c, ok := ds.MaybeHead(datasetID)
d.Chk.True(ok, "DataStore has no Head.")
d.Chk.True(ok, "DataStore \"%s\" has no Head.", datasetID)
return c
}
func (ds *dataStoreCommon) HeadRef(datasetID string) types.Ref {
r, ok := ds.MaybeHeadRef(datasetID)
d.Chk.True(ok, "DataStore \"%s\" has no Head.", datasetID)
return r
}
func (ds *dataStoreCommon) Datasets() types.Map {
if ds.datasets == nil {
if ds.rootRef.IsEmpty() {
@@ -68,8 +81,7 @@ func (ds *dataStoreCommon) doCommit(datasetID string, commit types.Struct) error
currentRootRef, currentDatasets := ds.getRootAndDatasets()
// TODO: This Commit will be orphaned if the tryUpdateRoot() below fails
ds.WriteValue(commit)
commitRef := types.NewTypedRefFromValue(commit)
commitRef := ds.WriteValue(commit)
// First commit in store is always fast-foward.
if !currentRootRef.IsEmpty() {
+3
View File
@@ -121,10 +121,13 @@ func (suite *DataStoreSuite) TestDataStoreCommit() {
// The old datastore still has no head.
_, ok := suite.ds.MaybeHead(datasetID)
suite.False(ok)
_, ok = suite.ds.MaybeHeadRef(datasetID)
suite.False(ok)
// The new datastore has |a|.
aCommit1 := ds2.Head(datasetID)
suite.True(aCommit1.Get(ValueField).Equals(a))
suite.Equal(aCommit1.Ref(), ds2.HeadRef(datasetID).TargetRef())
suite.ds = ds2
// |a| <- |b|
+16 -6
View File
@@ -3,7 +3,6 @@ package dataset
import (
"github.com/attic-labs/noms/d"
"github.com/attic-labs/noms/datas"
"github.com/attic-labs/noms/ref"
"github.com/attic-labs/noms/types"
)
@@ -30,6 +29,10 @@ func (ds *Dataset) MaybeHead() (types.Struct, bool) {
return ds.Store().MaybeHead(ds.id)
}
func (ds *Dataset) MaybeHeadRef() (types.Ref, bool) {
return ds.Store().MaybeHeadRef(ds.id)
}
// Head returns the current head Commit, which contains the current root of the Dataset's value tree.
func (ds *Dataset) Head() types.Struct {
c, ok := ds.MaybeHead()
@@ -37,12 +40,19 @@ func (ds *Dataset) Head() types.Struct {
return c
}
func (ds *Dataset) HeadRef() types.Ref {
r, ok := ds.MaybeHeadRef()
d.Chk.True(ok, "Dataset \"%s\" does not exist", ds.id)
return r
}
// Commit updates the commit that a dataset points at. The new Commit is constructed using v and the current Head.
// If the update cannot be performed, e.g., because of a conflict, Commit returns an 'ErrMergeNeeded' error and the current snapshot of the dataset so that the client can merge the changes and try again.
func (ds *Dataset) Commit(v types.Value) (Dataset, error) {
p := datas.NewSetOfRefOfCommit()
if head, ok := ds.MaybeHead(); ok {
p = p.Insert(types.NewTypedRefFromValue(head))
if headRef, ok := ds.MaybeHeadRef(); ok {
headRef.TargetValue(ds.Store()) // TODO: This is a hack to deconfuse the validation code, which doesn't hold onto validation state between commits.
p = p.Insert(headRef)
}
return ds.CommitWithParents(v, p)
}
@@ -63,9 +73,9 @@ func (ds *Dataset) Pull(sourceStore datas.DataStore, sourceRef types.Ref, concur
func (ds *Dataset) pull(source datas.DataStore, sourceRef types.Ref, concurrency int, topDown bool) (Dataset, error) {
sink := *ds
sinkHeadRef := types.NewTypedRef(types.MakeRefType(datas.NewCommit().Type()), ref.Ref{})
if currentHead, ok := sink.MaybeHead(); ok {
sinkHeadRef = types.NewTypedRefFromValue(currentHead)
sinkHeadRef := types.Ref{}
if currentHeadRef, ok := sink.MaybeHeadRef(); ok {
sinkHeadRef = currentHeadRef
}
if sourceRef == sinkHeadRef {