From d1484690ff9c9c7a7eba1aa7ec039d217d314655 Mon Sep 17 00:00:00 2001 From: Benjamin Kalman Date: Mon, 2 May 2016 10:25:03 -0700 Subject: [PATCH] Go: change Datastore/Dataset Commit to use Ref 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. --- datas/datastore.go | 6 ++++++ datas/datastore_common.go | 22 +++++++++++++++++----- datas/datastore_test.go | 3 +++ dataset/dataset.go | 22 ++++++++++++++++------ 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/datas/datastore.go b/datas/datastore.go index cdf0bb2e5f..c9ea853866 100644 --- a/datas/datastore.go +++ b/datas/datastore.go @@ -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 diff --git a/datas/datastore_common.go b/datas/datastore_common.go index c5bff72522..86109b2660 100644 --- a/datas/datastore_common.go +++ b/datas/datastore_common.go @@ -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() { diff --git a/datas/datastore_test.go b/datas/datastore_test.go index b61bec4c6a..505e84482f 100644 --- a/datas/datastore_test.go +++ b/datas/datastore_test.go @@ -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| diff --git a/dataset/dataset.go b/dataset/dataset.go index cdc8224927..6c0b569d6d 100644 --- a/dataset/dataset.go +++ b/dataset/dataset.go @@ -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 {