150 lines
5.2 KiB
Go
150 lines
5.2 KiB
Go
// Copyright 2026 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 main
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
driver "github.com/dolthub/dolt/go/libraries/doltcore/dtestutils/sql_server_driver"
|
|
)
|
|
|
|
// TestCloneNoConjoin asserts that a clone (in this case a backup
|
|
// sync-url) of a store with many table files does not conjoin just
|
|
// because of the datas.Clone operation.
|
|
//
|
|
// In order to construct a store with a lot of table files, without it
|
|
// itself being conjoined, this test is tightly coupled with
|
|
// implementation details around GenerationalNBS,
|
|
// nbs.defaultMaxTables, GC oldGenRefs, and how pull works.
|
|
//
|
|
// Concretely, to setup the store, this test first creates a new dolt
|
|
// commit on `main` and then runs GC. This creates a new table file in
|
|
// the old gen. It does this 192 times. It then uses a file remote,
|
|
// populated by another running sql-server, to do a similar thing. It
|
|
// creates a remote to the remote database and then fetches it. It
|
|
// creates a new commit on the remote database, pushes it, and then
|
|
// fetches that. This creates a new table file in the new gen. It does
|
|
// this 192 times. At the end, the new gen has more than 192 table
|
|
// files and the old gen has exactly 192 table files.
|
|
//
|
|
// Then this test calls dolt_backup(sync-url) to a file remote.
|
|
//
|
|
// Finally, the test asserts that the destination file remote has at
|
|
// least 384 table files in it. With default settings, if conjoin had
|
|
// been enabled, they would have been conjoined to be below 256 files.
|
|
func TestCloneNoConjoin(t *testing.T) {
|
|
t.Parallel()
|
|
var ports DynamicResources
|
|
ports.global = &GlobalPorts
|
|
ports.t = t
|
|
u, err := driver.NewDoltUser()
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() {
|
|
u.Cleanup()
|
|
})
|
|
|
|
testRS, err := u.MakeRepoStore()
|
|
require.NoError(t, err)
|
|
testRepo, err := testRS.MakeRepo("clone_no_conjoin_test")
|
|
require.NoError(t, err)
|
|
testSrvSettings := &driver.Server{
|
|
Args: []string{"-P", `{{get_port "server_port"}}`},
|
|
Envs: []string{"DOLT_REMOTE_PASSWORD=insecure_password"},
|
|
DynamicPort: "server_port",
|
|
}
|
|
testServer := MakeServer(t, testRepo, testSrvSettings, &ports)
|
|
testServer.DBName = "clone_no_conjoin_test"
|
|
|
|
remoteRS, err := u.MakeRepoStore()
|
|
require.NoError(t, err)
|
|
remoteRepo, err := remoteRS.MakeRepo("clone_no_conjoin_remote")
|
|
require.NoError(t, err)
|
|
remoteSrvSettings := &driver.Server{
|
|
Args: []string{"-P", `{{get_port "remote_server_port"}}`},
|
|
DynamicPort: "remote_server_port",
|
|
}
|
|
remoteServer := MakeServer(t, remoteRepo, remoteSrvSettings, &ports)
|
|
remoteServer.DBName = "clone_no_conjoin_remote"
|
|
|
|
// A file remote which remoteDB pushes to and db pulls from.
|
|
rendezvousDir := t.TempDir()
|
|
// The final sync-url destination about which we will make our assertions.
|
|
finalDestDir := t.TempDir()
|
|
|
|
ctx := t.Context()
|
|
|
|
// First make our oldgen table files.
|
|
db, err := testServer.DB(driver.Connection{User: "root"})
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
require.NoError(t, db.Close())
|
|
}()
|
|
func() {
|
|
conn, err := db.Conn(ctx)
|
|
require.NoError(t, err)
|
|
defer conn.Close()
|
|
for range 192 {
|
|
_, err = conn.ExecContext(ctx, "CALL DOLT_COMMIT('-A', '--allow-empty', '-m', 'creating a new commit')")
|
|
require.NoError(t, err)
|
|
_, err = conn.ExecContext(ctx, "CALL DOLT_GC()")
|
|
require.NoError(t, err)
|
|
}
|
|
}()
|
|
|
|
remoteDB, err := remoteServer.DB(driver.Connection{User: "root"})
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
require.NoError(t, remoteDB.Close())
|
|
}()
|
|
|
|
// Now make the newgen table files, pulling from a file remote.
|
|
func() {
|
|
remoteConn, err := remoteDB.Conn(ctx)
|
|
require.NoError(t, err)
|
|
defer remoteConn.Close()
|
|
_, err = remoteConn.ExecContext(ctx, "CALL DOLT_REMOTE('add', 'rendezvous', 'file://" + rendezvousDir + "')")
|
|
require.NoError(t, err)
|
|
conn, err := db.Conn(ctx)
|
|
require.NoError(t, err)
|
|
defer conn.Close()
|
|
_, err = conn.ExecContext(ctx, "CALL DOLT_REMOTE('add', 'rendezvous', 'file://" + rendezvousDir + "')")
|
|
require.NoError(t, err)
|
|
for range 192 {
|
|
_, err = remoteConn.ExecContext(ctx, "CALL DOLT_COMMIT('-A', '--allow-empty', '-m', 'creating a new commit')")
|
|
require.NoError(t, err)
|
|
_, err = remoteConn.ExecContext(ctx, "CALL DOLT_PUSH('rendezvous', 'main:remoteref')")
|
|
require.NoError(t, err)
|
|
_, err = conn.ExecContext(ctx, "CALL DOLT_FETCH('rendezvous')")
|
|
require.NoError(t, err)
|
|
}
|
|
}()
|
|
|
|
// Now backup sync-url to the finalDestDir
|
|
func() {
|
|
conn, err := db.Conn(ctx)
|
|
require.NoError(t, err)
|
|
defer conn.Close()
|
|
_, err = conn.ExecContext(ctx, "CALL DOLT_BACKUP('sync-url', 'file://" + finalDestDir + "')")
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
numTableFiles := CountTableFiles(t, finalDestDir)
|
|
t.Logf("found %v table files", numTableFiles)
|
|
assert.GreaterOrEqual(t, numTableFiles, 384)
|
|
}
|