mirror of
https://github.com/hanzoai/traces.git
synced 2026-10-30 18:20:41 +00:00
* Update proto for v1 backend * Functioning blocklist with new package * Functioning blocklist with existing package * Generate proto to existing package * Add wrapper around google UUID for proto marshaling * Update blocklist for wrapper type * Test WriteTenantIndex * Implement json for uuid * Almost functional backend tests * Passing backend tests * Improve UUID coverage and utility * TempoDB updates for UUID and struct type changes * Update method style for uuid.New() * Update method style for uuid.MustParse() * Add uuid.From helper * Update modules for UUID and proto struct types * Update poller integration test for UUID * Update tempo-cli for UUID and proto struct type changes * Lint and clean up * Fix serverless * Fix cli * Fix cli * Add fixture tests for roundtrip assurance between versions * Clean up notes from proto definition * Update backend/test * Be more specific about unmarshal UUID * Include event for compacted block * Use better json tag for compacted meta * Implement UnmarshalJson on CompcatedBlockMeta for embedded struct * Test for CompactedMeta marshal/unmarshal * Drop benchmark index * Clean commented code * Extend mocks to capture multiple writes * Update backend/test fixtures * Write both proto and json to the backend for all three files in all backends * Fix lint * Back UUID with google.UUID to avoid struct * Relocate pkg/uuid to tempodb/backend * Re-plumb UUID through tempodb * Re-plumb UUID through cmd * Re-plumb UUID through modules * Re-plumb UUID through integration/ * Drop package spec from tempo.proto * Improve encoding marshal performance * Drop block proto and tenantindex json * Drop additional proto include * Implement zstd tenant index compression * Add note about use of json in the dedicatedcolumns * Fix ingester local block * Spell * Revert mock update * Drop json fallback from tenantindex read * Replace single-tenant test fixtures * Update fixture replacement test * Improve error handling and fix test * Extend test for tenantindex round-trip * Small fixes * Revert "Drop json fallback from tenantindex read" This reverts commit 834ff5b85d8a8a4d7eb560fbb67ba8f3a5a3959a. * Add back mocks to capture multiple backend writes * Add back proto & json writitng/reading for tenantindex * Change TotalObjects type from int32 -> int64 The original change was int -> int32, which on 64bit machines is a downgrade that I overlooked. Raising here to int64 to maintain the size. * Store write buffer at object path in mocks to improve readability in tests * Avoid allocation in interface validation * Update note to include intern * Pluralize metas and compacted_metas fields * Fallback to json only on ErrDoesNotExist * Lint * Drop debug * Revert "Pluralize metas and compacted_metas fields" This reverts commit 46a8c36e37ac33e1ffc104287d898930e02cdd97. * Import original tenantindex and test contents for backwards compatibility * Update changelog
185 lines
4.3 KiB
Go
185 lines
4.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/parquet-go/parquet-go"
|
|
|
|
"github.com/grafana/tempo/pkg/tempopb"
|
|
"github.com/grafana/tempo/pkg/traceql"
|
|
"github.com/grafana/tempo/tempodb/backend"
|
|
"github.com/grafana/tempo/tempodb/backend/local"
|
|
"github.com/grafana/tempo/tempodb/encoding/common"
|
|
"github.com/grafana/tempo/tempodb/encoding/vparquet3"
|
|
"github.com/grafana/tempo/tempodb/encoding/vparquet4"
|
|
)
|
|
|
|
type convertParquet3to4 struct {
|
|
In string `arg:"" help:"The input parquet block to read from."`
|
|
Out string `arg:"" help:"The output folder to write block to." default:"./out" optional:""`
|
|
DedicatedColumns []string `arg:"" help:"List of dedicated columns to convert. Overwrites existing dedicated columns" optional:""`
|
|
}
|
|
|
|
func (cmd *convertParquet3to4) Run() error {
|
|
cmd.In = getPathToBlockDir(cmd.In)
|
|
|
|
// open the input parquet file
|
|
in, pf, err := openParquetFile(cmd.In)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer in.Close()
|
|
|
|
// open the input metadata file
|
|
meta, err := readBlockMeta(cmd.In)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// create output block
|
|
outR, outW, _, err := local.New(&local.Config{
|
|
Path: cmd.Out,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// calculate dedicated columns
|
|
var dedicatedCols backend.DedicatedColumns
|
|
|
|
if len(cmd.DedicatedColumns) > 0 {
|
|
dedicatedCols = make(backend.DedicatedColumns, 0, len(cmd.DedicatedColumns))
|
|
|
|
for _, col := range cmd.DedicatedColumns {
|
|
att, err := traceql.ParseIdentifier(col)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
scope := backend.DedicatedColumnScopeSpan
|
|
if att.Scope == traceql.AttributeScopeResource {
|
|
scope = backend.DedicatedColumnScopeResource
|
|
}
|
|
|
|
fmt.Printf("add dedicated column scope=%s name=%s\n", scope, att.Name)
|
|
|
|
dedicatedCols = append(dedicatedCols, backend.DedicatedColumn{
|
|
Scope: scope,
|
|
Name: att.Name,
|
|
Type: backend.DedicatedColumnTypeString,
|
|
})
|
|
}
|
|
} else {
|
|
dedicatedCols = meta.DedicatedColumns
|
|
}
|
|
|
|
// copy block
|
|
blockCfg := &common.BlockConfig{
|
|
BloomFP: 0.99,
|
|
BloomShardSizeBytes: 1024 * 1024,
|
|
Version: vparquet4.VersionString,
|
|
RowGroupSizeBytes: 100 * 1024 * 1024,
|
|
}
|
|
|
|
newMeta := *meta
|
|
newMeta.Version = vparquet4.VersionString
|
|
newMeta.DedicatedColumns = dedicatedCols
|
|
|
|
// create iterator over in file
|
|
iter := &parquetIterator3{
|
|
r: parquet.NewGenericReader[*vparquet3.Trace](pf),
|
|
m: meta,
|
|
}
|
|
|
|
fmt.Printf("Creating vParquet4 block in %s\n", filepath.Join(cmd.Out, meta.TenantID, newMeta.BlockID.String()))
|
|
fmt.Printf("Converting rows 0 to %d\n", pf.NumRows())
|
|
outMeta, err := vparquet4.CreateBlock(context.Background(), blockCfg, &newMeta, iter, backend.NewReader(outR), backend.NewWriter(outW))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Successfully created block with size=%d and footerSize=%d\n", outMeta.Size_, outMeta.FooterSize)
|
|
return nil
|
|
}
|
|
|
|
func getPathToBlockDir(path string) string {
|
|
if filepath.Base(path) == "data.parquet" {
|
|
return filepath.Dir(path)
|
|
}
|
|
return path
|
|
}
|
|
|
|
func openParquetFile(blockPath string) (*os.File, *parquet.File, error) {
|
|
inFile := filepath.Join(blockPath, "data.parquet")
|
|
in, err := os.Open(inFile)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
inStat, err := in.Stat()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
pf, err := parquet.OpenFile(in, inStat.Size())
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return in, pf, nil
|
|
}
|
|
|
|
func readBlockMeta(blockPath string) (*backend.BlockMeta, error) {
|
|
metaFile := filepath.Join(blockPath, "meta.json")
|
|
inMeta, err := os.Open(metaFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer inMeta.Close()
|
|
|
|
var meta backend.BlockMeta
|
|
err = json.NewDecoder(inMeta).Decode(&meta)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &meta, nil
|
|
}
|
|
|
|
type parquetIterator3 struct {
|
|
r *parquet.GenericReader[*vparquet3.Trace]
|
|
m *backend.BlockMeta
|
|
i int
|
|
}
|
|
|
|
func (i *parquetIterator3) Next(_ context.Context) (common.ID, *tempopb.Trace, error) {
|
|
traces := []*vparquet3.Trace{{}}
|
|
|
|
i.i++
|
|
if i.i%1000 == 0 {
|
|
fmt.Println(i.i)
|
|
}
|
|
|
|
_, err := i.r.Read(traces)
|
|
if errors.Is(err, io.EOF) {
|
|
return nil, nil, io.EOF
|
|
}
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
pqTrace := traces[0]
|
|
pbTrace := vparquet3.ParquetTraceToTempopbTrace(i.m, pqTrace)
|
|
return pqTrace.TraceID, pbTrace, nil
|
|
}
|
|
|
|
func (i *parquetIterator3) Close() {
|
|
_ = i.r.Close()
|
|
}
|