mirror of
https://github.com/dolthub/dolt.git
synced 2026-04-28 04:28:53 -05:00
b67ab2a9e1
This make Commit a typed struct with a Set(Commit). This also fixes a case where the recursive detection for determining if a Def can be created was not working.
94 lines
2.6 KiB
Go
94 lines
2.6 KiB
Go
package datas
|
|
|
|
import (
|
|
"github.com/attic-labs/noms/chunks"
|
|
"github.com/attic-labs/noms/d"
|
|
"github.com/attic-labs/noms/ref"
|
|
"github.com/attic-labs/noms/types"
|
|
)
|
|
|
|
type dataStoreCommon struct {
|
|
chunks.ChunkStore
|
|
head *Commit
|
|
}
|
|
|
|
func commitFromRef(commitRef ref.Ref, cs chunks.ChunkSource) *Commit {
|
|
c := CommitFromVal(types.ReadValue(commitRef, cs))
|
|
return &c
|
|
}
|
|
|
|
func (ds *dataStoreCommon) MaybeHead() (Commit, bool) {
|
|
if ds.head == nil {
|
|
return NewCommit(), false
|
|
}
|
|
return *ds.head, true
|
|
}
|
|
|
|
func (ds *dataStoreCommon) Head() Commit {
|
|
c, ok := ds.MaybeHead()
|
|
d.Chk.True(ok, "DataStore has no Head.")
|
|
return c
|
|
}
|
|
|
|
func (ds *dataStoreCommon) commit(v types.Value) bool {
|
|
p := NewSetOfCommit()
|
|
if head, ok := ds.MaybeHead(); ok {
|
|
p = p.Insert(head)
|
|
}
|
|
return ds.commitWithParents(v, p)
|
|
}
|
|
|
|
func (ds *dataStoreCommon) commitWithParents(v types.Value, p SetOfCommit) bool {
|
|
return ds.doCommit(NewCommit().SetParents(p).SetValue(v))
|
|
}
|
|
|
|
// doCommit manages concurrent access the single logical piece of mutable state: the current head. doCommit is optimistic in that it is attempting to update head making the assumption that currentRootRef is the ref of the current head. The call to UpdateRoot below will fail if that assumption fails (e.g. because of a race with another writer) and the entire algorithm must be tried again.
|
|
func (ds *dataStoreCommon) doCommit(commit Commit) bool {
|
|
currentRootRef := ds.Root()
|
|
|
|
// Note: |currentHead| may be different from ds.head and *must* be consistent with currentRootRef.
|
|
// If ds.head is nil, then any commit is allowed.
|
|
if ds.head != nil {
|
|
var currentHead Commit
|
|
if currentRootRef == ds.head.Ref() {
|
|
currentHead = *ds.head
|
|
} else {
|
|
currentHead = *commitFromRef(currentRootRef, ds)
|
|
}
|
|
|
|
// Allow only fast-forward commits.
|
|
if commit.Equals(currentHead) {
|
|
return true
|
|
} else if !descendsFrom(commit, currentHead) {
|
|
return false
|
|
}
|
|
}
|
|
// TODO: This Commit will be orphaned if this UpdateRoot below fails
|
|
newRootRef := types.WriteValue(commit.NomsValue(), ds)
|
|
|
|
ok := ds.UpdateRoot(newRootRef, currentRootRef)
|
|
return ok
|
|
}
|
|
|
|
func descendsFrom(commit, currentHead Commit) bool {
|
|
// BFS because the common case is that the ancestor is only a step or two away
|
|
ancestors := NewSetOfCommit().Insert(commit)
|
|
for !ancestors.Has(currentHead) {
|
|
if ancestors.Empty() {
|
|
return false
|
|
}
|
|
ancestors = getAncestors(ancestors)
|
|
}
|
|
return true
|
|
}
|
|
|
|
func getAncestors(commits SetOfCommit) SetOfCommit {
|
|
ancestors := NewSetOfCommit()
|
|
commits.Iter(func(c Commit) (stop bool) {
|
|
ancestors =
|
|
ancestors.Union(c.Parents())
|
|
return
|
|
})
|
|
return ancestors
|
|
}
|