Skip to content

Commit abb83ee

Browse files
committed
Fix ClickHouse server startup and version management
- Fix download URL to use correct v25.8.13.73-lts release - Extract clickhouse binary from tgz archive correctly - Start server in background instead of daemon mode (daemon was unreliable) - Use clickhouse client for EXPLAIN AST queries (faster than local) - Add version header to generated explain.txt files
1 parent af966e6 commit abb83ee

2 files changed

Lines changed: 130 additions & 57 deletions

File tree

cmd/regenerate-explain/main.go

Lines changed: 129 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package main
22

33
import (
4+
"archive/tar"
45
"bytes"
6+
"compress/gzip"
57
"flag"
68
"fmt"
79
"io"
@@ -19,20 +21,18 @@ import (
1921
const (
2022
// Required ClickHouse version for generating explain files
2123
// Update this when regenerating all test expectations
22-
requiredVersion = "25.8.1.3073"
23-
requiredLTS = "25.8.13.73-lts"
24+
requiredVersion = "25.8.13.73"
25+
requiredLTS = "v25.8.13.73-lts"
2426

25-
// Download URL for the static binary
26-
downloadURL = "https://github.com/ClickHouse/ClickHouse/releases/download/v25.8.1.3073-lts/clickhouse-linux-amd64"
27+
// Download URL for the static binary package
28+
downloadURL = "https://github.com/ClickHouse/ClickHouse/releases/download/v25.8.13.73-lts/clickhouse-common-static-25.8.13.73-amd64.tgz"
2729
)
2830

2931
var (
30-
clickhouseDir = ".clickhouse"
31-
clickhouseBin = "clickhouse"
32-
pidFile = filepath.Join(clickhouseDir, "clickhouse.pid")
33-
configFile = filepath.Join(clickhouseDir, "config.xml")
34-
serverLogFile = filepath.Join(clickhouseDir, "logs", "server.log")
35-
serverErrFile = filepath.Join(clickhouseDir, "logs", "server.err.log")
32+
clickhouseDir = ".clickhouse"
33+
clickhouseBin = "./clickhouse"
34+
pidFile = ".clickhouse/clickhouse.pid"
35+
configFile = ".clickhouse/config.xml"
3636
)
3737

3838
func main() {
@@ -64,7 +64,7 @@ func main() {
6464
}
6565

6666
if *dryRun {
67-
fmt.Println("Dry run mode - would process tests using clickhouse local")
67+
fmt.Println("Dry run mode - would process tests using clickhouse client")
6868
}
6969

7070
testdataDir := "parser/testdata"
@@ -115,6 +115,11 @@ func main() {
115115

116116
// ensureClickHouse ensures ClickHouse is downloaded and running with the correct version
117117
func ensureClickHouse() error {
118+
// Download if binary doesn't exist or has wrong version
119+
if err := ensureBinary(); err != nil {
120+
return fmt.Errorf("ensuring binary: %w", err)
121+
}
122+
118123
// Check if already running with correct version
119124
if version, err := getRunningVersion(); err == nil {
120125
if version == requiredVersion {
@@ -127,11 +132,6 @@ func ensureClickHouse() error {
127132
}
128133
}
129134

130-
// Download if binary doesn't exist or has wrong version
131-
if err := ensureBinary(); err != nil {
132-
return fmt.Errorf("ensuring binary: %w", err)
133-
}
134-
135135
// Start the server
136136
if err := startClickHouse(); err != nil {
137137
return fmt.Errorf("starting ClickHouse: %w", err)
@@ -220,32 +220,28 @@ func ensureBinary() error {
220220
return fmt.Errorf("download failed with status %d", resp.StatusCode)
221221
}
222222

223-
// Write to temporary file first
224-
tmpFile := clickhouseBin + ".tmp"
225-
out, err := os.Create(tmpFile)
223+
// Download to temporary file
224+
tmpTgz := clickhouseBin + ".tgz"
225+
out, err := os.Create(tmpTgz)
226226
if err != nil {
227227
return fmt.Errorf("creating temp file: %w", err)
228228
}
229229

230230
written, err := io.Copy(out, resp.Body)
231231
out.Close()
232232
if err != nil {
233-
os.Remove(tmpFile)
234-
return fmt.Errorf("writing binary: %w", err)
233+
os.Remove(tmpTgz)
234+
return fmt.Errorf("writing archive: %w", err)
235235
}
236236

237237
fmt.Printf("Downloaded %d bytes\n", written)
238238

239-
// Make executable and move to final location
240-
if err := os.Chmod(tmpFile, 0755); err != nil {
241-
os.Remove(tmpFile)
242-
return fmt.Errorf("chmod: %w", err)
243-
}
244-
245-
if err := os.Rename(tmpFile, clickhouseBin); err != nil {
246-
os.Remove(tmpFile)
247-
return fmt.Errorf("rename: %w", err)
239+
// Extract clickhouse binary from the tgz
240+
if err := extractClickhouseBinary(tmpTgz); err != nil {
241+
os.Remove(tmpTgz)
242+
return fmt.Errorf("extracting binary: %w", err)
248243
}
244+
os.Remove(tmpTgz)
249245

250246
// Verify version
251247
version, err := getBinaryVersion()
@@ -261,6 +257,62 @@ func ensureBinary() error {
261257
return nil
262258
}
263259

260+
// extractClickhouseBinary extracts the clickhouse binary from a tgz archive
261+
func extractClickhouseBinary(tgzPath string) error {
262+
f, err := os.Open(tgzPath)
263+
if err != nil {
264+
return err
265+
}
266+
defer f.Close()
267+
268+
gzr, err := gzip.NewReader(f)
269+
if err != nil {
270+
return fmt.Errorf("gzip reader: %w", err)
271+
}
272+
defer gzr.Close()
273+
274+
tr := tar.NewReader(gzr)
275+
276+
// Look for the clickhouse binary in the archive
277+
// It's at usr/bin/clickhouse
278+
for {
279+
header, err := tr.Next()
280+
if err == io.EOF {
281+
break
282+
}
283+
if err != nil {
284+
return fmt.Errorf("reading tar: %w", err)
285+
}
286+
287+
// Check if this is the clickhouse binary (at usr/bin/clickhouse)
288+
if header.Typeflag == tar.TypeReg && strings.HasSuffix(header.Name, "/usr/bin/clickhouse") {
289+
fmt.Printf("Extracting %s...\n", header.Name)
290+
291+
tmpBin := clickhouseBin + ".tmp"
292+
outFile, err := os.OpenFile(tmpBin, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755)
293+
if err != nil {
294+
return fmt.Errorf("creating output file: %w", err)
295+
}
296+
297+
if _, err := io.Copy(outFile, tr); err != nil {
298+
outFile.Close()
299+
os.Remove(tmpBin)
300+
return fmt.Errorf("extracting file: %w", err)
301+
}
302+
outFile.Close()
303+
304+
if err := os.Rename(tmpBin, clickhouseBin); err != nil {
305+
os.Remove(tmpBin)
306+
return fmt.Errorf("renaming binary: %w", err)
307+
}
308+
309+
return nil
310+
}
311+
}
312+
313+
return fmt.Errorf("clickhouse binary not found in archive")
314+
}
315+
264316
// getBinaryVersion returns the version of the clickhouse binary
265317
func getBinaryVersion() (string, error) {
266318
cmd := exec.Command(clickhouseBin, "local", "--query", "SELECT version()")
@@ -295,23 +347,46 @@ func startClickHouse() error {
295347

296348
fmt.Println("Starting ClickHouse server...")
297349

298-
// Start the server as a daemon
299-
cmd := exec.Command(clickhouseBin, "server",
300-
"--config-file="+configFile,
301-
"--daemon",
302-
"--pid-file="+pidFile)
303-
cmd.Stdout = os.Stdout
304-
cmd.Stderr = os.Stderr
350+
// Start the server in background using nohup-style approach
351+
cmd := exec.Command(clickhouseBin, "server", "--config-file="+configFile)
305352

306-
if err := cmd.Run(); err != nil {
353+
// Redirect output to log files
354+
logFile, err := os.OpenFile(filepath.Join(clickhouseDir, "logs", "clickhouse-server.log"),
355+
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
356+
if err != nil {
357+
return fmt.Errorf("opening log file: %w", err)
358+
}
359+
errLogFile, err := os.OpenFile(filepath.Join(clickhouseDir, "logs", "clickhouse-server.err.log"),
360+
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
361+
if err != nil {
362+
logFile.Close()
363+
return fmt.Errorf("opening error log file: %w", err)
364+
}
365+
366+
cmd.Stdout = logFile
367+
cmd.Stderr = errLogFile
368+
369+
if err := cmd.Start(); err != nil {
370+
logFile.Close()
371+
errLogFile.Close()
307372
return fmt.Errorf("starting server: %w", err)
308373
}
309374

375+
// Write PID file
376+
if err := os.WriteFile(pidFile, []byte(fmt.Sprintf("%d\n", cmd.Process.Pid)), 0644); err != nil {
377+
return fmt.Errorf("writing PID file: %w", err)
378+
}
379+
310380
// Wait for server to be ready
311381
fmt.Println("Waiting for server to be ready...")
312-
for i := 0; i < 30; i++ {
382+
for i := 0; i < 60; i++ {
313383
time.Sleep(1 * time.Second)
314-
if version, err := getRunningVersion(); err == nil {
384+
// Try to connect to the server
385+
testCmd := exec.Command(clickhouseBin, "client", "--query", "SELECT version()")
386+
var stdout bytes.Buffer
387+
testCmd.Stdout = &stdout
388+
if err := testCmd.Run(); err == nil {
389+
version := strings.TrimSpace(stdout.String())
315390
if version != requiredVersion {
316391
return fmt.Errorf("server started with version %s but expected %s", version, requiredVersion)
317392
}
@@ -320,6 +395,11 @@ func startClickHouse() error {
320395
}
321396
}
322397

398+
// Check logs for errors
399+
if logData, err := os.ReadFile(filepath.Join(clickhouseDir, "logs", "clickhouse-server.err.log")); err == nil && len(logData) > 0 {
400+
fmt.Fprintf(os.Stderr, "Server error log:\n%s\n", string(logData))
401+
}
402+
323403
return fmt.Errorf("timeout waiting for server to start")
324404
}
325405

@@ -376,22 +456,21 @@ func writeConfig() error {
376456
<clickhouse>
377457
<logger>
378458
<level>information</level>
379-
<log>%s/%s</log>
380-
<errorlog>%s/%s</errorlog>
459+
<log>%s/.clickhouse/logs/clickhouse-server.log</log>
460+
<errorlog>%s/.clickhouse/logs/clickhouse-server.err.log</errorlog>
381461
<size>100M</size>
382462
<count>3</count>
383463
</logger>
384464
385465
<http_port>8123</http_port>
386466
<tcp_port>9000</tcp_port>
387-
<mysql_port>9004</mysql_port>
388467
389468
<listen_host>127.0.0.1</listen_host>
390469
391-
<path>%s/%s/data/</path>
392-
<tmp_path>%s/%s/tmp/</tmp_path>
393-
<user_files_path>%s/%s/user_files/</user_files_path>
394-
<format_schema_path>%s/%s/format_schemas/</format_schema_path>
470+
<path>%s/.clickhouse/data/</path>
471+
<tmp_path>%s/.clickhouse/tmp/</tmp_path>
472+
<user_files_path>%s/.clickhouse/user_files/</user_files_path>
473+
<format_schema_path>%s/.clickhouse/format_schemas/</format_schema_path>
395474
396475
<mark_cache_size>5368709120</mark_cache_size>
397476
@@ -428,14 +507,7 @@ func writeConfig() error {
428507
</default>
429508
</quotas>
430509
</clickhouse>
431-
`,
432-
cwd, serverLogFile,
433-
cwd, serverErrFile,
434-
cwd, clickhouseDir,
435-
cwd, clickhouseDir,
436-
cwd, clickhouseDir,
437-
cwd, clickhouseDir,
438-
)
510+
`, cwd, cwd, cwd, cwd, cwd, cwd)
439511

440512
return os.WriteFile(configFile, []byte(config), 0644)
441513
}
@@ -565,10 +637,10 @@ func findCommentStart(line string) int {
565637
return -1
566638
}
567639

568-
// explainAST runs EXPLAIN AST on the statement using clickhouse local
640+
// explainAST runs EXPLAIN AST on the statement using clickhouse client
569641
func explainAST(stmt string) (string, error) {
570642
query := fmt.Sprintf("EXPLAIN AST %s", stmt)
571-
cmd := exec.Command(clickhouseBin, "local", "--query", query)
643+
cmd := exec.Command(clickhouseBin, "client", "--query", query)
572644

573645
var stdout, stderr bytes.Buffer
574646
cmd.Stdout = &stdout

parser/testdata/00001_select_1/explain.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
-- Generated by ClickHouse 25.8.13.73
12
SelectWithUnionQuery (children 1)
23
ExpressionList (children 1)
34
SelectQuery (children 1)

0 commit comments

Comments
 (0)