Skip to content

go/store: fix push latency growth for git-backed remotes#10597

Merged
coffeegoddd merged 14 commits intomainfrom
db/fixes-clean
Mar 3, 2026
Merged

go/store: fix push latency growth for git-backed remotes#10597
coffeegoddd merged 14 commits intomainfrom
db/fixes-clean

Conversation

@coffeegoddd
Copy link
Copy Markdown
Contributor

Cache remote DoltDB instances across pushes, use parented commits with bounded depth for incremental git deltas, write table files as single blobs instead of split .records/.tail intermediates, and run periodic git gc to repack cache repos.

@coffeegoddd
Copy link
Copy Markdown
Contributor Author

@coffeegoddd DOLT

comparing_percentages
100.000000 to 100.000000
version result total
68fccc0 ok 5937471
version total_tests
68fccc0 5937471
correctness_percentage
100.0

@coffeegoddd
Copy link
Copy Markdown
Contributor Author

@coffeegoddd DOLT

comparing_percentages
100.000000 to 100.000000
version result total
942bc24 ok 5937471
version total_tests
942bc24 5937471
correctness_percentage
100.0

@coffeegoddd
Copy link
Copy Markdown
Contributor Author

@coffeegoddd DOLT

comparing_percentages
100.000000 to 100.000000
version result total
0f55ff4 ok 5937471
version total_tests
0f55ff4 5937471
correctness_percentage
100.0

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR targets push latency growth for git-backed remotes by reducing per-push re-open work, improving git delta efficiency, and lowering git object growth in the cache repo.

Changes:

  • Cache git-backed remote DoltDB instances across pushes to reuse already-opened table sources.
  • Switch Git NBS persistence to write table files as a single blob (avoids .records / .tail intermediates).
  • Adjust GitBlobstore remote-managed write semantics to use bounded parent chains for incremental deltas and add periodic git gc for cache repo repacking.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
go/store/nbs/store.go Use singleBlobBSPersister for git-backed NBS stores.
go/store/nbs/single_blob_bs_persister.go New persister that writes table files as a single blob while still supporting conjoin.
go/store/nbs/git_blobstore_empty_remote_test.go Update test expectations for the new persister type.
go/store/nbs/bs_persister.go Minor formatting-only change.
go/store/nbs/bs_manifest.go Minor formatting-only change.
go/store/blobstore/internal/git/api.go Extend GitAPI with RevListCount.
go/store/blobstore/internal/git/impl.go Implement RevListCount using git rev-list --count.
go/store/blobstore/git_blobstore.go Add separate write/pending locks, read-sync TTL dedup, bounded parent commits, and periodic git gc.
go/store/blobstore/git_blobstore_test.go Update tests for new tracking behavior and add read-during-push concurrency test.
go/store/blobstore/git_blobstore_helpers_test.go Update fakeGitAPI to satisfy the new interface method.
go/store/blobstore/git_blobstore_cache_merge_semantics_test.go Disable read-sync dedup in a test to observe immediate remote mutations.
go/libraries/doltcore/sqle/database_provider.go Cache git-backed remote DoltDB instances and close them on provider shutdown.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +563 to +583
isGitRemote := strings.HasPrefix(strings.ToLower(r.Url), "git+")
if isGitRemote {
p.mu.RLock()
if cached, ok := p.remoteDbs[r.Url]; ok {
p.mu.RUnlock()
return cached, nil
}
p.mu.RUnlock()
}

remoteDB, err := r.GetRemoteDB(ctx, format, dialer)
if err != nil {
return nil, err
}

if isGitRemote {
p.mu.Lock()
p.remoteDbs[r.Url] = remoteDB
p.mu.Unlock()
}
return remoteDB, nil
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The git-remote DB cache can race: two goroutines can both miss p.remoteDbs[r.Url], both open a new remote DB, and then the later store overwrites the earlier without closing it. To avoid leaking open remotes, consider re-checking the cache under p.mu.Lock() (double-checked locking) and closing the newly-opened DB if another goroutine already cached one.

Copilot uses AI. Check for mistakes.
Comment on lines +1135 to +1144
// instead of enumerating the full tree. After maxParentedCommits in the
// existing chain, create a parentless commit to sever history so git gc can
// prune old objects.
var parentPtr *git.OID
if hasParent && parent != "" {
depth, err := gbs.api.RevListCount(ctx, parent)
if err == nil && depth < maxParentedCommits {
p := parent
parentPtr = &p
}
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RevListCount runs git rev-list --count <oid>, which can be expensive if the remote ref has a long history (e.g., externally mutated). Since you only need to know whether the depth exceeds maxParentedCommits, consider using a bounded traversal (e.g., rev-list --count --max-count=<maxParentedCommits+1>) or another O(1) heuristic to avoid scanning an unbounded history.

Suggested change
// instead of enumerating the full tree. After maxParentedCommits in the
// existing chain, create a parentless commit to sever history so git gc can
// prune old objects.
var parentPtr *git.OID
if hasParent && parent != "" {
depth, err := gbs.api.RevListCount(ctx, parent)
if err == nil && depth < maxParentedCommits {
p := parent
parentPtr = &p
}
// instead of enumerating the full tree.
// NOTE: We deliberately avoid an unbounded history traversal (e.g. "git rev-list --count")
// here for performance reasons. This means we may keep longer parent chains than
// strictly necessary for GC, but avoids potentially expensive scans on large repos.
var parentPtr *git.OID
if hasParent && parent != "" {
p := parent
parentPtr = &p

Copilot uses AI. Check for mistakes.
const readers = 25
var wg sync.WaitGroup
readErrs := make(chan error, readers)
for range readers {
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop won't compile: for range readers {} only works with slices/maps/channels/strings, not an integer constant. Use a counted loop (e.g., for i := 0; i < readers; i++ { ... }).

Suggested change
for range readers {
for i := 0; i < readers; i++ {

Copilot uses AI. Check for mistakes.
@coffeegoddd
Copy link
Copy Markdown
Contributor Author

@coffeegoddd DOLT

comparing_percentages
100.000000 to 100.000000
version result total
a6a847d ok 5937471
version total_tests
a6a847d 5937471
correctness_percentage
100.0

@coffeegoddd coffeegoddd requested a review from reltuk March 2, 2026 17:21
Copy link
Copy Markdown
Contributor

@bheni bheni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I'd address copilot's issues. My review is mostly surface level stuff. Would need to take some time to get more context here, but if you feel good about the tests then I'm good with it.

@coffeegoddd
Copy link
Copy Markdown
Contributor Author

@coffeegoddd DOLT

comparing_percentages
100.000000 to 100.000000
version result total
272d08e ok 5937471
version total_tests
272d08e 5937471
correctness_percentage
100.0

@coffeegoddd
Copy link
Copy Markdown
Contributor Author

@coffeegoddd DOLT

test_name from_latency_p95 to_latency_p95 percent_change
tpcc-scale-factor-1 61.08 61.08 0.0
test_name from_server_name from_server_version from_tps to_server_name to_server_version to_tps percent_change
tpcc-scale-factor-1 dolt 0c63589 37.53 dolt 272d08e 37.84 0.83

@coffeegoddd coffeegoddd merged commit 5f7509e into main Mar 3, 2026
25 of 26 checks passed
@coffeegoddd coffeegoddd deleted the db/fixes-clean branch March 3, 2026 01:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants