mirror of
https://github.com/dolthub/dolt.git
synced 2025-12-30 16:12:39 -06:00
Optimize commit iterator (#9751)
This commit is contained in:
@@ -250,7 +250,7 @@ func historicalFuzzyMatching(ctx context.Context, heads hash.HashSet, groupings
|
||||
return err
|
||||
}
|
||||
for {
|
||||
h, _, err := iterator.Next(ctx)
|
||||
h, _, _, _, err := iterator.Next(ctx)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
|
||||
@@ -28,9 +28,11 @@ import (
|
||||
|
||||
// CommitItr is an interface for iterating over a set of unique commits
|
||||
type CommitItr[C Context] interface {
|
||||
// Next returns the hash of the next commit, and a pointer to that commit. Implementations of Next must handle
|
||||
// making sure the list of commits returned are unique. When complete Next will return hash.Hash{}, nil, io.EOF
|
||||
Next(ctx C) (hash.Hash, *OptionalCommit, error)
|
||||
// Next returns the next commit's hash, pointer, metadata, and height.
|
||||
// Implementations of Next must handle making sure the list of commits returned are unique.
|
||||
// When complete Next will return hash.Hash{}, nil, nil, 0, io.EOF
|
||||
// Note: Some implementations may always return nil for the metadata and height return values.
|
||||
Next(ctx C) (hash.Hash, *OptionalCommit, *datas.CommitMeta, uint64, error)
|
||||
|
||||
// Reset the commit iterator back to the start
|
||||
Reset(ctx context.Context) error
|
||||
@@ -88,25 +90,27 @@ func (cmItr *commitItr[C]) Reset(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Next returns the hash of the next commit, and a pointer to that commit. It handles making sure the list of commits
|
||||
// returned are unique. When complete Next will return hash.Hash{}, nil, io.EOF
|
||||
func (cmItr *commitItr[C]) Next(ctx C) (hash.Hash, *OptionalCommit, error) {
|
||||
// Next returns the hash of the next commit, and a pointer to that commit.
|
||||
// It handles making sure the list of commits returned are unique.
|
||||
// When complete Next will return hash.Hash{}, nil, nil, 0, io.EOF.
|
||||
// Note: This implementation always returns nil for the metadata and height return values.
|
||||
func (cmItr *commitItr[C]) Next(ctx C) (hash.Hash, *OptionalCommit, *datas.CommitMeta, uint64, error) {
|
||||
for cmItr.curr == nil {
|
||||
if cmItr.currentRoot >= len(cmItr.rootCommits) {
|
||||
return hash.Hash{}, nil, io.EOF
|
||||
return hash.Hash{}, nil, nil, 0, io.EOF
|
||||
}
|
||||
|
||||
cm := cmItr.rootCommits[cmItr.currentRoot]
|
||||
h, err := cm.HashOf()
|
||||
|
||||
if err != nil {
|
||||
return hash.Hash{}, nil, err
|
||||
return hash.Hash{}, nil, nil, 0, err
|
||||
}
|
||||
|
||||
if !cmItr.added[h] {
|
||||
cmItr.added[h] = true
|
||||
cmItr.curr = cm
|
||||
return h, &OptionalCommit{cmItr.curr, h}, nil
|
||||
return h, &OptionalCommit{cmItr.curr, h}, nil, 0, nil
|
||||
}
|
||||
|
||||
cmItr.currentRoot++
|
||||
@@ -115,7 +119,7 @@ func (cmItr *commitItr[C]) Next(ctx C) (hash.Hash, *OptionalCommit, error) {
|
||||
parents, err := cmItr.curr.ParentHashes(ctx)
|
||||
|
||||
if err != nil {
|
||||
return hash.Hash{}, nil, err
|
||||
return hash.Hash{}, nil, nil, 0, err
|
||||
}
|
||||
|
||||
for _, h := range parents {
|
||||
@@ -137,13 +141,13 @@ func (cmItr *commitItr[C]) Next(ctx C) (hash.Hash, *OptionalCommit, error) {
|
||||
cmItr.unprocessed = cmItr.unprocessed[:numUnprocessed-1]
|
||||
cmItr.curr, err = HashToCommit(ctx, cmItr.ddb.ValueReadWriter(), cmItr.ddb.ns, next)
|
||||
if err != nil && err != ErrGhostCommitEncountered {
|
||||
return hash.Hash{}, nil, err
|
||||
return hash.Hash{}, nil, nil, 0, err
|
||||
}
|
||||
if err == ErrGhostCommitEncountered {
|
||||
cmItr.curr = nil
|
||||
}
|
||||
|
||||
return next, &OptionalCommit{cmItr.curr, next}, nil
|
||||
return next, &OptionalCommit{cmItr.curr, next}, nil, 0, nil
|
||||
}
|
||||
|
||||
func HashToCommit(ctx context.Context, vrw types.ValueReadWriter, ns tree.NodeStore, h hash.Hash) (*Commit, error) {
|
||||
@@ -183,19 +187,18 @@ func NewFilteringCommitItr[C Context](itr CommitItr[C], filter CommitFilter[C])
|
||||
|
||||
// Next returns the hash of the next commit, and a pointer to that commit. Implementations of Next must handle
|
||||
// making sure the list of commits returned are unique. When complete Next will return hash.Hash{}, nil, io.EOF
|
||||
func (itr FilteringCommitItr[C]) Next(ctx C) (hash.Hash, *OptionalCommit, error) {
|
||||
func (itr FilteringCommitItr[C]) Next(ctx C) (hash.Hash, *OptionalCommit, *datas.CommitMeta, uint64, error) {
|
||||
// iteration will terminate on io.EOF or a commit that is !filteredOut
|
||||
for {
|
||||
h, cm, err := itr.itr.Next(ctx)
|
||||
|
||||
h, cm, meta, height, err := itr.itr.Next(ctx)
|
||||
if err != nil {
|
||||
return hash.Hash{}, nil, err
|
||||
return hash.Hash{}, nil, nil, 0, err
|
||||
}
|
||||
|
||||
if filterOut, err := itr.filter(ctx, h, cm); err != nil {
|
||||
return hash.Hash{}, nil, err
|
||||
return hash.Hash{}, nil, nil, 0, err
|
||||
} else if !filterOut {
|
||||
return h, cm, nil
|
||||
return h, cm, meta, height, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,12 +220,14 @@ type CommitSliceIter[C Context] struct {
|
||||
|
||||
var _ CommitItr[context.Context] = (*CommitSliceIter[context.Context])(nil)
|
||||
|
||||
func (i *CommitSliceIter[C]) Next(ctx C) (hash.Hash, *OptionalCommit, error) {
|
||||
// Next implements the CommitItr interface.
|
||||
// Note: This implementation always returns nil for the metadata and height return values.
|
||||
func (i *CommitSliceIter[C]) Next(ctx C) (hash.Hash, *OptionalCommit, *datas.CommitMeta, uint64, error) {
|
||||
if i.i >= len(i.h) {
|
||||
return hash.Hash{}, nil, io.EOF
|
||||
return hash.Hash{}, nil, nil, 0, io.EOF
|
||||
}
|
||||
i.i++
|
||||
return i.h[i.i-1], &OptionalCommit{i.cm[i.i-1], i.h[i.i-1]}, nil
|
||||
return i.h[i.i-1], &OptionalCommit{i.cm[i.i-1], i.h[i.i-1]}, nil, 0, nil
|
||||
|
||||
}
|
||||
|
||||
@@ -232,7 +237,7 @@ func (i *CommitSliceIter[C]) Reset(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func NewOneCommitIter[C Context](cm *Commit, h hash.Hash, meta *datas.CommitMeta) *OneCommitIter[C] {
|
||||
return &OneCommitIter[C]{cm: &OptionalCommit{cm, h}, h: h}
|
||||
return &OneCommitIter[C]{cm: &OptionalCommit{cm, h}, h: h, m: meta}
|
||||
}
|
||||
|
||||
type OneCommitIter[C Context] struct {
|
||||
@@ -244,13 +249,14 @@ type OneCommitIter[C Context] struct {
|
||||
|
||||
var _ CommitItr[context.Context] = (*OneCommitIter[context.Context])(nil)
|
||||
|
||||
func (i *OneCommitIter[C]) Next(_ C) (hash.Hash, *OptionalCommit, error) {
|
||||
// Next implements the CommitItr interface.
|
||||
// Note: This implementation always returns nil for the metadata and height return values.
|
||||
func (i *OneCommitIter[C]) Next(_ C) (hash.Hash, *OptionalCommit, *datas.CommitMeta, uint64, error) {
|
||||
if i.done {
|
||||
return hash.Hash{}, nil, io.EOF
|
||||
return hash.Hash{}, nil, nil, 0, io.EOF
|
||||
}
|
||||
i.done = true
|
||||
return i.h, i.cm, nil
|
||||
|
||||
return i.h, i.cm, i.m, 0, nil
|
||||
}
|
||||
|
||||
func (i *OneCommitIter[C]) Reset(_ context.Context) error {
|
||||
|
||||
@@ -474,6 +474,23 @@ func (ddb *DoltDB) Resolve(ctx context.Context, cs *CommitSpec, cwb ref.DoltRef)
|
||||
return commit.GetAncestor(ctx, cs.aSpec)
|
||||
}
|
||||
|
||||
// ResolveHash takes a hash and returns an OptionalCommit directly.
|
||||
// This assumes no ancestor spec resolution and no current working branch (cwb) needed.
|
||||
func (ddb *DoltDB) ResolveHash(ctx context.Context, hash hash.Hash) (*OptionalCommit, error) {
|
||||
commitValue, err := datas.LoadCommitAddr(ctx, ddb.vrw, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if commitValue.IsGhost() {
|
||||
return &OptionalCommit{nil, hash}, nil
|
||||
}
|
||||
commit, err := NewCommit(ctx, ddb.vrw, ddb.ns, commitValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &OptionalCommit{commit, hash}, nil
|
||||
}
|
||||
|
||||
// BootstrapShallowResolve is a special case of Resolve that is used to resolve a commit prior to pulling it's history
|
||||
// in a shallow clone. In general, application code should call Resolve and get an OptionalCommit. This is a special case
|
||||
// where we need to get the head commit for the commit closure used to determine what commits should skipped.
|
||||
|
||||
@@ -69,23 +69,25 @@ func (q *q) Swap(i, j int) {
|
||||
// the commit with the newer timestamp is "less". Finally if both commits are ghost commits, we don't really have enough
|
||||
// information to compare on, so we just compare the hashes to ensure that the results are stable.
|
||||
func (q *q) Less(i, j int) bool {
|
||||
_, okI := q.pending[i].commit.ToCommit()
|
||||
_, okJ := q.pending[i].commit.ToCommit()
|
||||
cI := q.pending[i]
|
||||
cJ := q.pending[j]
|
||||
_, okI := cI.commit.ToCommit()
|
||||
_, okJ := cJ.commit.ToCommit()
|
||||
|
||||
if !okI && okJ {
|
||||
return true
|
||||
} else if okI && !okJ {
|
||||
return false
|
||||
} else if !okI && !okJ {
|
||||
return q.pending[i].hash.String() < q.pending[j].hash.String()
|
||||
return cI.hash.String() < cJ.hash.String()
|
||||
}
|
||||
|
||||
if q.pending[i].height > q.pending[j].height {
|
||||
if cI.height > cJ.height {
|
||||
return true
|
||||
}
|
||||
|
||||
if q.pending[i].height == q.pending[j].height {
|
||||
return q.pending[i].meta.UserTimestamp > q.pending[j].meta.UserTimestamp
|
||||
if cI.height == cJ.height {
|
||||
return cI.meta.UserTimestamp > cJ.meta.UserTimestamp
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -128,15 +130,11 @@ func (q *q) SetInvisible(ctx context.Context, ddb *doltdb.DoltDB, id hash.Hash)
|
||||
}
|
||||
|
||||
func load(ctx context.Context, ddb *doltdb.DoltDB, h hash.Hash) (*doltdb.OptionalCommit, error) {
|
||||
cs, err := doltdb.NewCommitSpec(h.String())
|
||||
oc, err := ddb.ResolveHash(ctx, h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err := ddb.Resolve(ctx, cs, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
return oc, nil
|
||||
}
|
||||
|
||||
func (q *q) Get(ctx context.Context, ddb *doltdb.DoltDB, id hash.Hash) (*c, error) {
|
||||
@@ -158,14 +156,21 @@ func (q *q) Get(ctx context.Context, ddb *doltdb.DoltDB, id hash.Hash) (*c, erro
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
meta, err := commit.GetCommitMeta(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &c{ddb: ddb, commit: &doltdb.OptionalCommit{Commit: commit, Addr: id}, meta: meta, height: h, hash: id}
|
||||
q.loaded[id] = c
|
||||
return c, nil
|
||||
lc := &c{
|
||||
ddb: ddb,
|
||||
commit: &doltdb.OptionalCommit{Commit: commit, Addr: id},
|
||||
meta: meta,
|
||||
height: h,
|
||||
hash: id,
|
||||
}
|
||||
q.loaded[id] = lc
|
||||
return lc, nil
|
||||
}
|
||||
|
||||
func newQueue() *q {
|
||||
@@ -190,7 +195,7 @@ func GetDotDotRevisions(ctx context.Context, includedDB *doltdb.DoltDB, included
|
||||
|
||||
var commitList []*doltdb.OptionalCommit
|
||||
for num < 0 || len(commitList) < num {
|
||||
_, commit, err := itr.Next(ctx)
|
||||
_, commit, _, _, err := itr.Next(ctx)
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
@@ -234,43 +239,35 @@ func newCommiterator[C doltdb.Context](ctx context.Context, ddb *doltdb.DoltDB,
|
||||
}
|
||||
|
||||
// Next implements doltdb.CommitItr
|
||||
func (iter *commiterator[C]) Next(ctx C) (hash.Hash, *doltdb.OptionalCommit, error) {
|
||||
func (iter *commiterator[C]) Next(ctx C) (hash.Hash, *doltdb.OptionalCommit, *datas.CommitMeta, uint64, error) {
|
||||
if iter.q.NumVisiblePending() > 0 {
|
||||
nextC := iter.q.PopPending()
|
||||
|
||||
var err error
|
||||
parents := []hash.Hash{}
|
||||
commit, ok := nextC.commit.ToCommit()
|
||||
if ok {
|
||||
parents, err = commit.ParentHashes(ctx)
|
||||
if err != nil {
|
||||
return hash.Hash{}, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, parentID := range parents {
|
||||
if err := iter.q.AddPendingIfUnseen(ctx, nextC.ddb, parentID); err != nil {
|
||||
return hash.Hash{}, nil, err
|
||||
for _, parentCommit := range commit.DatasParents() {
|
||||
if err := iter.q.AddPendingIfUnseen(ctx, nextC.ddb, parentCommit.Addr()); err != nil {
|
||||
return hash.Hash{}, nil, nil, 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
matches := true
|
||||
if iter.matchFn != nil {
|
||||
matches, err = iter.matchFn(nextC.commit)
|
||||
|
||||
if err != nil {
|
||||
return hash.Hash{}, nil, err
|
||||
return hash.Hash{}, nil, nil, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
if matches {
|
||||
return nextC.hash, &doltdb.OptionalCommit{Commit: commit, Addr: nextC.hash}, nil
|
||||
return nextC.hash, &doltdb.OptionalCommit{Commit: commit, Addr: nextC.hash}, nextC.meta, nextC.height, nil
|
||||
}
|
||||
|
||||
return iter.Next(ctx)
|
||||
}
|
||||
|
||||
return hash.Hash{}, nil, io.EOF
|
||||
return hash.Hash{}, nil, nil, 0, io.EOF
|
||||
}
|
||||
|
||||
// Reset implements doltdb.CommitItr
|
||||
@@ -301,7 +298,7 @@ func GetTopNTopoOrderedCommitsMatching(ctx context.Context, ddb *doltdb.DoltDB,
|
||||
|
||||
var commitList []*doltdb.Commit
|
||||
for n < 0 || len(commitList) < n {
|
||||
_, optCmt, err := itr.Next(ctx)
|
||||
_, optCmt, _, _, err := itr.Next(ctx)
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
@@ -345,28 +342,28 @@ func newDotDotCommiterator[C doltdb.Context](ctx context.Context, includedDdb *d
|
||||
}
|
||||
|
||||
// Next implements doltdb.CommitItr
|
||||
func (i *dotDotCommiterator[C]) Next(ctx C) (hash.Hash, *doltdb.OptionalCommit, error) {
|
||||
func (i *dotDotCommiterator[C]) Next(ctx C) (hash.Hash, *doltdb.OptionalCommit, *datas.CommitMeta, uint64, error) {
|
||||
if i.q.NumVisiblePending() > 0 {
|
||||
nextC := i.q.PopPending()
|
||||
|
||||
commit, ok := nextC.commit.ToCommit()
|
||||
if !ok {
|
||||
return nextC.hash, nextC.commit, nil
|
||||
return nextC.hash, nextC.commit, nextC.meta, nextC.height, nil
|
||||
}
|
||||
|
||||
parents, err := commit.ParentHashes(ctx)
|
||||
if err != nil {
|
||||
return hash.Hash{}, nil, err
|
||||
return hash.Hash{}, nil, nil, 0, err
|
||||
}
|
||||
|
||||
for _, parentID := range parents {
|
||||
if nextC.invisible {
|
||||
if err := i.q.SetInvisible(ctx, nextC.ddb, parentID); err != nil {
|
||||
return hash.Hash{}, nil, err
|
||||
return hash.Hash{}, nil, nil, 0, err
|
||||
}
|
||||
}
|
||||
if err := i.q.AddPendingIfUnseen(ctx, nextC.ddb, parentID); err != nil {
|
||||
return hash.Hash{}, nil, err
|
||||
return hash.Hash{}, nil, nil, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,18 +371,18 @@ func (i *dotDotCommiterator[C]) Next(ctx C) (hash.Hash, *doltdb.OptionalCommit,
|
||||
if i.matchFn != nil {
|
||||
matches, err = i.matchFn(nextC.commit)
|
||||
if err != nil {
|
||||
return hash.Hash{}, nil, err
|
||||
return hash.Hash{}, nil, nil, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
// If not invisible, return commit. Otherwise get next commit
|
||||
// If not invisible, return commit. Otherwise, get next commit
|
||||
if !nextC.invisible && matches {
|
||||
return nextC.hash, nextC.commit, nil
|
||||
return nextC.hash, nextC.commit, nextC.meta, nextC.height, nil
|
||||
}
|
||||
return i.Next(ctx)
|
||||
}
|
||||
|
||||
return hash.Hash{}, nil, io.EOF
|
||||
return hash.Hash{}, nil, nil, 0, io.EOF
|
||||
}
|
||||
|
||||
// Reset implements doltdb.CommitItr
|
||||
|
||||
@@ -200,7 +200,7 @@ func findRebaseCommits(ctx *sql.Context, currentBranchCommit, upstreamBranchComm
|
||||
// Drain the iterator into a slice so that we can easily reverse the order of the commits
|
||||
// so that the oldest commit is first in the generated rebase plan.
|
||||
for {
|
||||
_, optCmt, err := commitItr.Next(ctx)
|
||||
_, optCmt, _, _, err := commitItr.Next(ctx)
|
||||
if err == io.EOF {
|
||||
return commits, nil
|
||||
} else if err != nil {
|
||||
|
||||
@@ -919,7 +919,7 @@ func resolveAsOfTime(ctx *sql.Context, ddb *doltdb.DoltDB, head ref.DoltRef, asO
|
||||
}
|
||||
|
||||
for {
|
||||
_, optCmt, err := cmItr.Next(ctx)
|
||||
_, optCmt, meta, _, err := cmItr.Next(ctx)
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
@@ -930,9 +930,11 @@ func resolveAsOfTime(ctx *sql.Context, ddb *doltdb.DoltDB, head ref.DoltRef, asO
|
||||
return nil, nil, doltdb.ErrGhostCommitEncountered
|
||||
}
|
||||
|
||||
meta, err := curr.GetCommitMeta(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
if meta == nil {
|
||||
meta, err = curr.GetCommitMeta(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if meta.Time().Equal(asOf) || meta.Time().Before(asOf) {
|
||||
|
||||
@@ -146,7 +146,7 @@ var _ sql.PartitionIter = (*DoltProceduresDiffPartitionItr)(nil)
|
||||
func (dpdp *DoltProceduresDiffPartitionItr) Next(ctx *sql.Context) (sql.Partition, error) {
|
||||
// First iterate through commit history, then add working partition as the final step
|
||||
for {
|
||||
cmHash, optCmt, err := dpdp.cmItr.Next(ctx)
|
||||
cmHash, optCmt, _, _, err := dpdp.cmItr.Next(ctx)
|
||||
if err == io.EOF {
|
||||
// Finished with commit history, now add working partition if not done
|
||||
if !dpdp.workingPartitionDone {
|
||||
|
||||
@@ -146,7 +146,7 @@ var _ sql.PartitionIter = (*DoltSchemasDiffPartitionItr)(nil)
|
||||
func (dsdp *DoltSchemasDiffPartitionItr) Next(ctx *sql.Context) (sql.Partition, error) {
|
||||
// First iterate through commit history, then add working partition as the final step
|
||||
for {
|
||||
cmHash, optCmt, err := dsdp.cmItr.Next(ctx)
|
||||
cmHash, optCmt, _, _, err := dsdp.cmItr.Next(ctx)
|
||||
if err == io.EOF {
|
||||
// Finished with commit history, now add working partition if not done
|
||||
if !dsdp.workingPartitionDone {
|
||||
|
||||
@@ -146,7 +146,7 @@ func countCommitsInRange(ctx context.Context, ddb *doltdb.DoltDB, startCommitHas
|
||||
}
|
||||
count := 0
|
||||
for {
|
||||
nextHash, _, err := itr.Next(ctx)
|
||||
nextHash, _, _, _, err := itr.Next(ctx)
|
||||
if err == io.EOF {
|
||||
return 0, fmt.Errorf("no match found to ancestor commit")
|
||||
} else if err != nil {
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/schema"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess"
|
||||
"github.com/dolthub/dolt/go/libraries/utils/gpg"
|
||||
"github.com/dolthub/dolt/go/store/datas"
|
||||
"github.com/dolthub/dolt/go/store/hash"
|
||||
)
|
||||
|
||||
@@ -688,9 +689,11 @@ func (itr *logTableFunctionRowIter) Next(ctx *sql.Context) (sql.Row, error) {
|
||||
var commitHash hash.Hash
|
||||
var commit *doltdb.Commit
|
||||
var optCmt *doltdb.OptionalCommit
|
||||
var meta *datas.CommitMeta
|
||||
var height uint64
|
||||
var err error
|
||||
for {
|
||||
commitHash, optCmt, err = itr.child.Next(ctx)
|
||||
commitHash, optCmt, meta, height, err = itr.child.Next(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -762,14 +765,19 @@ func (itr *logTableFunctionRowIter) Next(ctx *sql.Context) (sql.Row, error) {
|
||||
}
|
||||
}
|
||||
|
||||
meta, err := commit.GetCommitMeta(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if meta == nil {
|
||||
meta, err = commit.GetCommitMeta(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
height, err := commit.Height()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// TODO: will retrieve height again if it's 0
|
||||
if height == 0 {
|
||||
height, err = commit.Height()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
row := sql.NewRow(commitHash.String(), meta.Name, meta.Email, meta.Time(), meta.Description, height)
|
||||
|
||||
@@ -337,7 +337,7 @@ func (itr *doltColDiffCommitHistoryRowItr) Next(ctx *sql.Context) (sql.Row, erro
|
||||
}
|
||||
itr.commits = nil
|
||||
} else if itr.child != nil {
|
||||
_, optCmt, err := itr.child.Next(ctx)
|
||||
_, optCmt, _, _, err := itr.child.Next(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ func NewCommitAncestorsRowItr(sqlCtx *sql.Context, ddb *doltdb.DoltDB) (*CommitA
|
||||
// After retrieving the last row, Close will be automatically closed.
|
||||
func (itr *CommitAncestorsRowItr) Next(ctx *sql.Context) (sql.Row, error) {
|
||||
if len(itr.cache) == 0 {
|
||||
ch, optCmt, err := itr.itr.Next(ctx)
|
||||
ch, optCmt, _, _, err := itr.itr.Next(ctx)
|
||||
if err != nil {
|
||||
// When complete itr.Next will return io.EOF
|
||||
return nil, err
|
||||
|
||||
@@ -152,7 +152,7 @@ func NewCommitsRowItr(ctx *sql.Context, ddb *doltdb.DoltDB) (CommitsRowItr, erro
|
||||
// Next retrieves the next row. It will return io.EOF if it's the last row.
|
||||
// After retrieving the last row, Close will be automatically closed.
|
||||
func (itr CommitsRowItr) Next(ctx *sql.Context) (sql.Row, error) {
|
||||
h, optCmt, err := itr.itr.Next(ctx)
|
||||
h, optCmt, _, _, err := itr.itr.Next(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ func (dt *DiffTable) PartitionRanges(ctx *sql.Context, ranges []prolly.Range) (s
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmHash, _, err := cmItr.Next(ctx)
|
||||
cmHash, _, _, _, err := cmItr.Next(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -424,7 +424,7 @@ func (dt *DiffTable) scanHeightForChild(ctx *sql.Context, parent hash.Hash, heig
|
||||
func (dt *DiffTable) reverseIterForChild(ctx *sql.Context, parent hash.Hash) (*doltdb.Commit, hash.Hash, error) {
|
||||
iter := doltdb.CommitItrForRoots[*sql.Context](dt.ddb, dt.head)
|
||||
for {
|
||||
childHs, optCmt, err := iter.Next(ctx)
|
||||
childHs, optCmt, _, _, err := iter.Next(ctx)
|
||||
if errors.Is(err, io.EOF) {
|
||||
return nil, hash.Hash{}, nil
|
||||
} else if err != nil {
|
||||
@@ -839,7 +839,7 @@ func (dps *DiffPartitions) Next(ctx *sql.Context) (sql.Partition, error) {
|
||||
}
|
||||
|
||||
for {
|
||||
cmHash, optCmt, err := dps.cmItr.Next(ctx)
|
||||
cmHash, optCmt, _, _, err := dps.cmItr.Next(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ func NewLogItr(ctx *sql.Context, ddb *doltdb.DoltDB, head *doltdb.Commit) (*LogI
|
||||
// Next retrieves the next row. It will return io.EOF if it's the last row.
|
||||
// After retrieving the last row, Close will be automatically closed.
|
||||
func (itr *LogItr) Next(ctx *sql.Context) (sql.Row, error) {
|
||||
h, optCmt, err := itr.child.Next(ctx)
|
||||
h, optCmt, meta, height, err := itr.child.Next(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -246,14 +246,18 @@ func (itr *LogItr) Next(ctx *sql.Context) (sql.Row, error) {
|
||||
return nil, doltdb.ErrGhostCommitRuntimeFailure
|
||||
}
|
||||
|
||||
meta, err := cm.GetCommitMeta(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if meta == nil {
|
||||
meta, err = cm.GetCommitMeta(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
height, err := cm.Height()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if height == 0 {
|
||||
height, err = cm.Height()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return sql.NewRow(h.String(), meta.Name, meta.Email, meta.Time(), meta.Description, height), nil
|
||||
|
||||
@@ -338,7 +338,7 @@ func (itr *doltDiffCommitHistoryRowItr) Next(ctx *sql.Context) (sql.Row, error)
|
||||
}
|
||||
itr.commits = nil
|
||||
} else if itr.child != nil {
|
||||
_, optCmt, err := itr.child.Next(ctx)
|
||||
_, optCmt, _, _, err := itr.child.Next(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -347,6 +347,7 @@ func (itr *doltDiffCommitHistoryRowItr) Next(ctx *sql.Context) (sql.Row, error)
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
// TODO: we already have meta and height
|
||||
err = itr.loadTableChanges(ctx, commit)
|
||||
if err == doltdb.ErrGhostCommitEncountered {
|
||||
// When showing the diff table in a shallow clone, we show as much of the dolt_history_{table} as we can,
|
||||
|
||||
@@ -456,7 +456,7 @@ type commitPartitioner struct {
|
||||
|
||||
// Next returns the next partition and nil, io.EOF when complete
|
||||
func (cp commitPartitioner) Next(ctx *sql.Context) (sql.Partition, error) {
|
||||
h, optCmt, err := cp.cmItr.Next(ctx)
|
||||
h, optCmt, _, _, err := cp.cmItr.Next(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
5
go/performance/dolt_log_bench/.gitignore
vendored
Normal file
5
go/performance/dolt_log_bench/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
*.test
|
||||
*.pprof
|
||||
*.out
|
||||
*.pdf
|
||||
*.exe
|
||||
94
go/performance/dolt_log_bench/dolt_log_test.go
Normal file
94
go/performance/dolt_log_bench/dolt_log_test.go
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright 2025 Dolthub, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dolt_log_bench
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/dolthub/go-mysql-server/sql"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/dolthub/dolt/go/cmd/dolt/commands"
|
||||
"github.com/dolthub/dolt/go/cmd/dolt/commands/engine"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/dtestutils"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/env"
|
||||
)
|
||||
|
||||
var dEnv *env.DoltEnv
|
||||
|
||||
func init() {
|
||||
dEnv = dtestutils.CreateTestEnv()
|
||||
populateCommitGraph(dEnv)
|
||||
}
|
||||
|
||||
func setupBenchmark(t *testing.B, dEnv *env.DoltEnv) (*sql.Context, *engine.SqlEngine) {
|
||||
ctx := context.Background()
|
||||
config := &engine.SqlEngineConfig{
|
||||
ServerUser: "root",
|
||||
Autocommit: true,
|
||||
}
|
||||
|
||||
mrEnv, err := env.MultiEnvForDirectory(ctx, dEnv.Config.WriteableConfig(), dEnv.FS, dEnv.Version, dEnv)
|
||||
require.NoError(t, err)
|
||||
|
||||
eng, err := engine.NewSqlEngine(ctx, mrEnv, config)
|
||||
require.NoError(t, err)
|
||||
|
||||
sqlCtx, err := eng.NewLocalContext(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
sqlCtx.SetCurrentDatabase("dolt")
|
||||
return sqlCtx, eng
|
||||
}
|
||||
|
||||
func populateCommitGraph(dEnv *env.DoltEnv) {
|
||||
ctx := context.Background()
|
||||
cliCtx, err := commands.NewArgFreeCliContext(ctx, dEnv, dEnv.FS)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer cliCtx.Close()
|
||||
execSql := func(dEnv *env.DoltEnv, q string) int {
|
||||
args := []string{"-r", "null", "-q", q}
|
||||
return commands.SqlCmd{}.Exec(ctx, "sql", args, dEnv, cliCtx)
|
||||
}
|
||||
for i := 0; i < 500; i++ {
|
||||
execSql(dEnv, fmt.Sprintf("call dolt_commit('--allow-empty', '-m', '%d') ", i))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDoltLog(b *testing.B) {
|
||||
ctx, eng := setupBenchmark(b, dEnv)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, iter, _, err := eng.Query(ctx, "select * from dolt_log()")
|
||||
require.NoError(b, err)
|
||||
for {
|
||||
_, err := iter.Next(ctx)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
require.Error(b, io.EOF)
|
||||
err = iter.Close(ctx)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
_ = eng.Close()
|
||||
b.ReportAllocs()
|
||||
}
|
||||
@@ -106,7 +106,7 @@ func (db *database) loadDatasetsNomsMap(ctx context.Context, rootHash hash.Hash)
|
||||
}
|
||||
|
||||
func (db *database) loadDatasetsRefmap(ctx context.Context, rootHash hash.Hash) (prolly.AddressMap, error) {
|
||||
if rootHash == (hash.Hash{}) {
|
||||
if rootHash.IsEmpty() {
|
||||
return prolly.NewEmptyAddressMap(db.ns)
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ func (m nomsDatasetsMap) IterAll(ctx context.Context, cb func(string, hash.Hash)
|
||||
}
|
||||
|
||||
// Datasets returns the Map of Datasets in the current root. If you intend to edit the map and commit changes back,
|
||||
// then you should fetch the current root, then call DatasetsInRoot with that hash. Otherwise another writer could
|
||||
// then you should fetch the current root, then call DatasetsInRoot with that hash. Otherwise, another writer could
|
||||
// change the root value between when you get the root hash and call this method.
|
||||
func (db *database) Datasets(ctx context.Context) (DatasetsMap, error) {
|
||||
rootHash, err := db.rt.Root(ctx)
|
||||
|
||||
Reference in New Issue
Block a user