Files
Zach LeslieandGitHub a9f63d073b Replace TenantIndex, BlockMeta and CompactedBlockMeta with proto near-equivalents (#4072)
* 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
2024-10-02 18:40:59 +00:00

159 lines
4.5 KiB
Go

package local
import (
"bytes"
"context"
crand "crypto/rand"
"fmt"
"math/rand"
"os"
"testing"
"github.com/google/uuid"
"github.com/grafana/tempo/pkg/io"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/tempo/tempodb/backend"
)
const objectName = "test"
func TestReadWrite(t *testing.T) {
fakeTracesFile, err := os.CreateTemp("/tmp", "")
defer os.Remove(fakeTracesFile.Name())
assert.NoError(t, err, "unexpected error creating temp file")
r, w, _, err := New(&Config{
Path: t.TempDir(),
})
assert.NoError(t, err, "unexpected error creating local backend")
blockID := uuid.New()
tenantIDs := []string{"fake"}
for i := 0; i < 10; i++ {
tenantIDs = append(tenantIDs, fmt.Sprintf("%d", rand.Int()))
}
fakeMeta := &backend.BlockMeta{
BlockID: backend.UUID(blockID),
}
fakeObject := make([]byte, 20)
_, err = crand.Read(fakeObject)
assert.NoError(t, err, "unexpected error creating fakeObject")
ctx := context.Background()
for _, id := range tenantIDs {
fakeMeta.TenantID = id
err = w.Write(ctx, objectName, backend.KeyPathForBlock((uuid.UUID)(fakeMeta.BlockID), id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil)
assert.NoError(t, err, "unexpected error writing")
err = w.Write(ctx, backend.MetaName, backend.KeyPathForBlock((uuid.UUID)(fakeMeta.BlockID), id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil)
assert.NoError(t, err, "unexpected error meta.json")
err = w.Write(ctx, backend.CompactedMetaName, backend.KeyPathForBlock((uuid.UUID)(fakeMeta.BlockID), id), bytes.NewReader(fakeObject), int64(len(fakeObject)), nil)
assert.NoError(t, err, "unexpected error meta.compacted.json")
}
actualObject, size, err := r.Read(ctx, objectName, backend.KeyPathForBlock(blockID, tenantIDs[0]), nil)
assert.NoError(t, err, "unexpected error reading")
actualObjectBytes, err := io.ReadAllWithEstimate(actualObject, size)
assert.NoError(t, err, "unexpected error reading")
assert.Equal(t, fakeObject, actualObjectBytes)
actualReadRange := make([]byte, 5)
err = r.ReadRange(ctx, objectName, backend.KeyPathForBlock(blockID, tenantIDs[0]), 5, actualReadRange, nil)
assert.NoError(t, err, "unexpected error range")
assert.Equal(t, fakeObject[5:10], actualReadRange)
list, err := r.List(ctx, backend.KeyPath{tenantIDs[0]})
assert.NoError(t, err, "unexpected error listing")
assert.Len(t, list, 1)
assert.Equal(t, blockID.String(), list[0])
m, cm, err := r.ListBlocks(ctx, tenantIDs[0])
assert.NoError(t, err, "unexpected error listing blocks")
assert.Len(t, m, 1)
assert.Len(t, cm, 1)
}
func TestShutdownLeavesTenantsWithBlocks(t *testing.T) {
r, w, _, err := New(&Config{
Path: t.TempDir(),
})
require.NoError(t, err)
ctx := context.Background()
blockID := backend.NewUUID()
contents := bytes.NewReader([]byte("test"))
tenant := "fake"
// write a "block"
err = w.Write(ctx, "test", backend.KeyPathForBlock((uuid.UUID)(blockID), tenant), contents, contents.Size(), nil)
require.NoError(t, err)
tenantExists(t, tenant, r)
blockExists(t, blockID, tenant, r)
// shutdown the backend
r.Shutdown()
tenantExists(t, tenant, r)
blockExists(t, blockID, tenant, r)
}
func TestShutdownRemovesTenantsWithoutBlocks(t *testing.T) {
r, w, c, err := New(&Config{
Path: t.TempDir(),
})
require.NoError(t, err)
ctx := context.Background()
blockID := backend.NewUUID()
contents := bytes.NewReader([]byte("test"))
tenant := "tenant"
// write a "block"
err = w.Write(ctx, "test", backend.KeyPathForBlock((uuid.UUID)(blockID), tenant), contents, contents.Size(), nil)
require.NoError(t, err)
tenantExists(t, tenant, r)
blockExists(t, blockID, tenant, r)
// clear the block
err = c.ClearBlock((uuid.UUID)(blockID), tenant)
require.NoError(t, err)
tenantExists(t, tenant, r)
// block should not exist
blocks, err := r.List(ctx, backend.KeyPath{tenant})
require.NoError(t, err)
require.Len(t, blocks, 0)
// shutdown the backend
r.Shutdown()
// tenant should not exist
tenants, err := r.List(ctx, backend.KeyPath{})
require.NoError(t, err)
require.Len(t, tenants, 0)
}
func tenantExists(t *testing.T, tenant string, r backend.RawReader) {
tenants, err := r.List(context.Background(), backend.KeyPath{})
require.NoError(t, err)
require.Len(t, tenants, 1)
require.Equal(t, tenant, tenants[0])
}
func blockExists(t *testing.T, blockID backend.UUID, tenant string, r backend.RawReader) {
blocks, err := r.List(context.Background(), backend.KeyPath{tenant})
require.NoError(t, err)
require.Len(t, blocks, 1)
require.Equal(t, blockID.String(), blocks[0])
}