Skip to content

Commit 216beca

Browse files
feat: extract meta.db from 2.x Bolt file (#27031)
A small utility to extract the V1 metadata from a V2 bolt database for debugging use.
1 parent 0c55eb6 commit 216beca

1 file changed

Lines changed: 113 additions & 0 deletions

File tree

cmd/extract-meta/main.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// extract-meta extracts the v1_tsm1_metadata value from an InfluxDB BoltDB file
2+
// and writes it to a file in binary format, or optionally as JSON.
3+
package main
4+
5+
import (
6+
"encoding/json"
7+
"flag"
8+
"fmt"
9+
"os"
10+
11+
"github.com/influxdata/influxdb/v2/v1/services/meta"
12+
bolt "go.etcd.io/bbolt"
13+
)
14+
15+
func main() {
16+
var (
17+
boltPath string
18+
outputPath string
19+
asJSON bool
20+
)
21+
22+
flag.StringVar(&boltPath, "bolt", "", "path to the BoltDB file (e.g., influxd.bolt)")
23+
flag.StringVar(&outputPath, "out", "", "output file path; use - for stdout (default: stdout for JSON, meta.db.bin for binary)")
24+
flag.BoolVar(&asJSON, "json", false, "output as JSON instead of binary")
25+
flag.Parse()
26+
27+
if boltPath == "" {
28+
fmt.Fprintln(os.Stderr, "error: -bolt flag is required")
29+
flag.Usage()
30+
os.Exit(1)
31+
}
32+
33+
if err := run(boltPath, outputPath, asJSON); err != nil {
34+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
35+
os.Exit(1)
36+
}
37+
}
38+
39+
func run(boltPath, outputPath string, asJSON bool) error {
40+
db, err := bolt.Open(boltPath, 0600, &bolt.Options{ReadOnly: true})
41+
if err != nil {
42+
return fmt.Errorf("failed to open bolt db %s: %w", boltPath, err)
43+
}
44+
defer db.Close()
45+
46+
var data []byte
47+
48+
err = db.View(func(tx *bolt.Tx) error {
49+
bucket := tx.Bucket(meta.BucketName)
50+
if bucket == nil {
51+
return fmt.Errorf("bucket %q not found", string(meta.BucketName))
52+
}
53+
54+
val := bucket.Get([]byte(meta.Filename))
55+
if val == nil {
56+
return fmt.Errorf("key %q not found in bucket %q", meta.Filename, string(meta.BucketName))
57+
}
58+
59+
// Copy the value since it's only valid for the duration of the transaction
60+
data = make([]byte, len(val))
61+
copy(data, val)
62+
63+
return nil
64+
})
65+
if err != nil {
66+
return err
67+
}
68+
69+
if asJSON {
70+
// Unmarshal the protobuf data
71+
var metaData meta.Data
72+
if err := metaData.UnmarshalBinary(data); err != nil {
73+
return fmt.Errorf("failed to unmarshal metadata: %w", err)
74+
}
75+
76+
// Marshal to JSON
77+
jsonData, err := json.MarshalIndent(&metaData, "", " ")
78+
if err != nil {
79+
return fmt.Errorf("failed to marshal to JSON: %w", err)
80+
}
81+
82+
if outputPath == "" || outputPath == "-" {
83+
// Write to stdout
84+
if _, err = os.Stdout.Write(jsonData); err != nil {
85+
return fmt.Errorf("failed to write JSON to stdout: %w", err)
86+
}
87+
} else {
88+
if err := os.WriteFile(outputPath, jsonData, 0644); err != nil {
89+
return fmt.Errorf("failed to write output file %s: %w", outputPath, err)
90+
}
91+
fmt.Fprintf(os.Stderr, "wrote JSON to %s\n", outputPath)
92+
}
93+
} else {
94+
// Binary output
95+
if outputPath == "-" {
96+
// Write to stdout
97+
if _, err := os.Stdout.Write(data); err != nil {
98+
return fmt.Errorf("failed to write binary to stdout: %w", err)
99+
}
100+
} else {
101+
if outputPath == "" {
102+
outputPath = "meta.db.bin"
103+
}
104+
if err := os.WriteFile(outputPath, data, 0644); err != nil {
105+
return fmt.Errorf("failed to write output file %s: %w", outputPath, err)
106+
}
107+
fmt.Printf("extracted %d bytes from %s[%s][%s] to %s\n",
108+
len(data), boltPath, string(meta.BucketName), meta.Filename, outputPath)
109+
}
110+
}
111+
112+
return nil
113+
}

0 commit comments

Comments
 (0)